Browse Source

roll unrolled loops with code

feature/witness_bin
Jordi Baylina 5 years ago
parent
commit
ec0e7f421b
No known key found for this signature in database GPG Key ID: 7480C80C1BE43112
9 changed files with 96 additions and 22 deletions
  1. +4
    -0
      c/zqfield.cpp
  2. +1
    -0
      c/zqfield.h
  3. +15
    -5
      src/c_build.js
  4. +17
    -5
      src/c_gen.js
  5. +17
    -9
      src/exec.js
  6. +1
    -1
      src/utils.js
  7. +2
    -2
      src/zqfield.js
  8. +11
    -0
      test/basiccases.js
  9. +28
    -0
      test/circuits/componentarray.circom

+ 4
- 0
c/zqfield.cpp

@ -189,3 +189,7 @@ void ZqField::shr(PBigInt r, PBigInt a, PBigInt b) {
} }
} }
int ZqField::toInt(PBigInt a) {
return mpz_get_si (*a);
}

+ 1
- 0
c/zqfield.h

@ -45,6 +45,7 @@ public:
void shr(PBigInt r, PBigInt a, PBigInt b); void shr(PBigInt r, PBigInt a, PBigInt b);
int isTrue(PBigInt a); int isTrue(PBigInt a);
int toInt(PBigInt a);
}; };
#endif // ZQFIELD_H #endif // ZQFIELD_H

+ 15
- 5
src/c_build.js

