mirror of
https://github.com/arnaucube/circom.git
synced 2026-02-06 18:56:40 +01:00
Arrays working
This commit is contained in:
@@ -142,7 +142,7 @@ void Circom_CalcWit::checkConstraint(PBigInt value1, PBigInt value2, char const
|
||||
#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 @@ function buildFunction(name, paramValues) {
|
||||
} else {
|
||||
res.type = "CONSTVAL";
|
||||
res.returnValue = ctx.returnValue;
|
||||
res.returnSizes = ctx.returnSizes;
|
||||
}
|
||||
|
||||
ctx.scopes = oldScopes;
|
||||
@@ -507,7 +508,7 @@ function hashFunctionCall(ctx, name, paramValues) {
|
||||
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 @@ function value2str(v) {
|
||||
if (i>0) S+=",";
|
||||
S+=value2str(v[i]);
|
||||
}
|
||||
S+="]";
|
||||
return S;
|
||||
} else {
|
||||
return bigInt(v).toString();
|
||||
|
||||
285
src/c_gen.js
285
src/c_gen.js
@@ -17,7 +17,7 @@ function newRef(ctx, type, _name, value, sizes) {
|
||||
}
|
||||
}
|
||||
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 @@ function newRef(ctx, type, _name, value, sizes) {
|
||||
};
|
||||
|
||||
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,9 +58,10 @@ function instantiateRef(ctx, name, initValue) {
|
||||
}
|
||||
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 (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 {
|
||||
@@ -69,6 +69,8 @@ function instantiateRef(ctx, name, initValue) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function instantiateConstant(ctx, value) {
|
||||
@@ -118,11 +120,11 @@ function gen(ctx, ast) {
|
||||
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 @@ function gen(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 @@ function genDeclareVariable(ctx, ast) {
|
||||
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=[];
|
||||
let sizes;
|
||||
|
||||
if (ast.name.selectors.length>0) {
|
||||
sizes=[];
|
||||
for (let i=0; i< ast.name.selectors.length; i++) {
|
||||
const size = gen(ctx, ast.name.selectors[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());
|
||||
sizes.push(size.value[0].toJSNumber());
|
||||
}
|
||||
}
|
||||
sizes = utils.accSizes(sizes);
|
||||
} else {
|
||||
sizes = null; // If not sizes, the sized are defined in the first assignement.
|
||||
}
|
||||
|
||||
const res = scope[varName] = {
|
||||
stack: true,
|
||||
@@ -320,6 +330,10 @@ function genDeclareVariable(ctx, ast) {
|
||||
used: false,
|
||||
};
|
||||
|
||||
if (sizes) {
|
||||
res.value = new Array(sizes[0]);
|
||||
}
|
||||
|
||||
scope[varName] = res;
|
||||
|
||||
return varName;
|
||||
@@ -396,7 +410,7 @@ function genGetOffset(ctx, vOffset, vSizes, sels) {
|
||||
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 genGetOffset(ctx, vOffset, vSizes, sels) {
|
||||
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 @@ function genVariable(ctx, ast) {
|
||||
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,15 +567,7 @@ function genGetSignal(ctx, cIdx, sIdx) {
|
||||
return res;
|
||||
}
|
||||
|
||||
function genVarAssignement(ctx, ast) {
|
||||
|
||||
let lName;
|
||||
let sels;
|
||||
|
||||
if (ctx.error) return;
|
||||
|
||||
if (ast.values[0].type == "PIN") {
|
||||
|
||||
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);
|
||||
@@ -582,8 +591,83 @@ function genVarAssignement(ctx, ast) {
|
||||
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);
|
||||
}
|
||||
|
||||
return genSetSignal(ctx, "ctx->cIdx", vsIdx, rName);
|
||||
}
|
||||
|
||||
function genVarAssignment(ctx, ast, lName, sels, rName) {
|
||||
|
||||
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 {
|
||||
instantiateRef(ctx,lName, left.value);
|
||||
}
|
||||
instantiated=true;
|
||||
}
|
||||
|
||||
if (instantiated) {
|
||||
if (offset.used) {
|
||||
ctx.code += `ctx->field->copyn(${lName} + ${oName}, ${rName}, ${right.sizes[0]});\n`;
|
||||
} else {
|
||||
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) {
|
||||
|
||||
let lName;
|
||||
let sels;
|
||||
|
||||
if (ctx.error) return;
|
||||
|
||||
if (ast.values[0].type == "PIN") return genPinAssignement(ctx, ast);
|
||||
|
||||
if (ast.values[0].type == "DECLARE") {
|
||||
lName = gen(ctx, ast.values[0]);
|
||||
if (ctx.error) return;
|
||||
@@ -597,51 +681,23 @@ function genVarAssignement(ctx, ast) {
|
||||
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;
|
||||
}
|
||||
|
||||
function genConstraint(ctx, ast) {
|
||||
@@ -655,13 +711,43 @@ function genConstraint(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++) {
|
||||
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");
|
||||
}
|
||||
S+="]";
|
||||
return S;
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -675,7 +761,7 @@ function genFunctionCall(ctx, ast) {
|
||||
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 @@ function genFunctionCall(ctx, ast) {
|
||||
|
||||
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 @@ function genFor(ctx, ast) {
|
||||
|
||||
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 @@ function genFor(ctx, ast) {
|
||||
`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 @@ function genFor(ctx, ast) {
|
||||
`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 genReturn(ctx, ast) {
|
||||
|
||||
|
||||
|
||||
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 @@ function genBinaryOp(ctx, ast, op) {
|
||||
|
||||
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 @@ function genBinaryOp(ctx, ast, op) {
|
||||
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]);
|
||||
@@ -995,14 +1078,6 @@ function genMod(ctx, ast) {
|
||||
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) {
|
||||
const a = gen(ctx, ast.values[0]);
|
||||
if (ctx.error) return;
|
||||
|
||||
@@ -6,7 +6,6 @@ module.exports.ident =ident;
|
||||
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 @@ function csArr(_arr) {
|
||||
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];
|
||||
@@ -91,6 +84,8 @@ function stringifyBigInts(o) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function unstringifyBigInts(o) {
|
||||
if ((typeof(o) == "string") && (/^[0-9]+$/.test(o) )) {
|
||||
return bigInt(o);
|
||||
|
||||
@@ -9,6 +9,10 @@ module.exports = class ZqField {
|
||||
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 @@ 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
test/circuits/arrays.circom
Normal file
43
test/circuits/arrays.circom
Normal file
@@ -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();
|
||||
Reference in New Issue
Block a user