Browse Source

Arrays working

feature/witness_bin
Jordi Baylina 4 years ago
parent
commit
fbcc753bc1
No known key found for this signature in database GPG Key ID: 7480C80C1BE43112
9 changed files with 284 additions and 139 deletions
  1. +1
    -1
      c/calcwit.cpp
  2. +15
    -2
      c/zqfield.cpp
  3. +3
    -0
      c/zqfield.h
  4. +3
    -1
      src/c_build.js
  5. +203
    -128
      src/c_gen.js
  6. +2
    -7
      src/utils.js
  7. +4
    -0
      src/zqfield.js
  8. +10
    -0
      test/basiccases.js
  9. +43
    -0
      test/circuits/arrays.circom

+ 1
- 1
c/calcwit.cpp

@ -142,7 +142,7 @@ void Circom_CalcWit::checkConstraint(PBigInt value1, PBigInt value2, char const
#ifdef SANITY_CHECK #ifdef SANITY_CHECK
if (mpz_cmp(*value1, *value2) != 0) { if (mpz_cmp(*value1, *value2) != 0) {
char *pcV1 = mpz_get_str(0, 10, *value1); 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 sV1 = std::string(pcV1);
std::string sV2 = std::string(pcV2); std::string sV2 = std::string(pcV2);
free(pcV1); free(pcV1);

+ 15
- 2
c/zqfield.cpp

@ -1,14 +1,27 @@
#include "zqfield.h" #include "zqfield.h"
ZqField::ZqField(PBigInt ap) { ZqField::ZqField(PBigInt ap) {
mpz_init2(tmp, 1024);
mpz_init_set(p, *ap); mpz_init_set(p, *ap);
mpz_init_set_ui(zero, 0); mpz_init_set_ui(zero, 0);
mpz_init_set_ui(one, 1); 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) { 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) { void ZqField::lt(PBigInt r, PBigInt a, PBigInt b) {

+ 3
- 0
c/zqfield.h

@ -4,15 +4,18 @@
#include "circom.h" #include "circom.h"
class ZqField { class ZqField {
mpz_t tmp;
public: public:
BigInt p; BigInt p;
BigInt one; BigInt one;
BigInt zero; BigInt zero;
ZqField(PBigInt ap); ZqField(PBigInt ap);
~ZqField();
void copyn(PBigInt a, PBigInt b, int n); void copyn(PBigInt a, PBigInt b, int n);
void add(PBigInt r,PBigInt a, PBigInt b); void add(PBigInt r,PBigInt a, PBigInt b);
void mul(PBigInt r,PBigInt a, PBigInt b);
void lt(PBigInt r, PBigInt a, PBigInt b); void lt(PBigInt r, PBigInt a, PBigInt b);
int isTrue(PBigInt a); int isTrue(PBigInt a);
}; };

+ 3
- 1
src/c_build.js

@ -445,6 +445,7 @@ function buildFunction(name, paramValues) {
} else { } else {
res.type = "CONSTVAL"; res.type = "CONSTVAL";
res.returnValue = ctx.returnValue; res.returnValue = ctx.returnValue;
res.returnSizes = ctx.returnSizes;
} }
ctx.scopes = oldScopes; ctx.scopes = oldScopes;
@ -507,7 +508,7 @@ function hashFunctionCall(ctx, name, paramValues) {
const constParams = []; const constParams = [];
for (let i=0; i<ctx.functions[name].params.length; i++) { for (let i=0; i<ctx.functions[name].params.length; i++) {
if (!paramValues[i].used) { 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; let instanceDef = name;
@ -528,6 +529,7 @@ function value2str(v) {
if (i>0) S+=","; if (i>0) S+=",";
S+=value2str(v[i]); S+=value2str(v[i]);
} }
S+="]";
return S; return S;
} else { } else {
return bigInt(v).toString(); return bigInt(v).toString();

+ 203
- 128
src/c_gen.js

@ -17,7 +17,7 @@ function newRef(ctx, type, _name, value, sizes) {
} }
} }
if (Array.isArray(sizes)) { if (Array.isArray(sizes)) {
sizes = utils.accSizes(sizes);
// sizes = sizes;
} else if (utils.isDefined(value)) { } else if (utils.isDefined(value)) {
sizes = utils.accSizes(utils.extractSizes(value)); sizes = utils.accSizes(utils.extractSizes(value));
} else { } else {
@ -37,13 +37,12 @@ function newRef(ctx, type, _name, value, sizes) {
}; };
if (utils.isDefined(value)) { if (utils.isDefined(value)) {
scope[name].value = value;
scope[name].value = utils.flatArray(value);
} }
return name; return name;
} }
function instantiateRef(ctx, name, initValue) { function instantiateRef(ctx, name, initValue) {
const v = getScope(ctx, name); const v = getScope(ctx, name);
if (!v.stack) return error(ctx, null, "Using a non existing var: " + name); if (!v.stack) return error(ctx, null, "Using a non existing var: " + name);
@ -59,13 +58,16 @@ function instantiateRef(ctx, name, initValue) {
} }
v.used = true; v.used = true;
if (utils.isDefined(initValue)) { 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 @@ function gen(ctx, ast) {
return genPin(ctx, ast); return genPin(ctx, ast);
} else if (ast.type == "OP") { } else if (ast.type == "OP") {
if (ast.op == "=") { if (ast.op == "=") {
return genVarAssignement(ctx, ast);
return genAssignement(ctx, ast);
} else if (ast.op == "<--") { } else if (ast.op == "<--") {
return genVarAssignement(ctx, ast);
return genAssignement(ctx, ast);
} else if (ast.op == "<==") { } else if (ast.op == "<==") {
return genSignalAssignConstrain(ctx, ast);
return genSignalAssignConstraint(ctx, ast);
} else if (ast.op == "===") { } else if (ast.op == "===") {
return genConstraint(ctx, ast); return genConstraint(ctx, ast);
} else if (ast.op == "+=") { } else if (ast.op == "+=") {
@ -136,7 +138,7 @@ function gen(ctx, ast) {
} else if (ast.op == "UMINUS") { } else if (ast.op == "UMINUS") {
return genUMinus(ctx, ast); return genUMinus(ctx, ast);
} else if (ast.op == "*") { } else if (ast.op == "*") {
return genMul(ctx, ast);
return genBinaryOp(ctx, ast, "mul");
} else if (ast.op == "%") { } else if (ast.op == "%") {
return genMod(ctx, ast); return genMod(ctx, ast);
} else if (ast.op == "PLUSPLUSRIGHT") { } else if (ast.op == "PLUSPLUSRIGHT") {
@ -299,18 +301,26 @@ function genDeclareVariable(ctx, ast) {
if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name"); 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); 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 (size.used) {
return error(ctx, ast, "Variable size variables not allowed");
} else {
sizes.push(size.value.toJSNumber());
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[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] = { const res = scope[varName] = {
stack: true, stack: true,
@ -320,6 +330,10 @@ function genDeclareVariable(ctx, ast) {
used: false, used: false,
}; };
if (sizes) {
res.value = new Array(sizes[0]);
}
scope[varName] = res; scope[varName] = res;
return varName; return varName;
@ -396,7 +410,7 @@ function genGetOffset(ctx, vOffset, vSizes, sels) {
rStr += rN; rStr += rN;
rN =0; rN =0;
} }
if (rStr == iOffset.label) {
if ((vOffset)&&(rStr == iOffset.label)) {
return vOffset; return vOffset;
} else { } else {
const res = newRef(ctx, "INT", "_offset"); const res = newRef(ctx, "INT", "_offset");
@ -410,9 +424,11 @@ function genGetOffset(ctx, vOffset, vSizes, sels) {
function genVariable(ctx, ast) { function genVariable(ctx, ast) {
const v = getScope(ctx, ast.name); const v = getScope(ctx, ast.name);
const l = ast.selectors ? ast.selectors.length : 0;
if (v.type == "SIGNAL") { if (v.type == "SIGNAL") {
let vOffset; let vOffset;
if (ast.selectors.length>0) {
if (l>0) {
const vsOffset = genGetSigalOffset(ctx, "ctx->cIdx", ast.name); const vsOffset = genGetSigalOffset(ctx, "ctx->cIdx", ast.name);
const vsSizes = genGetSignalSizes(ctx, "ctx->cIdx", ast.name); const vsSizes = genGetSignalSizes(ctx, "ctx->cIdx", ast.name);
vOffset = genGetOffset(ctx, vsOffset, vsSizes, ast.selectors ); vOffset = genGetOffset(ctx, vsOffset, vsSizes, ast.selectors );
@ -422,36 +438,37 @@ function genVariable(ctx, ast) {
return genGetSignal(ctx, "ctx->cIdx", vOffset); return genGetSignal(ctx, "ctx->cIdx", vOffset);
} else if (v.type == "BIGINT") { } 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); const offset = getScope(ctx, vOffset);
if (v.used) { if (v.used) {
if (offset.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; 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) { } 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; 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 { } else {
return ast.name; return ast.name;
} }
} else { } else {
if (offset.used) { if (offset.used) {
instantiateRef(ctx, ast.name, v.value); 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; 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; return res;
} else { } 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 @@ function genGetSignal(ctx, cIdx, sIdx) {
return res; 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 lName;
let sels;
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);
}
if (ctx.error) return;
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);
}
if (ast.values[0].type == "PIN") {
return genSetSignal(ctx, "ctx->cIdx", vsIdx, rName);
}
function genVarAssignment(ctx, ast, lName, sels, rName) {
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 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");
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 { } 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 { } 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") { if (ast.values[0].type == "DECLARE") {
lName = gen(ctx, ast.values[0]); lName = gen(ctx, ast.values[0]);
@ -597,51 +681,23 @@ function genVarAssignement(ctx, ast) {
const left = getScope(ctx, lName); const left = getScope(ctx, lName);
if (!left) return error(ctx, ast, "Variable does not exists: "+ast.values[0].name); 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. // Component instantiation is already done.
if (left.type == "COMPONENT") { if (left.type == "COMPONENT") {
ctx.last = lName; ctx.last = lName;
return; return;
} }
if (ctx.conditionalCode && !left.used) {
instantiateRef(ctx, lName, left.value);
}
const rName = gen(ctx, ast.values[1]); 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) { function genConstraint(ctx, ast) {
@ -655,13 +711,43 @@ function genConstraint(ctx, ast) {
function genArray(ctx, ast) { 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++) { 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 @@ function genFunctionCall(ctx, ast) {
const fn = ctx.buildFunction(ast.name, params); const fn = ctx.buildFunction(ast.name, params);
if (fn.type == "VARVAL_CONSTSIZE") { 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); instantiateRef(ctx, res);
ctx.code +=`${fn.fnName}(ctx, ${res}`; ctx.code +=`${fn.fnName}(ctx, ${res}`;
@ -686,7 +772,7 @@ function genFunctionCall(ctx, ast) {
return res; return res;
} else { } else {
const res = newRef(ctx, "BIGINT", "_retVal", fn.returnValue);
const res = newRef(ctx, "BIGINT", "_retVal", fn.returnValue, fn.returnSizes);
return res; return res;
} }
} }
@ -727,6 +813,8 @@ function genFor(ctx, ast) {
const condName = gen(ctx, ast.condition); const condName = gen(ctx, ast.condition);
const cond = getScope(ctx, condName); 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) { if (cond.used) {
inLoop = true; inLoop = true;
enterConditionalCode(ctx); enterConditionalCode(ctx);
@ -738,7 +826,7 @@ function genFor(ctx, ast) {
`while (${condVar}) {\n`; `while (${condVar}) {\n`;
} else { } else {
if (!utils.isDefined(cond.value)) return error(ctx, ast, "condition value not assigned"); 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 @@ function genFor(ctx, ast) {
`while (${condVar}) {\n`; `while (${condVar}) {\n`;
} else { } else {
ctx.code = oldCode + ctx.code; ctx.code = oldCode + ctx.code;
if (cond2.value.isZero()) end=true;
if (cond2.value[0].isZero()) end=true;
} }
} else { } else {
ctx.code = ctx.code =
@ -844,35 +932,35 @@ function genReturn(ctx, ast) {
function genSignalAssignConstrain(ctx, ast) {
const res = genVarAssignement(ctx, ast);
function genSignalAssignConstraint(ctx, ast) {
const res = genAssignement(ctx, ast);
// genConstraint(ctx, ast); // genConstraint(ctx, ast);
return res; return res;
// return genVarAssignement(ctx, ast); // return genVarAssignement(ctx, ast);
} }
function genVarAddAssignement(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) { 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) { 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) { 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) { 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) { 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) { function genBinaryOp(ctx, ast, op) {
@ -886,6 +974,8 @@ function genBinaryOp(ctx, ast, op) {
if ((!a.used)&&(!utils.isDefined(a.value))) return error(ctx, ast, "Using a not assigned varialble: "+aName); 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 ((!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; let rName;
if (a.used || b.used) { if (a.used || b.used) {
@ -900,18 +990,11 @@ function genBinaryOp(ctx, ast, op) {
instantiateRef(ctx, rName); instantiateRef(ctx, rName);
ctx.code += `ctx->field->${op}(${rName},${aName}, ${bName});\n`; ctx.code += `ctx->field->${op}(${rName},${aName}, ${bName});\n`;
} else { } 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; 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) { function genSub(ctx, ast) {
const a = gen(ctx, ast.values[0]); const a = gen(ctx, ast.values[0]);
@ -995,14 +1078,6 @@ function genMod(ctx, ast) {
return `bigInt(${a}).mod(bigInt(${b}))`; 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) { function genGt(ctx, ast) {
const a = gen(ctx, ast.values[0]); const a = gen(ctx, ast.values[0]);
if (ctx.error) return; if (ctx.error) return;

+ 2
- 7
src/utils.js

@ -6,7 +6,6 @@ module.exports.ident =ident;
module.exports.extractSizes =extractSizes; module.exports.extractSizes =extractSizes;
module.exports.flatArray = flatArray; module.exports.flatArray = flatArray;
module.exports.csArr = csArr; module.exports.csArr = csArr;
module.exports.subArray = subArray;
module.exports.accSizes = accSizes; module.exports.accSizes = accSizes;
module.exports.fnvHash = fnvHash; module.exports.fnvHash = fnvHash;
module.exports.stringifyBigInts = stringifyBigInts; module.exports.stringifyBigInts = stringifyBigInts;
@ -54,12 +53,6 @@ function csArr(_arr) {
return S; return S;
} }
function subArray(value, sels) {
if ((!sels) || (sels.length == 0)) return value;
return subArray(value[sels[0]], sels.slice(1));
}
function accSizes(_sizes) { function accSizes(_sizes) {
const sizes = _sizes || []; const sizes = _sizes || [];
const accSizes = [1, 0]; const accSizes = [1, 0];
@ -91,6 +84,8 @@ function stringifyBigInts(o) {
} }
} }
function unstringifyBigInts(o) { function unstringifyBigInts(o) {
if ((typeof(o) == "string") && (/^[0-9]+$/.test(o) )) { if ((typeof(o) == "string") && (/^[0-9]+$/.test(o) )) {
return bigInt(o); return bigInt(o);

+ 4
- 0
src/zqfield.js

@ -9,6 +9,10 @@ module.exports = class ZqField {
return a.add(b).mod(this.p); return a.add(b).mod(this.p);
} }
mul(a, b) {
return a.mul(b).mod(this.p);
}
lt(a, b) { lt(a, b) {
return a.lt(b) ? bigInt(1) : bigInt(0); return a.lt(b) ? bigInt(1) : bigInt(0);
} }

+ 10
- 0
test/basiccases.js

@ -97,4 +97,14 @@ describe("basic cases", function () {
] ]
); );
}); });
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]}],
]
);
});
}); });

+ 43
- 0
test/circuits/arrays.circom

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

Loading…
Cancel
Save