Arrays working
@@ -142,7 +142,7 @@ void Circom_CalcWit::checkConstraint(PBigInt value1, PBigInt value2, char const *err) {
#ifdef SANITY_CHECK if (mpz_cmp(*value1, *value2) != 0) { char *pcV1 = mpz_get_str(0, 10, *value1); - char *pcV2 = mpz_get_str(0, 10, *value1); + char *pcV2 = mpz_get_str(0, 10, *value2); std::string sV1 = std::string(pcV1); std::string sV2 = std::string(pcV2); free(pcV1);
@@ -1,14 +1,27 @@
#include "zqfield.h" ZqField::ZqField(PBigInt ap) { + mpz_init2(tmp, 1024); mpz_init_set(p, *ap); mpz_init_set_ui(zero, 0); mpz_init_set_ui(one, 1); } +ZqField::~ZqField() { + mpz_clear(tmp); + mpz_clear(p); + mpz_clear(zero); + mpz_clear(one); +} + void ZqField::add(PBigInt r, PBigInt a, PBigInt b) { - mpz_add(*r,*a,*b); - mpz_fdiv_r(*r, *r, p); + mpz_add(tmp,*a,*b); + mpz_fdiv_r(*r, tmp, p); +} + +void ZqField::mul(PBigInt r, PBigInt a, PBigInt b) { + mpz_mul(tmp,*a,*b); + mpz_fdiv_r(*r, tmp, p); } void ZqField::lt(PBigInt r, PBigInt a, PBigInt b) {
@@ -4,15 +4,18 @@
#include "circom.h" class ZqField { + mpz_t tmp; public: BigInt p; BigInt one; BigInt zero; ZqField(PBigInt ap); + ~ZqField(); void copyn(PBigInt a, PBigInt b, int n); void add(PBigInt r,PBigInt a, PBigInt b); + void mul(PBigInt r,PBigInt a, PBigInt b); void lt(PBigInt r, PBigInt a, PBigInt b); int isTrue(PBigInt a); };
@@ -445,6 +445,7 @@ ctx.functionCodes.push(code);
} else { res.type = "CONSTVAL"; res.returnValue = ctx.returnValue; + res.returnSizes = ctx.returnSizes; } ctx.scopes = oldScopes;@@ -507,7 +508,7 @@ // TODO
const constParams = []; for (let i=0; i<ctx.functions[name].params.length; i++) { if (!paramValues[i].used) { - constParams.push(ctx.functions[name].params[i] + "=" + value2str(paramValues[i])); + constParams.push(ctx.functions[name].params[i] + "=" + value2str(paramValues[i].value)); } } let instanceDef = name;@@ -528,6 +529,7 @@ for (let i=0; i<v.length; i++) {
if (i>0) S+=","; S+=value2str(v[i]); } + S+="]"; return S; } else { return bigInt(v).toString();
@@ -17,7 +17,7 @@ name = _name;
} } if (Array.isArray(sizes)) { - sizes = utils.accSizes(sizes); + // sizes = sizes; } else if (utils.isDefined(value)) { sizes = utils.accSizes(utils.extractSizes(value)); } else {@@ -37,13 +37,12 @@ label: label
}; if (utils.isDefined(value)) { - scope[name].value = value; + scope[name].value = utils.flatArray(value); } return name; } - function instantiateRef(ctx, name, initValue) { const v = getScope(ctx, name); if (!v.stack) return error(ctx, null, "Using a non existing var: " + name);@@ -59,13 +58,16 @@ ctx.codeHeader += `Circom_Sizes ${v.label};\n`;
} v.used = true; if (utils.isDefined(initValue)) { - const flatedValue = utils.flatArray(initValue); - for (let i=0; i<flatedValue.length; i++) { - const c = `mpz_set_str(${v.label}[${i}], "${flatedValue[i].toString(10)}", 10);\n`; - if (ctx.conditionalCode) { - ctx.conditionalCodeHeader += c; - } else { - ctx.code += c; + if (v.type == "BIGINT") { + for (let i=0; i<initValue.length; i++) { + if (utils.isDefined(initValue[i])) { + const c = `mpz_set_str(${v.label}[${i}], "${initValue[i].toString(10)}", 10);\n`; + if (ctx.conditionalCode) { + ctx.conditionalCodeHeader += c; + } else { + ctx.code += c; + } + } } } }@@ -118,11 +120,11 @@ } else if (ast.type == "PIN") {
return genPin(ctx, ast); } else if (ast.type == "OP") { if (ast.op == "=") { - return genVarAssignement(ctx, ast); + return genAssignement(ctx, ast); } else if (ast.op == "<--") { - return genVarAssignement(ctx, ast); + return genAssignement(ctx, ast); } else if (ast.op == "<==") { - return genSignalAssignConstrain(ctx, ast); + return genSignalAssignConstraint(ctx, ast); } else if (ast.op == "===") { return genConstraint(ctx, ast); } else if (ast.op == "+=") {@@ -136,7 +138,7 @@ return genSub(ctx, ast);
} else if (ast.op == "UMINUS") { return genUMinus(ctx, ast); } else if (ast.op == "*") { - return genMul(ctx, ast); + return genBinaryOp(ctx, ast, "mul"); } else if (ast.op == "%") { return genMod(ctx, ast); } else if (ast.op == "PLUSPLUSRIGHT") {@@ -299,18 +301,26 @@
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); - let sizes=[]; - for (let i=0; i< ast.name.selectors.length; i++) { - const size = gen(ctx, ast.name.selectors[i]); - if (ctx.error) return; + let sizes; + + if (ast.name.selectors.length>0) { + sizes=[]; + for (let i=0; i< ast.name.selectors.length; i++) { + const sizeName = gen(ctx, ast.name.selectors[i]); + const size = getScope(ctx, sizeName); + if (size.sizes[0] != 1) return error(ctx, ast, "A selector cannot be an array"); + if (ctx.error) return; - if (size.used) { - return error(ctx, ast, "Variable size variables not allowed"); - } else { - sizes.push(size.value.toJSNumber()); + if (size.used) { + return error(ctx, ast, "Variable size variables not allowed"); + } else { + sizes.push(size.value[0].toJSNumber()); + } } + sizes = utils.accSizes(sizes); + } else { + sizes = null; // If not sizes, the sized are defined in the first assignement. } - sizes = utils.accSizes(sizes); const res = scope[varName] = { stack: true,@@ -319,6 +329,10 @@ sizes: sizes,
label: labelName, used: false, }; + + if (sizes) { + res.value = new Array(sizes[0]); + } scope[varName] = res;@@ -396,7 +410,7 @@ if (rStr != "") rStr += " + ";
rStr += rN; rN =0; } - if (rStr == iOffset.label) { + if ((vOffset)&&(rStr == iOffset.label)) { return vOffset; } else { const res = newRef(ctx, "INT", "_offset");@@ -410,9 +424,11 @@
function genVariable(ctx, ast) { const v = getScope(ctx, ast.name); + const l = ast.selectors ? ast.selectors.length : 0; + if (v.type == "SIGNAL") { let vOffset; - if (ast.selectors.length>0) { + if (l>0) { const vsOffset = genGetSigalOffset(ctx, "ctx->cIdx", ast.name); const vsSizes = genGetSignalSizes(ctx, "ctx->cIdx", ast.name); vOffset = genGetOffset(ctx, vsOffset, vsSizes, ast.selectors );@@ -422,36 +438,37 @@ }
return genGetSignal(ctx, "ctx->cIdx", vOffset); } else if (v.type == "BIGINT") { - const vOffset = genGetOffset(ctx, 0, v.sizes, ast.sels ); + const vOffset = genGetOffset(ctx, 0, v.sizes, ast.selectors ); const offset = getScope(ctx, vOffset); if (v.used) { if (offset.used) { - const res = newRef(ctx, "BIGINT", "_v", v.sizes.slice(ast.sels.length)); + const resN = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l)); + const res = getScope(ctx, resN); res.used = true; - ctx.codeHeader += `PBigInt ${res.label}`; - ctx.code += `${res} = ${ast.name} + ${vOffset.label};\n`; - return res; + ctx.codeHeader += `PBigInt ${res.label};\n`; + ctx.code += `${res.label} = ${ast.name} + ${offset.label};\n`; + return resN; } else if (offset.value) { - const res = newRef(ctx, "BIGINT", "_v", v.sizes.slice(ast.sels.length)); + const resN = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l)); + const res = getScope(ctx, resN); res.used = true; - ctx.codeHeader += `PBigInt ${res.label}`; - ctx.code += `${res} = ${ast.name} + ${vOffset.value};\n`; - return res; + ctx.codeHeader += `PBigInt ${res.label};\n`; + ctx.code += `${res.label} = ${ast.name} + ${offset.value};\n`; + return resN; } else { return ast.name; } } else { if (offset.used) { instantiateRef(ctx, ast.name, v.value); - const res = newRef(ctx, "BIGINT", "_v", v.sizes.slice(ast.sels.length)); + const res = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l)); res.used = true; - ctx.codeHeader += `PBigInt ${res.label}`; - ctx.code += `${res} = ${ast.name} + ${vOffset.label};\n`; + ctx.codeHeader += `PBigInt ${res};\n`; + ctx.code += `${res} = ${ast.name} + ${offset.label};\n`; return res; } else { - const sa = utils.subArray(v.value, ast.selectors); - const res = newRef(ctx, "BIGINT", "_v", sa); - return res; + // return newSubRef(ctx, ast.name, ast.selectors); + return newRef(ctx, "BIGINT", "_v", v.value.slice(offset.value[0], offset.value[0] + v.sizes[l]),v.sizes.slice(l)); } } }@@ -550,39 +567,106 @@ ctx.code += `ctx->getSignal(${cIdx}, ${sIdx}, ${res});\n`;
return res; } -function genVarAssignement(ctx, ast) { +function genPinAssignement(ctx, ast) { + let vcIdx; + if (ast.values[0].component.selectors.length>0) { + const vcOffset = genGetSubComponentOffset(ctx, "ctx->cIdx", ast.values[0].component.name); + const vcSizes = genGetSubComponentSizes(ctx, "ctx->cIdx", ast.values[0].component.name); + vcIdx = genGetOffset(ctx, vcOffset, vcSizes, ast.values[0].component.selectors ); + } else { + vcIdx = genGetSubComponentOffset(ctx, "ctx->cIdx", ast.values[0].component.name); + } + + let vsIdx; + if (ast.values[0].pin.selectors.length>0) { + const vsOffset = genGetSigalOffset(ctx, vcIdx, ast.values[0].pin.name); + const vsSizes = genGetSignalSizes(ctx, vcIdx, ast.values[0].pin.name); + vsIdx = genGetOffset(ctx, vsOffset, vsSizes, ast.values[0].pin.selectors ); + } else { + vsIdx = genGetSigalOffset(ctx, vcIdx, ast.values[0].pin.name); + } + + const vVal = gen(ctx, ast.values[1]); + + genSetSignal(ctx, vcIdx, vsIdx, vVal); + + return vVal; +} + +function genSignalAssignmen(ctx, ast, lName, sels, rName) { + let vsIdx; + if (sels.length>0) { + const vsOffset = genGetSigalOffset(ctx, "ctx->cIdx", lName); + const vsSizes = genGetSignalSizes(ctx, "ctx->cIdx", lName); + vsIdx = genGetOffset(ctx, vsOffset, vsSizes, sels ); + } else { + vsIdx = genGetSigalOffset(ctx, "ctx->cIdx", lName); + } - let lName; - let sels; + return genSetSignal(ctx, "ctx->cIdx", vsIdx, rName); +} - if (ctx.error) return; +function genVarAssignment(ctx, ast, lName, sels, rName) { - if (ast.values[0].type == "PIN") { + const left = getScope(ctx, lName); + const right = getScope(ctx, rName); + if (!utils.isDefined(left.sizes)) { + left.sizes = right.sizes; + left.value = new Array(left.sizes[0]); + } + if (!utils.sameSizes(left.sizes.slice(sels.length), right.sizes)) return error(ctx, ast, "Sizes do not match"); - let vcIdx; - if (ast.values[0].component.selectors.length>0) { - const vcOffset = genGetSubComponentOffset(ctx, "ctx->cIdx", ast.values[0].component.name); - const vcSizes = genGetSubComponentSizes(ctx, "ctx->cIdx", ast.values[0].component.name); - vcIdx = genGetOffset(ctx, vcOffset, vcSizes, ast.values[0].component.selectors ); + const oName = genGetOffset(ctx, 0, left.sizes, sels); + const offset = getScope(ctx, oName); + + let instantiated=false; + if (left.used) { + instantiateRef(ctx, rName, right.value); + instantiated=true; + } else if (right.used) { + if (sels.length == 0) { + instantiateRef(ctx,lName); + } else { + instantiateRef(ctx,lName, left.value); + } + instantiated=true; + } else if (offset.used) { + instantiateRef(ctx, rName, right.value); + if (sels.length == 0) { + instantiateRef(ctx,lName); } else { - vcIdx = genGetSubComponentOffset(ctx, "ctx->cIdx", ast.values[0].component.name); + instantiateRef(ctx,lName, left.value); } + instantiated=true; + } - let vsIdx; - if (ast.values[0].pin.selectors.length>0) { - const vsOffset = genGetSigalOffset(ctx, vcIdx, ast.values[0].pin.name); - const vsSizes = genGetSignalSizes(ctx, vcIdx, ast.values[0].pin.name); - vsIdx = genGetOffset(ctx, vsOffset, vsSizes, ast.values[0].pin.selectors ); + if (instantiated) { + if (offset.used) { + ctx.code += `ctx->field->copyn(${lName} + ${oName}, ${rName}, ${right.sizes[0]});\n`; } else { - vsIdx = genGetSigalOffset(ctx, vcIdx, ast.values[0].pin.name); + if (offset.value[0]>0) { + ctx.code += `ctx->field->copyn(${lName} + ${offset.value[0]}, ${rName}, ${right.sizes[0]});\n`; + } else { + ctx.code += `ctx->field->copyn(${lName}, ${rName}, ${right.sizes[0]});\n`; + } } + } else { + if (offset.value[0]>0) { + for (let i=0; i<right.sizes[0]; i++) left.value[offset.value[0] + i] = right.value[i]; + } else { + for (let i=0; i<right.sizes[0]; i++) left.value[i] = right.value[i]; + } + } +} + +function genAssignement(ctx, ast) { - const vVal = gen(ctx, ast.values[1]); + let lName; + let sels; - genSetSignal(ctx, vcIdx, vsIdx, vVal); + if (ctx.error) return; - return vVal; - } + if (ast.values[0].type == "PIN") return genPinAssignement(ctx, ast); if (ast.values[0].type == "DECLARE") { lName = gen(ctx, ast.values[0]);@@ -597,51 +681,23 @@
const left = getScope(ctx, lName); if (!left) return error(ctx, ast, "Variable does not exists: "+ast.values[0].name); - if (ctx.conditionalCode && !left.used) { - instantiateRef(ctx, lName, left.value); - } - // Component instantiation is already done. if (left.type == "COMPONENT") { ctx.last = lName; return; } + if (ctx.conditionalCode && !left.used) { + instantiateRef(ctx, lName, left.value); + } const rName = gen(ctx, ast.values[1]); - const right = getScope(ctx, rName); - if (left.type == "SIGNAL") { + if (left.type == "SIGNAL") return genSignalAssignmen(ctx, ast, lName, sels, rName); - let vsIdx; - if (sels.length>0) { - const vsOffset = genGetSigalOffset(ctx, "ctx->cIdx", lName); - const vsSizes = genGetSignalSizes(ctx, "ctx->cIdx", lName); - vsIdx = genGetOffset(ctx, vsOffset, vsSizes, sels ); - } else { - vsIdx = genGetSigalOffset(ctx, "ctx->cIdx", lName); - } + if (left.type == "BIGINT") return genVarAssignment(ctx, ast, lName, sels, rName); - 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, right.value); - } - ctx.code += `ctx->field->copyn(${left.label}, ${right.label}, ${right.sizes[0]});\n`; - } else { - if (right.used) { - instantiateRef(ctx, lName); - ctx.code += `ctx->field->copyn(${left.label}, ${right.label}, ${right.sizes[0]});\n`; - } else { - left.value = right.value; - } - } - } else { - return error(ctx, ast, "Assigning to invalid"); - } - return lName; + return error(ctx, ast, "Assigning to invalid"); } function genConstraint(ctx, ast) {@@ -655,13 +711,43 @@ }
function genArray(ctx, ast) { - let S = "["; + let subSizes; + let instantiate = false; + if (ast.values.length == 0) return error(ctx, ast, "Arrays with zero elements not allowed"); + const value = []; + const names = []; for (let i=0; i<ast.values.length; i++) { - if (i>0) S += ","; - S += gen(ctx, ast.values[i]); + const eName = gen(ctx, ast.values[i]); + const e = getScope(ctx, eName); + + if (i==0) { + subSizes = e.sizes; + } else { + if (!utils.sameSizes(subSizes, e.sizes)) return error(ctx, ast, "Heteroeneus array not allowed"); + } + if (e.used) { + instantiate = true; + } + if (!instantiate) { + value.push(...e.value); + } + names.push(eName); + } + + const newSize = [subSizes[0]*ast.values.length , ...subSizes]; + + if (instantiate) { + const rName = newRef(ctx, "BIGINT", "_arr", null, newSize); + instantiateRef(ctx, rName); + for (let i=0; i<ast.values.length; i++) { + ctx.code += `ctx->field->copyn(${rName}+${i*subSizes[0]}, ${names[i]}, ${subSizes[0]});\n`; + } + return rName; + } else { + const rName = newRef(ctx, "BIGINT", "_arr", value, newSize); + return rName; } - S+="]"; - return S; + }@@ -675,7 +761,7 @@
const fn = ctx.buildFunction(ast.name, params); if (fn.type == "VARVAL_CONSTSIZE") { - const res = newRef(ctx, "BIGINT", `_ret${ast.name}Sizes`, fn.retSizes); + const res = newRef(ctx, "BIGINT", `_ret${ast.name}Sizes`, null, fn.returnSizes); instantiateRef(ctx, res); ctx.code +=`${fn.fnName}(ctx, ${res}`;@@ -686,7 +772,7 @@ ctx.code+=");\n";
return res; } else { - const res = newRef(ctx, "BIGINT", "_retVal", fn.returnValue); + const res = newRef(ctx, "BIGINT", "_retVal", fn.returnValue, fn.returnSizes); return res; } }@@ -727,6 +813,8 @@
const condName = gen(ctx, ast.condition); const cond = getScope(ctx, condName); + if (!utils.sameSizes(cond.sizes, [1,0])) return error(ctx, ast.condition, "Operation cannot be done on an array"); + if (cond.used) { inLoop = true; enterConditionalCode(ctx);@@ -738,7 +826,7 @@ `${condVar} = ctx->field->isTrue(${condName});\n` +
`while (${condVar}) {\n`; } else { if (!utils.isDefined(cond.value)) return error(ctx, ast, "condition value not assigned"); - if (cond.value.isZero()) end=true; + if (cond.value[0].isZero()) end=true; }@@ -772,7 +860,7 @@ `${condVar} = ctx->field->isTrue(${condName2});\n` +
`while (${condVar}) {\n`; } else { ctx.code = oldCode + ctx.code; - if (cond2.value.isZero()) end=true; + if (cond2.value[0].isZero()) end=true; } } else { ctx.code =@@ -844,35 +932,35 @@ }
-function genSignalAssignConstrain(ctx, ast) { - const res = genVarAssignement(ctx, ast); +function genSignalAssignConstraint(ctx, ast) { + const res = genAssignement(ctx, ast); // genConstraint(ctx, ast); return res; // return genVarAssignement(ctx, ast); } function genVarAddAssignement(ctx, ast) { - return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: ast.values}]}); + return genAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: ast.values}]}); } function genVarMulAssignement(ctx, ast) { - return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "*", values: ast.values}]}); + return genAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "*", values: ast.values}]}); } function genPlusPlusRight(ctx, ast) { - return `(${genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]})}).add(__P__).sub(bigInt(1)).mod(__P__)`; + return `(${genAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]})}).add(__P__).sub(bigInt(1)).mod(__P__)`; } function genPlusPlusLeft(ctx, ast) { - return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]}); + return genAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]}); } function genMinusMinusRight(ctx, ast) { - return `(${genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "-", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]})}).add(__P__).sub(bigInt(1)).mod(__P__)`; + return `(${genAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "-", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]})}).add(__P__).sub(bigInt(1)).mod(__P__)`; } function genMinusMinusLeft(ctx, ast) { - return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "-", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]}); + return genAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "-", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]}); } function genBinaryOp(ctx, ast, op) {@@ -886,6 +974,8 @@ const b = getScope(ctx, bName);
if ((!a.used)&&(!utils.isDefined(a.value))) return error(ctx, ast, "Using a not assigned varialble: "+aName); if ((!b.used)&&(!utils.isDefined(b.value))) return error(ctx, ast, "Using a not assigned varialble: "+bName); + if (!utils.sameSizes(a.sizes, [1,0])) return error(ctx, ast, "Operation cannot be done on an array"); + if (!utils.sameSizes(b.sizes, [1,0])) return error(ctx, ast, "Operation cannot be done on an array"); let rName; if (a.used || b.used) {@@ -900,18 +990,11 @@ rName = newRef(ctx, "BIGINT", "_tmp");
instantiateRef(ctx, rName); ctx.code += `ctx->field->${op}(${rName},${aName}, ${bName});\n`; } else { - rName = newRef(ctx, "BIGINT", "_tmp", ctx.field[op](a.value, b.value)); + rName = newRef(ctx, "BIGINT", "_tmp", ctx.field[op](a.value[0], b.value[0])); } return rName; } -function genMul(ctx, ast) { - const a = gen(ctx, ast.values[0]); - if (ctx.error) return; - const b = gen(ctx, ast.values[1]); - if (ctx.error) return; - return `bigInt(${a}).mul(bigInt(${b})).mod(__P__)`; -} function genSub(ctx, ast) { const a = gen(ctx, ast.values[0]);@@ -993,14 +1076,6 @@ if (ctx.error) return;
const b = gen(ctx, ast.values[1]); if (ctx.error) return; return `bigInt(${a}).mod(bigInt(${b}))`; -} - -function genLt(ctx, ast) { - const a = gen(ctx, ast.values[0]); - if (ctx.error) return; - const b = gen(ctx, ast.values[1]); - if (ctx.error) return; - return `bigInt(${a}).lt(bigInt(${b})) ? 1 : 0`; } function genGt(ctx, ast) {
@@ -6,7 +6,6 @@
module.exports.extractSizes =extractSizes; module.exports.flatArray = flatArray; module.exports.csArr = csArr; -module.exports.subArray = subArray; module.exports.accSizes = accSizes; module.exports.fnvHash = fnvHash; module.exports.stringifyBigInts = stringifyBigInts;@@ -54,12 +53,6 @@ }
return S; } -function subArray(value, sels) { - if ((!sels) || (sels.length == 0)) return value; - - return subArray(value[sels[0]], sels.slice(1)); -} - function accSizes(_sizes) { const sizes = _sizes || []; const accSizes = [1, 0];@@ -90,6 +83,8 @@ } else {
return o; } } + + function unstringifyBigInts(o) { if ((typeof(o) == "string") && (/^[0-9]+$/.test(o) )) {
@@ -9,6 +9,10 @@ add(a, b) {
return a.add(b).mod(this.p); } + mul(a, b) { + return a.mul(b).mod(this.p); + } + lt(a, b) { return a.lt(b) ? bigInt(1) : bigInt(0); }
@@ -97,4 +97,14 @@ [{in: __P__.minus(2)}, {out: 40}],
] ); }); + it("arrays", async () => { + await doTest( + "arrays.circom", + [ + [{in: 0}, {out: [1, 8, 51]}], + [{in: 10}, {out: [11, 28, 111]}], + [{in: __P__.minus(2)}, {out: [__P__.minus(1), 4, 39]}], + ] + ); + }); });
@@ -0,0 +1,43 @@
+// arr1 + + +function Add3(arr1, arr2, arr3) { + var res[3]; + + var i; + var j; + + res[0] = arr1; + res[1] = 0; + for (i=0; i<2; i += 1) { + res[1] = res[1] + arr2[i]; + } + + res[2] = 0; + for (i=0; i<2; i++) { + for (j=0; j<3; j += 1) { + res[2] = res[2] + arr3[i][j]; + } + } + + return res; +} + +template Main() { + signal input in; + signal output out[3]; + + var c = Add3(1, [2,3], [[4,5,6], [7,8,9]]); // [1, 5, 39]; + var d = Add3(in, [in+1, in+2], [[in+1, in+2, in+3], [in+1, in+2, in+3]]); + + out[0] <-- d[0] + c[0]; + out[0] === in+c[0]; + + out[1] <-- d[1]+c[1]; + out[1] === 2*in+3+c[1]; + + out[2] <-- d[2]+c[2]; + out[2] === 6*in+12+c[2]; +} + +component main = Main();