arnaucube
arnaucube/circomPublic Self-hosted repository
roll unrolled loops with code
Jordi Baylina jordi@baylina.cat
Tue, 10 Dec 2019 18:46:10 +0100
commit

ec0e7f421ba1611c519b2c1d8c175cd10c403124

parent

afa8201c2c7d92ce8c89ca2f6ea876c67c7d2f3f

M c/zqfield.cpp → c/zqfield.cpp

@@ -189,3 +189,7 @@ mpz_and(*r, *r, mask);

} } +int ZqField::toInt(PBigInt a) { + return mpz_get_si (*a); +} +
M c/zqfield.h → c/zqfield.h

@@ -45,6 +45,7 @@ void shl(PBigInt r, PBigInt a, PBigInt b);

void shr(PBigInt r, PBigInt a, PBigInt b); int isTrue(PBigInt a); + int toInt(PBigInt a); }; #endif // ZQFIELD_H
M src/c_build.js → src/c_build.js

@@ -150,6 +150,8 @@ ctx.codeHeader = "// Header\n";

ctx.codeFooter = "// Footer\n"; ctx.uniqueNames = Object.assign({},ctx.globalNames); ctx.refs = []; + ctx.fileName = ctx.templates[ctx.components[i].template].fileName; + ctx.filePath = ctx.templates[ctx.components[i].template].filePath; for (let p in ctx.components[i].params) { if (ctx.scopes[0][p]) return ctx.throwError(`Repeated parameter at ${ctx.components[i].template}: ${p}`);

@@ -245,7 +247,7 @@ if ((i+1)%32==0) {

line += (i>31) ? "," : " "; line += toHex(acc); acc = 0; - if ( i % (32*64) == 0) { + if ( (i+1) % (32*64) == 0) { arr.push(line); line = ""; }

@@ -299,9 +301,12 @@ for (let i=0; i<NVars; i++) {

code += (i>0) ? ",": " "; code += arr[i]; if ((i>0)&&(i%64 == 0)) { - if (code != "") codes.push(code + "\n"); - codes.push(code); - code =0; + if (code != "") { + codes.push(code + "\n"); + } else { + codes.push(code); + } + code =""; } } if (code != "") codes.push(code + "\n");

@@ -338,7 +343,6 @@ }

if (name=="sizes") name="sizes_0"; if (this.definedSizes[name]) return this.definedSizes[name]; - name = "_" + name; const labelName = this.getUniqueName(name); this.definedSizes[name] = labelName;

@@ -371,6 +375,8 @@ const oldCode = ctx.code;

const oldCodeHeader = ctx.codeHeader; const oldCodeFooter = ctx.codeFooter; const oldUniqueNames = ctx.uniqueNames; + const oldFileName = ctx.fileName; + const oldFilePath = ctx.oldFilePath; ctx.scopes = [{}];

@@ -382,6 +388,8 @@ ctx.codeFooter = "// Footer\n";

ctx.uniqueNames = Object.assign({},ctx.globalNames); ctx.returnValue = null; ctx.returnSizes = null; + ctx.fileName = ctx.functions[name].fileName; + ctx.filePath = ctx.functions[name].filePath; let paramsStr = "";

@@ -443,6 +451,8 @@ ctx.code = oldCode;

ctx.codeHeader = oldCodeHeader; ctx.codeFooter = oldCodeFooter; ctx.uniqueNames = oldUniqueNames; + ctx.fileName = oldFileName; + ctx.filePath = oldFilePath; ctx.definedFunctions[h] = res;
M src/c_gen.js → src/c_gen.js

@@ -40,6 +40,7 @@

function instantiateRef(ctx, refId, initValue) { const v = ctx.refs[refId]; if (v.used) return; + if (!v.sizes) v.sizes = [1,0]; if (v.type=="BIGINT") { ctx.codeHeader += `PBigInt ${v.label} = ctx->allocBigInts(${v.sizes[0]});\n`;

@@ -344,7 +345,7 @@ return ast.refId;

} function genNumber(ctx, ast) { - return newRef(ctx, "BIGINT", "_num", ast.value); + return newRef(ctx, "BIGINT", "_num", bigInt(ast.value)); }

@@ -391,9 +392,9 @@ }

if (rStr != "") rStr += " + "; if (iIdx.used) { - rStr += iIdx.label; + rStr += `ctx->field->toInt(${iIdx.label})`; } else { - rStr += iIdx.value; + rStr += iIdx.value[0].toString(); } rStr += "*"; if (iSizes.used) {

@@ -741,6 +742,8 @@ const bRef = gen(ctx, ast.values[1]);

const b = ctx.refs[bRef]; if (ctx.error) return; const strErr = ast.fileName + ":" + ast.first_line + ":" + ast.first_column; + instantiateRef(ctx, aRef); + instantiateRef(ctx, bRef); ctx.code += `ctx->checkConstraint(${a.label}, ${b.label}, "${strErr}");`; }

@@ -897,13 +900,18 @@ if (ctx.error) return;

const cond2 = ctx.refs[condRef2]; + if ((!cond2.used) &&(haveCode(ctx.code))) { + instantiateRef(ctx, condRef2, cond2.value); + } + if (!inLoop) { if (cond2.used) { ctx.code = oldCode + ctx.code; inLoop = true; enterConditionalCode(ctx, ast); - condVar = newRef(ctx, "INT", "_cond"); - instantiateRef(ctx, condVar); + condVarRef = newRef(ctx, "INT", "_cond"); + condVar = ctx.refs[condVarRef]; + instantiateRef(ctx, condVarRef); ctx.code = oldCode +

@@ -928,6 +936,10 @@ ctx.code += "}\n";

leaveConditionalCode(ctx); } ctx.scopes.pop(); + + function haveCode(c) { + return c.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, "").trim() != ""; + } } function genIf(ctx, ast) {
M src/exec.js → src/exec.js

@@ -320,7 +320,9 @@ }

}; ctx.templates[ast.name] = { block: ast.block, - params: ast.params + params: ast.params, + fileName: ctx.fileName, + filePath: ctx.filePath, }; }