@ -150,6 +150,8 @@ function buildCode(ctx) {
ctx.codeFooter = "// Footer\n"; ctx.codeFooter = "// Footer\n";
ctx.uniqueNames = Object.assign({},ctx.globalNames); ctx.uniqueNames = Object.assign({},ctx.globalNames);
ctx.refs = []; 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) { for (let p in ctx.components[i].params) {
if (ctx.scopes[0][p]) return ctx.throwError(`Repeated parameter at ${ctx.components[i].template}: ${p}`); if (ctx.scopes[0][p]) return ctx.throwError(`Repeated parameter at ${ctx.components[i].template}: ${p}`);
@ -245,7 +247,7 @@ function buildMapIsInput(ctx) {
line += (i>31) ? "," : " "; line += (i>31) ? "," : " ";
line += toHex(acc); line += toHex(acc);
acc = 0; acc = 0;
if ( i % (32*64) == 0) {
if ( (i+1) % (32*64) == 0) {
arr.push(line); arr.push(line);
line = ""; line = "";
} }
@ -299,9 +301,12 @@ function buildWit2Sig(ctx) {
code += (i>0) ? ",": " "; code += (i>0) ? ",": " ";
code += arr[i]; code += arr[i];
if ((i>0)&&(i%64 == 0)) { 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"); if (code != "") codes.push(code + "\n");
@ -338,7 +343,6 @@ function addSizes(_sizes) {
if (name=="sizes") name="sizes_0"; if (name=="sizes") name="sizes_0";
if (this.definedSizes[name]) return this.definedSizes[name]; if (this.definedSizes[name]) return this.definedSizes[name];
name = "_" + name;
const labelName = this.getUniqueName(name); const labelName = this.getUniqueName(name);
this.definedSizes[name] = labelName; this.definedSizes[name] = labelName;
@ -371,6 +375,8 @@ function buildFunction(name, paramValues) {
const oldCodeHeader = ctx.codeHeader; const oldCodeHeader = ctx.codeHeader;
const oldCodeFooter = ctx.codeFooter; const oldCodeFooter = ctx.codeFooter;
const oldUniqueNames = ctx.uniqueNames; const oldUniqueNames = ctx.uniqueNames;
const oldFileName = ctx.fileName;
const oldFilePath = ctx.oldFilePath;
ctx.scopes = [{}]; ctx.scopes = [{}];
@ -382,6 +388,8 @@ function buildFunction(name, paramValues) {
ctx.uniqueNames = Object.assign({},ctx.globalNames); ctx.uniqueNames = Object.assign({},ctx.globalNames);
ctx.returnValue = null; ctx.returnValue = null;
ctx.returnSizes = null; ctx.returnSizes = null;
ctx.fileName = ctx.functions[name].fileName;
ctx.filePath = ctx.functions[name].filePath;
let paramsStr = ""; let paramsStr = "";
@ -443,6 +451,8 @@ function buildFunction(name, paramValues) {
ctx.codeHeader = oldCodeHeader; ctx.codeHeader = oldCodeHeader;
ctx.codeFooter = oldCodeFooter; ctx.codeFooter = oldCodeFooter;
ctx.uniqueNames = oldUniqueNames; ctx.uniqueNames = oldUniqueNames;
ctx.fileName = oldFileName;
ctx.filePath = oldFilePath;
ctx.definedFunctions[h] = res; ctx.definedFunctions[h] = res;

+ 17
- 5
src/c_gen.js

@ -40,6 +40,7 @@ function newRef(ctx, type, name, value, sizes) {
function instantiateRef(ctx, refId, initValue) { function instantiateRef(ctx, refId, initValue) {
const v = ctx.refs[refId]; const v = ctx.refs[refId];
if (v.used) return; if (v.used) return;
if (!v.sizes) v.sizes = [1,0];
if (v.type=="BIGINT") { if (v.type=="BIGINT") {
ctx.codeHeader += `PBigInt ${v.label} = ctx->allocBigInts(${v.sizes[0]});\n`; ctx.codeHeader += `PBigInt ${v.label} = ctx->allocBigInts(${v.sizes[0]});\n`;
@ -344,7 +345,7 @@ function genDeclareVariable(ctx, ast) {
} }
function genNumber(ctx, ast) { function genNumber(ctx, ast) {
return newRef(ctx, "BIGINT", "_num", ast.value);
return newRef(ctx, "BIGINT", "_num", bigInt(ast.value));
} }
@ -391,9 +392,9 @@ function genGetOffset(ctx, refOffset, vSizes, sels) {
if (rStr != "") rStr += " + "; if (rStr != "") rStr += " + ";
if (iIdx.used) { if (iIdx.used) {
rStr += iIdx.label;
rStr += `ctx->field->toInt(${iIdx.label})`;
} else { } else {
rStr += iIdx.value;
rStr += iIdx.value[0].toString();
} }
rStr += "*"; rStr += "*";
if (iSizes.used) { if (iSizes.used) {
@ -741,6 +742,8 @@ function genConstraint(ctx, ast) {
const b = ctx.refs[bRef]; const b = ctx.refs[bRef];
if (ctx.error) return; if (ctx.error) return;
const strErr = ast.fileName + ":" + ast.first_line + ":" + ast.first_column; 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}");`; ctx.code += `ctx->checkConstraint(${a.label}, ${b.label}, "${strErr}");`;
} }
@ -897,13 +900,18 @@ function genLoop(ctx, ast) {
const cond2 = ctx.refs[condRef2]; const cond2 = ctx.refs[condRef2];
if ((!cond2.used) &&(haveCode(ctx.code))) {
instantiateRef(ctx, condRef2, cond2.value);
}
if (!inLoop) { if (!inLoop) {
if (cond2.used) { if (cond2.used) {
ctx.code = oldCode + ctx.code; ctx.code = oldCode + ctx.code;
inLoop = true; inLoop = true;
enterConditionalCode(ctx, ast); 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 = ctx.code =
oldCode + oldCode +
@ -928,6 +936,10 @@ function genLoop(ctx, ast) {
leaveConditionalCode(ctx); leaveConditionalCode(ctx);
} }
ctx.scopes.pop(); ctx.scopes.pop();
function haveCode(c) {
return c.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, "").trim() != "";
}
} }
function genIf(ctx, ast) { function genIf(ctx, ast) {

+ 17
- 9
src/exec.js

@ -320,7 +320,9 @@ function execTemplateDef(ctx, ast) {
}; };
ctx.templates[ast.name] = { ctx.templates[ast.name] = {
block: ast.block, block: ast.block,
params: ast.params
params: ast.params,
fileName: ctx.fileName,
filePath: ctx.filePath,
}; };
} }
@ -344,7 +346,9 @@ function execFunctionDef(ctx, ast) {
}; };
ctx.functions[ast.name] = { ctx.functions[ast.name] = {
block: ast.block, block: ast.block,
params: ast.params
params: ast.params,
fileName: ctx.fileName,
filePath: ctx.filePath
}; };
} }
@ -383,7 +387,7 @@ function execDeclareComponent(ctx, ast) {
}; };
} }
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 (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"); if (fn.type != "FUNCTIONCALL") return error(ctx, fn, "Right type of instantiate component must be a function call");
@ -408,13 +412,16 @@ function execInstantiateComponet(ctx, vr, fn) {
if (template.params.length != paramValues.length) return error(ctx, fn, "Invalid Number of parameters"); 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"); if (vComp.type != "COMPONENT") return error(ctx, fn, "Assigning to a non component");
const cIdx = vComp.cIdx; const cIdx = vComp.cIdx;
if (cIdx == -1) return error(ctx, fn, "Component not defined"); 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); instantiateComponent(cIdx+i);
} }
@ -762,11 +769,12 @@ function execVarAssignement(ctx, ast) {
const [num, sels, typ] = getScopeRef(ctx, v.name, v.selectors); const [num, sels, typ] = getScopeRef(ctx, v.name, v.selectors);
if (ctx.error) return; 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 ((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 (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`); 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]); const res = exec(ctx, ast.values[1]);

+ 1
- 1
src/utils.js

@ -38,7 +38,7 @@ function flatArray(a) {
fillArray(res, a[i]); fillArray(res, a[i]);
} }
} else { } else {
res.push(a);
res.push(bigInt(a));
} }
} }
} }

+ 2
- 2
src/zqfield.js

@ -30,7 +30,7 @@ module.exports = class ZqField {
} }
mul(a, b) { mul(a, b) {
return a.mul(b).mod(this.p);
return a.times(b).mod(this.p);
} }
lt(a, b) { lt(a, b) {
@ -59,7 +59,7 @@ module.exports = class ZqField {
div(a, b) { div(a, b) {
assert(!b.isZero(), "Division by zero"); 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) { idiv(a, b) {

+ 11
- 0
test/basiccases.js

@ -287,4 +287,15 @@ describe("basic cases", function () {
] ]
); );
}); });
it("Component array ", async () => {
await doTest(
"componentarray.circom",
[
[{in: 1}, {out: 1}],
[{in: 2}, {out: 256}],
[{in: 3}, {out: 6561}],
[{in:-1}, {out: 1}],
]
);
});
}); });

+ 28
- 0
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);

Loading…
Cancel
Save