arnaucube
arnaucube/circomPublic Self-hosted repository
functions added
Jordi Baylina jordi@baylina.cat
Fri, 29 Nov 2019 20:19:58 +0100
commit

f4bbcfd90c8fb561af56d55c793b00f1f26fbb77

parent

93330f065b5cd4d8548cc37af4c4078a7f8d92a6

M c/calcwit.cpp → c/calcwit.cpp

@@ -109,14 +109,14 @@ }

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<sizes[0]; i++) mpz_init2(res[i], 256); +PBigInt Circom_CalcWit::allocBigInts(int n) { + PBigInt res = new BigInt[n]; + for (int i=0; i<n; i++) mpz_init2(res[i], 256); return res; } -void Circom_CalcWit::freeBigInts(PBigInt bi, Circom_Sizes sizes) { - for (int i=0; i<sizes[0]; i++) mpz_clear(bi[i]); +void Circom_CalcWit::freeBigInts(PBigInt bi, int n) { + for (int i=0; i<n; i++) mpz_clear(bi[i]); delete[] bi; }
M c/calcwit.h → c/calcwit.h

@@ -35,8 +35,8 @@ Circom_Sizes getSubComponentSizes(int cIdx, u64 hash);

int getSignalOffset(int cIdx, u64 hash); Circom_Sizes getSignalSizes(int cIdx, u64 hash); - PBigInt allocBigInts(Circom_Sizes sizes); - void freeBigInts(PBigInt bi, Circom_Sizes sizes); + PBigInt allocBigInts(int n); + void freeBigInts(PBigInt bi, int n); void getSignal(int cIdx, int sIdx, PBigInt value); void setSignal(int cIdx, int sIdx, PBigInt value);
M c/zqfield.cpp → c/zqfield.cpp

@@ -6,7 +6,6 @@ mpz_init_set_ui(zero, 0);

mpz_init_set_ui(one, 1); } - void ZqField::add(PBigInt r, PBigInt a, PBigInt b) { mpz_add(*r,*a,*b); mpz_fdiv_r(*r, *r, p);

@@ -25,6 +24,6 @@ int ZqField::isTrue(PBigInt a) {

return mpz_sgn(*a); } -void ZqField::copy(PBigInt a, PBigInt b) { - return mpz_set(*a, *b); +void ZqField::copyn(PBigInt a, PBigInt b, int n) { + for (int i=0;i<n; i++) mpz_set(a[i], b[i]); }
M c/zqfield.h → c/zqfield.h

@@ -11,7 +11,7 @@ BigInt one;

BigInt zero; ZqField(PBigInt ap); - void copy(PBigInt a, PBigInt b); + void copyn(PBigInt a, PBigInt b, int n); void add(PBigInt r,PBigInt a, PBigInt b); void lt(PBigInt r, PBigInt a, PBigInt b); int isTrue(PBigInt a);
M src/c_build.js → src/c_build.js

@@ -27,6 +27,9 @@ module.exports = buildC;

function buildC(ctx) { + ctx.definedFunctions = {}; + ctx.functionCodes = []; + ctx.buildFunction = buildFunction; ctx.code = ""; ctx.conditionalCodeHeader = ""; ctx.tmpNames = {};

@@ -36,7 +39,10 @@ ctx.definedSizes = {};

ctx.addSizes = addSizes; const entryTables = buildEntryTables(ctx); + ctx.globalNames = ctx.tmpNames; + const code = buildCode(ctx); + const functions = buildFuncFunctions(ctx); const compnentsArray = buildComponentsArray(ctx); const headder = buildHeader(ctx);

@@ -49,6 +55,7 @@ return "" +

headder + "\n" + sizes + "\n" + entryTables + "\n" + + functions + "\n" + code + "\n" + compnentsArray + "\n" + mapIsInput + "\n" +

@@ -128,31 +135,10 @@ }

} function buildCode(ctx) { - const globalNames = ctx.tmpNames; const fDefined = {}; - const functions = []; - for (let f in ctx.functions) { - ctx.scope = {}; - const paramsList = []; - for (let p in ctx.functions[f].params) { - const param = ctx.functions[f].params[p]; - paramsList.push("POINTER "+param.name); - - ctx.scope[param.name] = { - type: "LOCAL", - sels: param.sels, - getter: () => { 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; i<ctx.components.length; i++) { const h = hashComponentCall(ctx, i); const fName = ctx.components[i].template+"_"+h;

@@ -162,11 +148,10 @@

const scope = {_prefix : ""}; ctx.scopes = [scope]; ctx.conditionalCode = false; - ctx.nScopes = 0; ctx.code = ""; ctx.codeHeader = "// Header\n"; ctx.codeFooter = "// Footer\n"; - ctx.tmpNames = Object.assign({},globalNames); + ctx.tmpNames = Object.assign({},ctx.globalNames); for (let p in ctx.components[i].params) { newRef(ctx, "BIGINT", p, bigInt(ctx.components[i].params[p]));

@@ -182,12 +167,17 @@ ctx.codeFooter

) + "}\n"; - functions.push(S); + fnComponents.push(S); } ctx.components[i].fnName = fName; } - return functions.join("\n"); + return fnComponents.join("\n"); +} + +function buildFuncFunctions(ctx) { + return "// Functions\n" + + ctx.functionCodes.join("\n"); } function buildComponentsArray(ctx) {

@@ -327,6 +317,7 @@ // TODO: At the moment generate a diferent function for each instance of the component

return cIdx; } + function getTmpName(_suggestedName) { let suggestedName; if (_suggestedName) {

@@ -381,3 +372,90 @@

return labelName; } +function buildFunction(name, paramValues) { + const ctx = this; + const h = hashFunctionCall(ctx, name, paramValues); + + if (ctx.definedFunctions[h]) return ctx.definedFunctions[h]; + + const res = { + fnName: `${name}_${h}` + }; + + const oldScopes = ctx.scopes; + const oldConditionalCode = ctx.conditionalCode; + const oldCode = ctx.code; + const oldCodeHeader = ctx.codeHeader; + const oldCodeFooter = ctx.codeFooter; + const oldTmpNames = ctx.tmpNames; + + + const scope = {_prefix : ""}; + ctx.scopes = [scope]; + ctx.conditionalCode = false; + ctx.code = ""; + ctx.codeHeader = "// Header\n"; + ctx.codeFooter = "// Footer\n"; + ctx.tmpNames = Object.assign({},ctx.globalNames); + ctx.returnValue = null; + ctx.returnSizes = null; + + let paramsStr = ""; + + for (let i=0; i<ctx.functions[name].params.length; i++) { + + if (paramValues[i].used) { + paramsStr += `,PBigInt ${ctx.functions[name].params[i]}`; + scope[ctx.functions[name].params[i]] = { + stack: true, + type: "BIGINT", + used: true, + sizes: paramValues[i].sizes, + label: ctx.functions[name].params[i], + }; + } else { + scope[ctx.functions[name].params[i]] = { + stack: true, + type: "BIGINT", + used: false, + sizes: paramValues[i].sizes, + label: ctx.functions[name].params[i], + value: paramValues[i].value + }; + } + } + + gen(ctx, ctx.functions[name].block); + + if (ctx.returnValue == null) { + if (ctx.returnSizes == null) assert(false, `Funciont ${name} does not return any value`); + res.type = "VARVAL_CONSTSIZE"; + let code = `void ${name}_${h}(Circom_CalcWit *ctx, PBigInt __retValue ${paramsStr}) {`; + code += utils.ident(ctx.codeHeader); + code += utils.ident(ctx.code); + code += utils.ident("returnFunc:\n"); + code += utils.ident(ctx.codeFooter); + code += "}\n"; + res.returnSizes = ctx.returnSizes; + ctx.functionCodes.push(code); + } else { + res.type = "CONSTVAL"; + res.returnValue = ctx.returnValue; + } + + ctx.scopes = oldScopes; + ctx.conditionalCode = oldConditionalCode; + ctx.code = oldCode; + ctx.codeHeader = oldCodeHeader; + ctx.codeFooter = oldCodeFooter; + ctx.tmpNames = oldTmpNames; + + ctx.definedFunctions[h] = res; + + return res; +} + +function hashFunctionCall(ctx, name, paramValues) { + // TODO + return "1234"; +}
M src/c_gen.js → src/c_gen.js

@@ -5,10 +5,9 @@

module.exports.gen = gen; module.exports.newRef = newRef; -function newRef(ctx, type, _name, value, _sizes) { +function newRef(ctx, type, _name, value, sizes) { const isValue = ((typeof(value) != "undefined")&&(value != null)); let name; - let sizes; if (!_name) { name = ctx.getTmpName(); } else {

@@ -18,14 +17,12 @@ } else {

name = _name; } } - if (typeof(_sizes) == "string") { - sizes = _sizes; - } else if (Array.isArray(_sizes)) { - sizes = newSizes(ctx, _sizes); + if (Array.isArray(sizes)) { + sizes = utils.accSizes(sizes); } else if (isValue) { - sizes = newSizes(ctx, utils.extractSizes(value)); + sizes = utils.accSizes(utils.extractSizes(value)); } else { - sizes = newSizes(ctx, []); + sizes = [1, 0]; } const scope = ctx.scopes[ctx.scopes.length-1];

@@ -43,23 +40,6 @@

if (isValue) { scope[name].value = value; } - - return name; -} - -function newSizes(ctx, sizes) { - const scope = ctx.scopes[ctx.scopes.length-1]; - - const name = ctx.getTmpName("_sz"); - - scope[name] = { - stack: true, - type: "SIZES", - used: false, - dim: sizes.length, - label: name, - value: sizes - }; return name; }

@@ -71,27 +51,8 @@ if (!v.stack) return error(ctx, null, "Using a non existing var: " + name);

if (v.used) return; if (v.type=="BIGINT") { - - const iSize = getScope(ctx, v.sizes); - - if (iSize.used) { - const labelSize = iSize.label; - ctx.codeHeader += `PBigInt ${v.label};\n`; - const c = `${v.label} = ctx->allocBigInts(${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 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; i<flatedValue.length; i++) { ctx.codeHeader += `mpz_set_str(${res}[${i}], "${flatedValue[i].toString(10)}", 10);\n`; } - ctx.codeFooter += `ctx->freeBigInts(${res}, ${labelSize});\n`; + ctx.codeFooter += `ctx->freeBigInts(${res}, ${sizes[0]});\n`; return res; }

@@ -339,40 +300,23 @@

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 @@ }

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; i<sels.length; i++) { const vIdx = gen(ctx, sels[i]);

@@ -459,7 +411,6 @@

function genVariable(ctx, ast) { const v = getScope(ctx, ast.name); - if (v.type == "SIGNAL") { let vOffset; if (ast.selectors.length>0) {

@@ -476,13 +427,15 @@ const vOffset = genGetOffset(ctx, 0, v.sizes, ast.sels );

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 @@ return ast.name;

} } 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 @@ }

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 genFunctionCall(ctx, ast) { - let S = "["; + const params = []; for (let i=0; i<ast.params.length; i++) { - if (i>0) S += ","; - S += gen(ctx, ast.params[i]); + const pName = gen(ctx, ast.params[i]); + params.push(getScope(ctx, pName)); } - 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; i<params.length; i++) { + if (params[i].used) ctx.code+=`,${params[i].label}`; + } + ctx.code+=");\n"; - return `ctx.callFunction("${ast.name}", ${S})`; + return res; + } else { + const res = newRef(ctx, "BIGINT", "_retVal", fn.returnValue); + return res; + } } function enterConditionalCode(ctx) {

@@ -857,9 +821,26 @@ }

function genReturn(ctx, ast) { - const value = gen(ctx, ast.value); - if (ctx.error) return; - return `return ${value};`; + const vName = gen(ctx, ast.value); + const v= getScope(ctx, vName); + if (ctx.returnSizes) { + if (!utils.sizesEqual(vName.sizes, ctx.returnSizes)) return error(ctx, ast, "Diferent return sizes"); + } else { + ctx.returnSizes = v.sizes; + } + if (ctx.conditionalCode) { + instantiateRef(ctx, vName, vName.value); + } + if (v.used) { + ctx.code += `ctx->field->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; }
M src/utils.js → 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");

@@ -103,6 +104,16 @@ return res;

} else { return 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<s1.length; i++) { + if (s1[i] != s2[i]) return false; + } + return true; }
M test/basiccases.js → test/basiccases.js

@@ -19,6 +19,14 @@ }

describe("basic cases", function () { this.timeout(100000); + it("inout", async () => { + 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",

@@ -56,6 +64,26 @@ "forrolled.circom",

[ [{in: 0}, {out: 0}], [{in: 10}, {out: 10}], + ] + ); + }); + 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}], ] ); });
D test/circuits/addin.json

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

-{"in":[1,2]}
A 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();
A 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();
D test/circuits/out.json

@@ -1,5 +0,0 @@

-[ - "1" -,"0" -,"0" -]
D test/inout.js

@@ -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(); - }); -});