mirror of
https://github.com/arnaucube/circom.git
synced 2026-02-06 18:56:40 +01:00
roll unrolled loops with code
This commit is contained in:
@@ -189,3 +189,7 @@ void ZqField::shr(PBigInt r, PBigInt a, PBigInt b) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ZqField::toInt(PBigInt a) {
|
||||||
|
return mpz_get_si (*a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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");
|
if (code != "") {
|
||||||
codes.push(code);
|
codes.push(code + "\n");
|
||||||
code =0;
|
} 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;
|
||||||
|
|
||||||
|
|||||||
22
src/c_gen.js
22
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");
|
condVarRef = newRef(ctx, "INT", "_cond");
|
||||||
instantiateRef(ctx, condVar);
|
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) {
|
||||||
|
|||||||
26
src/exec.js
26
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]);
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ function flatArray(a) {
|
|||||||
fillArray(res, a[i]);
|
fillArray(res, a[i]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.push(a);
|
res.push(bigInt(a));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
test/circuits/componentarray.circom
Normal file
28
test/circuits/componentarray.circom
Normal file
@@ -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);
|
||||||
Reference in New Issue
Block a user