@@ -344,7 +346,9 @@ }

}; ctx.functions[ast.name] = { block: ast.block, - params: ast.params + params: ast.params, + fileName: ctx.fileName, + filePath: ctx.filePath }; }

@@ -383,7 +387,7 @@ selectors: []

}; } -function execInstantiateComponet(ctx, vr, fn) { +function execInstantiateComponet(ctx, vr, fn, sels) { if (vr.type != "VARIABLE") return error(ctx, fn, "Left hand instatiate component must be a variable"); if (fn.type != "FUNCTIONCALL") return error(ctx, fn, "Right type of instantiate component must be a function call");

@@ -408,13 +412,16 @@ }

if (template.params.length != paramValues.length) return error(ctx, fn, "Invalid Number of parameters"); - const vComp = getScope(ctx, componentName, vr.selectors); + const vComp = getScope(ctx, componentName); if (vComp.type != "COMPONENT") return error(ctx, fn, "Assigning to a non component"); const cIdx = vComp.cIdx; if (cIdx == -1) return error(ctx, fn, "Component not defined"); - let l=1; - for (let i=0; i<vComp.sizes.length; i++) l = l*vComp.sizes[i]; - for (let i=0; i<l; i++) { + + + const aSizes = utils.accSizes(vComp.sizes); + let o=0; + for (let i=0; i<sels.length; i++) o += sels[i] * aSizes[i+1]; + for (let i=o; i<o+aSizes[sels.length]; i++) { instantiateComponent(cIdx+i); }

@@ -762,11 +769,12 @@ }

const [num, sels, typ] = getScopeRef(ctx, v.name, v.selectors); if (ctx.error) return; + if (typ == "COMPONENT") return execInstantiateComponet(ctx, v, ast.values[1], sels); + if ((typeof(num) != "object")||(num == null)) return error(ctx, ast, "Variable not defined"); - if (typ == "COMPONENT") return execInstantiateComponet(ctx, v, ast.values[1]); if (ctx.error) return; - if ((typ == "SIGNAL")&&(ast.op == "=")) return error(ctx, ast, "Cannot assign to a signal with `=` use <-- or <== ops"); + if ((typ == "SIGNAL")&&(ast.op.indexOf("=")>=0)) return error(ctx, ast, "Cannot assign to a signal with `=` use <-- or <== ops"); if ((["NUMBER", "COMPONENT"].indexOf(typ) >= 0 )&&(ast.op != "=")) return error(ctx, ast, `Cannot assign to a var with ${ast.op}. use = op`); const res = exec(ctx, ast.values[1]);
M src/utils.js → src/utils.js

@@ -38,7 +38,7 @@ for (let i=0; i<a.length; i++) {

fillArray(res, a[i]); } } else { - res.push(a); + res.push(bigInt(a)); } } }
M src/zqfield.js → src/zqfield.js

@@ -30,7 +30,7 @@ return this.p.minus(a);

} mul(a, b) { - return a.mul(b).mod(this.p); + return a.times(b).mod(this.p); } lt(a, b) {

@@ -59,7 +59,7 @@ }

div(a, b) { assert(!b.isZero(), "Division by zero"); - return a.mul(b.modInv(this.p)).mod(this.p); + return a.times(b.modInv(this.p)).mod(this.p); } idiv(a, b) {
M test/basiccases.js → test/basiccases.js

@@ -287,4 +287,15 @@ [{x:-1}, {y: -5}],

] ); }); + it("Component array ", async () => { + await doTest( + "componentarray.circom", + [ + [{in: 1}, {out: 1}], + [{in: 2}, {out: 256}], + [{in: 3}, {out: 6561}], + [{in:-1}, {out: 1}], + ] + ); + }); });
A test/circuits/componentarray.circom

@@ -0,0 +1,28 @@

+template Square() { + signal input in; + signal output out; + + out <== in*in; +} + +template Main(n) { + signal input in; + signal output out; + + component squares[n]; + + var i; + + for (i=0; i<n; i++) { + squares[i] = Square(); + if (i==0) { + squares[i].in <== in; + } else { + squares[i].in <== squares[i-1].out; + } + } + + squares[n-1].out ==> out; +} + +component main = Main(3);