From f4bbcfd90c8fb561af56d55c793b00f1f26fbb77 Mon Sep 17 00:00:00 2001 From: Jordi Baylina Date: Fri, 29 Nov 2019 20:19:58 +0100 Subject: [PATCH] functions added --- c/calcwit.cpp | 10 +- c/calcwit.h | 4 +- c/zqfield.cpp | 5 +- c/zqfield.h | 2 +- src/c_build.js | 130 +++++++++++++++++++----- src/c_gen.js | 179 +++++++++++++++------------------ src/utils.js | 11 ++ test/basiccases.js | 28 ++++++ test/circuits/addin.json | 1 - test/circuits/function1.circom | 12 +++ test/circuits/function2.circom | 13 +++ test/circuits/out.json | 5 - test/inout.js | 19 ---- 13 files changed, 258 insertions(+), 161 deletions(-) delete mode 100644 test/circuits/addin.json create mode 100644 test/circuits/function1.circom create mode 100644 test/circuits/function2.circom delete mode 100644 test/circuits/out.json delete mode 100644 test/inout.js diff --git a/c/calcwit.cpp b/c/calcwit.cpp index 64dfd82..3d5b35a 100644 --- a/c/calcwit.cpp +++ b/c/calcwit.cpp @@ -109,14 +109,14 @@ Circom_Sizes Circom_CalcWit::getSignalSizes(int cIdx, u64 hash) { return circuit->components[cIdx].entries[entryPos].sizes; } -PBigInt Circom_CalcWit::allocBigInts(Circom_Sizes sizes) { - PBigInt res = new BigInt[sizes[0]]; - for (int i=0; i { return param.name; }, - }; - } - - ctx.code += "void "+f+"(POINTER _ret, "+paramsList.join(",")+") {\n"; - - ctx.code += gen(ctx, ctx.functions[f].block); - ctx.code += "}"; - } - + const fnComponents = []; for (let i=0; iallocBigInts(${labelSize});\n`; - if (ctx.conditionalCode) { - ctx.conditionalCodeHeader += c; - } else { - ctx.code += c; - } - ctx.codeFooter += `ctx->freeBigInts(${v.label}, ${labelSize});\n`; - } else if (iSize.value) { - const labelSize = ctx.addSizes(iSize.value); - ctx.codeHeader += `PBigInt ${v.label} = ctx->allocBigInts(${labelSize});\n`; - ctx.codeFooter += `ctx->freeBigInts(${v.label}, ${labelSize});\n`; - } else { - return error(ctx, null, "Undefined Sizes: " +name); - } - + ctx.codeHeader += `PBigInt ${v.label} = ctx->allocBigInts(${v.sizes[0]});\n`; + ctx.codeFooter += `ctx->freeBigInts(${v.label}, ${v.sizes[0]});\n`; } else if (v.type=="INT") { ctx.codeHeader += `int ${v.label};\n`; } else if (v.type=="SIZES") { @@ -112,15 +73,15 @@ function instantiateRef(ctx, name, initValue) { } function instantiateConstant(ctx, value) { - const labelSize = ctx.addSizes(utils.extractSizes(value)); + const sizes = utils.accSizes(utils.extractSizes(value)); const flatedValue = utils.flatArray(value); const res = ctx.getTmpName("_const"); ctx.codeHeader += `PBigInt ${res};\n`; - ctx.codeHeader += `${res} = ctx->allocBigInts(${labelSize});\n`; + ctx.codeHeader += `${res} = ctx->allocBigInts(${sizes[0]});\n`; for (let i=0; ifreeBigInts(${res}, ${labelSize});\n`; + ctx.codeFooter += `ctx->freeBigInts(${res}, ${sizes[0]});\n`; return res; } @@ -339,40 +300,23 @@ function genDeclareVariable(ctx, ast) { if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name"); if (typeof scope[varName] != "undefined") return error(ctx, ast, "Name already exists: "+varName); - const sizes=[]; - let instantiate = false; + let sizes=[]; for (let i=0; i< ast.name.selectors.length; i++) { const size = gen(ctx, ast.name.selectors[i]); if (ctx.error) return; if (size.used) { - instantiate = true; - sizes.push(`BigInt2Int(${scope[size].label})`); + return error(ctx, ast, "Variable size variables not allowed"); } else { sizes.push(size.value.toJSNumber()); } - - sizes.push( size.value.toJSNumber() ); - } - - const vSizes = newRef(ctx, "SIZES", "_sizes"); - const iSizes = scope[vSizes]; - iSizes.dim = ast.name.selectors.length; - if (instantiate) { - instantiateRef(ctx, vSizes); - ctx.code += `${iSizes.label}[${iSizes.dim+1}]=0`; - ctx.code += `${iSizes.label}[${iSizes.dim}]=1`; - for (let i=iSizes.dim-1; i>=0; i--) { - ctx.code += `${iSizes.label}[${i}] = ${sizes[i]}*${iSizes.label}[${i+1}];\n`; - } - } else { - iSizes.value = sizes; } + sizes = utils.accSizes(sizes); const res = scope[varName] = { stack: true, type: "BIGINT", - sizes: vSizes, + sizes: sizes, label: labelName, used: false, }; @@ -405,7 +349,15 @@ function genGetOffset(ctx, vOffset, vSizes, sels) { if ((sels)&&(sels.length>0)) { - const iSizes = getScope(ctx, vSizes); + let iSizes; + if (typeof vSizes == "string") { + iSizes = getScope(ctx, vSizes); + } else { + iSizes = { + used: false, + sizes: vSizes + }; + } for (let i=0; i0) { @@ -476,13 +427,15 @@ function genVariable(ctx, ast) { const offset = getScope(ctx, vOffset); if (v.used) { if (offset.used) { - const res = newRef(ctx, "BIGINT", "_v"); - instantiateRef(ctx, res); - ctx.code += `${res} = ${ast.name} + ${vOffset};\n`; + const res = newRef(ctx, "BIGINT", "_v", v.sizes.slice(ast.sels.length)); + res.used = true; + ctx.codeHeader += `PBigInt ${res.label}`; + ctx.code += `${res} = ${ast.name} + ${vOffset.label};\n`; return res; } else if (offset.value) { - const res = newRef(ctx, "BIGINT", "_v"); - instantiateRef(ctx, res); + const res = newRef(ctx, "BIGINT", "_v", v.sizes.slice(ast.sels.length)); + res.used = true; + ctx.codeHeader += `PBigInt ${res.label}`; ctx.code += `${res} = ${ast.name} + ${vOffset.value};\n`; return res; } else { @@ -490,11 +443,11 @@ function genVariable(ctx, ast) { } } else { if (offset.used) { - instantiateRef(ctx, ast.name); - const vConstant = instantiateConstant(ctx, v.value); - const res = newRef(ctx, "BIGINT", "_v"); - instantiateRef(ctx, res); - ctx.code += `${res} = ${vConstant} + ${vOffset};\n`; + instantiateRef(ctx, ast.name, v.value); + const res = newRef(ctx, "BIGINT", "_v", v.sizes.slice(ast.sels.length)); + res.used = true; + ctx.codeHeader += `PBigInt ${res.label}`; + ctx.code += `${res} = ${ast.name} + ${vOffset.label};\n`; return res; } else { const sa = utils.subArray(v.value, ast.selectors); @@ -672,22 +625,18 @@ function genVarAssignement(ctx, ast) { return genSetSignal(ctx, "ctx->cIdx", vsIdx, rName); } else if (left.type == "BIGINT") { + if (!utils.sameSizes(left.sizes, right.sizes)) return error(ctx, ast, "Sizes do not match"); if (left.used) { if (!right.used) { - instantiateRef(ctx, rName); + instantiateRef(ctx, rName, right.value); } - ctx.code += `ctx->field->copy(${left.label}, ${right.label});\n`; + ctx.code += `ctx->field->copyn(${left.label}, ${right.label}, ${right.sizes[0]});\n`; } else { if (right.used) { instantiateRef(ctx, lName); - ctx.code += `ctx->field->copy(${left.label}, ${right.label});\n`; + ctx.code += `ctx->field->copyn(${left.label}, ${right.label}, ${right.sizes[0]});\n`; } else { - if (ctx.conditionalCode) { - instantiateRef(ctx, lName); - ctx.code += `ctx->field->copy(${left.label}, ${right.label});\n`; - } else { - left.value = right.value; - } + left.value = right.value; } } } else { @@ -718,14 +667,29 @@ function genArray(ctx, ast) { function genFunctionCall(ctx, ast) { - let S = "["; + const params = []; for (let i=0; i0) S += ","; - S += gen(ctx, ast.params[i]); + const pName = gen(ctx, ast.params[i]); + params.push(getScope(ctx, pName)); } - S+="]"; - return `ctx.callFunction("${ast.name}", ${S})`; + const fn = ctx.buildFunction(ast.name, params); + + if (fn.type == "VARVAL_CONSTSIZE") { + const res = newRef(ctx, "BIGINT", `_ret${ast.name}Sizes`, fn.retSizes); + instantiateRef(ctx, res); + + ctx.code +=`${fn.fnName}(ctx, ${res}`; + for (let i=0; ifield->copyn(__retValue, ${vName}, ${v.sizes[0]});\n`; + } else { + if ((typeof v.value == "undefined") || v == null) return error(ctx, ast, "Returning an unknown value"); + if ((typeof ctx.returnValue == "undefined") || (ctx.returnValue == null)) { + ctx.returnValue = v.value; + } + } + ctx.code += "goto returnFunc;\n"; + return vName; } diff --git a/src/utils.js b/src/utils.js index 6af0201..5ac3844 100644 --- a/src/utils.js +++ b/src/utils.js @@ -11,6 +11,7 @@ module.exports.accSizes = accSizes; module.exports.fnvHash = fnvHash; module.exports.stringifyBigInts = stringifyBigInts; module.exports.unstringifyBigInts = unstringifyBigInts; +module.exports.sameSizes = sameSizes; function ident(text) { let lines = text.split("\n"); @@ -105,5 +106,15 @@ function unstringifyBigInts(o) { } } +function sameSizes(s1, s2) { + if (!Array.isArray(s1)) return false; + if (!Array.isArray(s2)) return false; + if (s1.length != s2.length) return false; + for (let i=0; i { + await doTest( + "inout.circom", + [ + [{in1: 1, in2: [2,3], in3:[[4,5], [6,7], [8,9]]}, {out1: 1, out2: [2,3], out3: [[4,5], [6,7],[8,9]]}], + ] + ); + }); it("add", async () => { await doTest( "add.circom", @@ -59,4 +67,24 @@ describe("basic cases", function () { ] ); }); + it("function1", async () => { + await doTest( + "function1.circom", + [ + [{in: 0}, {out: 3}], + [{in: 10}, {out: 13}], + [{in: __P__.minus(2)}, {out: 1}], + ] + ); + }); + it("function2", async () => { + await doTest( + "function2.circom", + [ + [{in: 0}, {out: 3}], + [{in: 10}, {out: 13}], + [{in: __P__.minus(2)}, {out: 1}], + ] + ); + }); }); diff --git a/test/circuits/addin.json b/test/circuits/addin.json deleted file mode 100644 index 370eb40..0000000 --- a/test/circuits/addin.json +++ /dev/null @@ -1 +0,0 @@ -{"in":[1,2]} diff --git a/test/circuits/function1.circom b/test/circuits/function1.circom new file mode 100644 index 0000000..5df85a8 --- /dev/null +++ b/test/circuits/function1.circom @@ -0,0 +1,12 @@ +function func1(a,b) { + return a+b; +} + +template Main() { + signal input in; + signal output out; + + out <== func1(in, 3); +} + +component main = Main(); diff --git a/test/circuits/function2.circom b/test/circuits/function2.circom new file mode 100644 index 0000000..8ce3f97 --- /dev/null +++ b/test/circuits/function2.circom @@ -0,0 +1,13 @@ +function fnConst(a,b) { + return a+b; +} + +template Main() { + signal input in; + signal output out; + + var a = fnConst(1,2); + out <== in +a; +} + +component main = Main(); diff --git a/test/circuits/out.json b/test/circuits/out.json deleted file mode 100644 index 5e54c96..0000000 --- a/test/circuits/out.json +++ /dev/null @@ -1,5 +0,0 @@ -[ - "1" -,"0" -,"0" -] diff --git a/test/inout.js b/test/inout.js deleted file mode 100644 index 2d329bb..0000000 --- a/test/inout.js +++ /dev/null @@ -1,19 +0,0 @@ -const path = require("path"); - -const c_tester = require("../index.js").c_tester; -// const stringifyBigInts = require("snarkjs").stringifyBigInts; - - -describe("inout test", function () { - this.timeout(100000); - it("Should compile a code with vars inside a for", async () => { - const cir = await c_tester(path.join(__dirname, "circuits", "inout.circom")); - - const out = await cir.calculateWitness({in1: 1, in2: [2,3], in3:[[4,5], [6,7], [8,9]]}); - - // console.log(JSON.stringify(stringifyBigInts(out),null,1)); - await cir.assertOut(out, {out1: 1, out2: [2,3], out3: [[4,5], [6,7],[8,9]]} ); - - await cir.release(); - }); -});