mirror of
https://github.com/arnaucube/circom.git
synced 2026-02-06 18:56:40 +01:00
functions added
This commit is contained in:
@@ -109,14 +109,14 @@ Circom_Sizes Circom_CalcWit::getSignalSizes(int cIdx, u64 hash) {
|
|||||||
return circuit->components[cIdx].entries[entryPos].sizes;
|
return circuit->components[cIdx].entries[entryPos].sizes;
|
||||||
}
|
}
|
||||||
|
|
||||||
PBigInt Circom_CalcWit::allocBigInts(Circom_Sizes sizes) {
|
PBigInt Circom_CalcWit::allocBigInts(int n) {
|
||||||
PBigInt res = new BigInt[sizes[0]];
|
PBigInt res = new BigInt[n];
|
||||||
for (int i=0; i<sizes[0]; i++) mpz_init2(res[i], 256);
|
for (int i=0; i<n; i++) mpz_init2(res[i], 256);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Circom_CalcWit::freeBigInts(PBigInt bi, Circom_Sizes sizes) {
|
void Circom_CalcWit::freeBigInts(PBigInt bi, int n) {
|
||||||
for (int i=0; i<sizes[0]; i++) mpz_clear(bi[i]);
|
for (int i=0; i<n; i++) mpz_clear(bi[i]);
|
||||||
delete[] bi;
|
delete[] bi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ public:
|
|||||||
int getSignalOffset(int cIdx, u64 hash);
|
int getSignalOffset(int cIdx, u64 hash);
|
||||||
Circom_Sizes getSignalSizes(int cIdx, u64 hash);
|
Circom_Sizes getSignalSizes(int cIdx, u64 hash);
|
||||||
|
|
||||||
PBigInt allocBigInts(Circom_Sizes sizes);
|
PBigInt allocBigInts(int n);
|
||||||
void freeBigInts(PBigInt bi, Circom_Sizes sizes);
|
void freeBigInts(PBigInt bi, int n);
|
||||||
|
|
||||||
void getSignal(int cIdx, int sIdx, PBigInt value);
|
void getSignal(int cIdx, int sIdx, PBigInt value);
|
||||||
void setSignal(int cIdx, int sIdx, PBigInt value);
|
void setSignal(int cIdx, int sIdx, PBigInt value);
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ ZqField::ZqField(PBigInt ap) {
|
|||||||
mpz_init_set_ui(one, 1);
|
mpz_init_set_ui(one, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ZqField::add(PBigInt r, PBigInt a, PBigInt b) {
|
void ZqField::add(PBigInt r, PBigInt a, PBigInt b) {
|
||||||
mpz_add(*r,*a,*b);
|
mpz_add(*r,*a,*b);
|
||||||
mpz_fdiv_r(*r, *r, p);
|
mpz_fdiv_r(*r, *r, p);
|
||||||
@@ -25,6 +24,6 @@ int ZqField::isTrue(PBigInt a) {
|
|||||||
return mpz_sgn(*a);
|
return mpz_sgn(*a);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZqField::copy(PBigInt a, PBigInt b) {
|
void ZqField::copyn(PBigInt a, PBigInt b, int n) {
|
||||||
return mpz_set(*a, *b);
|
for (int i=0;i<n; i++) mpz_set(a[i], b[i]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public:
|
|||||||
BigInt zero;
|
BigInt zero;
|
||||||
ZqField(PBigInt ap);
|
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 add(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);
|
||||||
|
|||||||
130
src/c_build.js
130
src/c_build.js
@@ -27,6 +27,9 @@ module.exports = buildC;
|
|||||||
|
|
||||||
|
|
||||||
function buildC(ctx) {
|
function buildC(ctx) {
|
||||||
|
ctx.definedFunctions = {};
|
||||||
|
ctx.functionCodes = [];
|
||||||
|
ctx.buildFunction = buildFunction;
|
||||||
ctx.code = "";
|
ctx.code = "";
|
||||||
ctx.conditionalCodeHeader = "";
|
ctx.conditionalCodeHeader = "";
|
||||||
ctx.tmpNames = {};
|
ctx.tmpNames = {};
|
||||||
@@ -36,7 +39,10 @@ function buildC(ctx) {
|
|||||||
ctx.addSizes = addSizes;
|
ctx.addSizes = addSizes;
|
||||||
|
|
||||||
const entryTables = buildEntryTables(ctx);
|
const entryTables = buildEntryTables(ctx);
|
||||||
|
ctx.globalNames = ctx.tmpNames;
|
||||||
|
|
||||||
const code = buildCode(ctx);
|
const code = buildCode(ctx);
|
||||||
|
const functions = buildFuncFunctions(ctx);
|
||||||
const compnentsArray = buildComponentsArray(ctx);
|
const compnentsArray = buildComponentsArray(ctx);
|
||||||
|
|
||||||
const headder = buildHeader(ctx);
|
const headder = buildHeader(ctx);
|
||||||
@@ -49,6 +55,7 @@ function buildC(ctx) {
|
|||||||
headder + "\n" +
|
headder + "\n" +
|
||||||
sizes + "\n" +
|
sizes + "\n" +
|
||||||
entryTables + "\n" +
|
entryTables + "\n" +
|
||||||
|
functions + "\n" +
|
||||||
code + "\n" +
|
code + "\n" +
|
||||||
compnentsArray + "\n" +
|
compnentsArray + "\n" +
|
||||||
mapIsInput + "\n" +
|
mapIsInput + "\n" +
|
||||||
@@ -128,31 +135,10 @@ function buildEntryTables(ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function buildCode(ctx) {
|
function buildCode(ctx) {
|
||||||
const globalNames = ctx.tmpNames;
|
|
||||||
|
|
||||||
const fDefined = {};
|
const fDefined = {};
|
||||||
|
|
||||||
const functions = [];
|
const fnComponents = [];
|
||||||
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 += "}";
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i=0; i<ctx.components.length; i++) {
|
for (let i=0; i<ctx.components.length; i++) {
|
||||||
const h = hashComponentCall(ctx, i);
|
const h = hashComponentCall(ctx, i);
|
||||||
const fName = ctx.components[i].template+"_"+h;
|
const fName = ctx.components[i].template+"_"+h;
|
||||||
@@ -162,11 +148,10 @@ function buildCode(ctx) {
|
|||||||
const scope = {_prefix : ""};
|
const scope = {_prefix : ""};
|
||||||
ctx.scopes = [scope];
|
ctx.scopes = [scope];
|
||||||
ctx.conditionalCode = false;
|
ctx.conditionalCode = false;
|
||||||
ctx.nScopes = 0;
|
|
||||||
ctx.code = "";
|
ctx.code = "";
|
||||||
ctx.codeHeader = "// Header\n";
|
ctx.codeHeader = "// Header\n";
|
||||||
ctx.codeFooter = "// Footer\n";
|
ctx.codeFooter = "// Footer\n";
|
||||||
ctx.tmpNames = Object.assign({},globalNames);
|
ctx.tmpNames = Object.assign({},ctx.globalNames);
|
||||||
|
|
||||||
for (let p in ctx.components[i].params) {
|
for (let p in ctx.components[i].params) {
|
||||||
newRef(ctx, "BIGINT", p, bigInt(ctx.components[i].params[p]));
|
newRef(ctx, "BIGINT", p, bigInt(ctx.components[i].params[p]));
|
||||||
@@ -182,12 +167,17 @@ function buildCode(ctx) {
|
|||||||
) +
|
) +
|
||||||
"}\n";
|
"}\n";
|
||||||
|
|
||||||
functions.push(S);
|
fnComponents.push(S);
|
||||||
}
|
}
|
||||||
ctx.components[i].fnName = fName;
|
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) {
|
function buildComponentsArray(ctx) {
|
||||||
@@ -327,6 +317,7 @@ function hashComponentCall(ctx, cIdx) {
|
|||||||
return cIdx;
|
return cIdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getTmpName(_suggestedName) {
|
function getTmpName(_suggestedName) {
|
||||||
let suggestedName;
|
let suggestedName;
|
||||||
if (_suggestedName) {
|
if (_suggestedName) {
|
||||||
@@ -381,3 +372,90 @@ function addSizes(_sizes) {
|
|||||||
return labelName;
|
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";
|
||||||
|
}
|
||||||
|
|||||||
179
src/c_gen.js
179
src/c_gen.js
@@ -5,10 +5,9 @@ const assert = require("assert");
|
|||||||
module.exports.gen = gen;
|
module.exports.gen = gen;
|
||||||
module.exports.newRef = newRef;
|
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));
|
const isValue = ((typeof(value) != "undefined")&&(value != null));
|
||||||
let name;
|
let name;
|
||||||
let sizes;
|
|
||||||
if (!_name) {
|
if (!_name) {
|
||||||
name = ctx.getTmpName();
|
name = ctx.getTmpName();
|
||||||
} else {
|
} else {
|
||||||
@@ -18,14 +17,12 @@ function newRef(ctx, type, _name, value, _sizes) {
|
|||||||
name = _name;
|
name = _name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (typeof(_sizes) == "string") {
|
if (Array.isArray(sizes)) {
|
||||||
sizes = _sizes;
|
sizes = utils.accSizes(sizes);
|
||||||
} else if (Array.isArray(_sizes)) {
|
|
||||||
sizes = newSizes(ctx, _sizes);
|
|
||||||
} else if (isValue) {
|
} else if (isValue) {
|
||||||
sizes = newSizes(ctx, utils.extractSizes(value));
|
sizes = utils.accSizes(utils.extractSizes(value));
|
||||||
} else {
|
} else {
|
||||||
sizes = newSizes(ctx, []);
|
sizes = [1, 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
const scope = ctx.scopes[ctx.scopes.length-1];
|
const scope = ctx.scopes[ctx.scopes.length-1];
|
||||||
@@ -47,23 +44,6 @@ function newRef(ctx, type, _name, value, _sizes) {
|
|||||||
return name;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function instantiateRef(ctx, name, initValue) {
|
function instantiateRef(ctx, name, initValue) {
|
||||||
const v = getScope(ctx, name);
|
const v = getScope(ctx, name);
|
||||||
@@ -71,27 +51,8 @@ function instantiateRef(ctx, name, initValue) {
|
|||||||
if (v.used) return;
|
if (v.used) return;
|
||||||
|
|
||||||
if (v.type=="BIGINT") {
|
if (v.type=="BIGINT") {
|
||||||
|
ctx.codeHeader += `PBigInt ${v.label} = ctx->allocBigInts(${v.sizes[0]});\n`;
|
||||||
const iSize = getScope(ctx, v.sizes);
|
ctx.codeFooter += `ctx->freeBigInts(${v.label}, ${v.sizes[0]});\n`;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (v.type=="INT") {
|
} else if (v.type=="INT") {
|
||||||
ctx.codeHeader += `int ${v.label};\n`;
|
ctx.codeHeader += `int ${v.label};\n`;
|
||||||
} else if (v.type=="SIZES") {
|
} else if (v.type=="SIZES") {
|
||||||
@@ -112,15 +73,15 @@ function instantiateRef(ctx, name, initValue) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function instantiateConstant(ctx, value) {
|
function instantiateConstant(ctx, value) {
|
||||||
const labelSize = ctx.addSizes(utils.extractSizes(value));
|
const sizes = utils.accSizes(utils.extractSizes(value));
|
||||||
const flatedValue = utils.flatArray(value);
|
const flatedValue = utils.flatArray(value);
|
||||||
const res = ctx.getTmpName("_const");
|
const res = ctx.getTmpName("_const");
|
||||||
ctx.codeHeader += `PBigInt ${res};\n`;
|
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++) {
|
for (let i=0; i<flatedValue.length; i++) {
|
||||||
ctx.codeHeader += `mpz_set_str(${res}[${i}], "${flatedValue[i].toString(10)}", 10);\n`;
|
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;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,40 +300,23 @@ 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);
|
||||||
|
|
||||||
const sizes=[];
|
let sizes=[];
|
||||||
let instantiate = false;
|
|
||||||
for (let i=0; i< ast.name.selectors.length; i++) {
|
for (let i=0; i< ast.name.selectors.length; i++) {
|
||||||
const size = gen(ctx, ast.name.selectors[i]);
|
const size = gen(ctx, ast.name.selectors[i]);
|
||||||
if (ctx.error) return;
|
if (ctx.error) return;
|
||||||
|
|
||||||
if (size.used) {
|
if (size.used) {
|
||||||
instantiate = true;
|
return error(ctx, ast, "Variable size variables not allowed");
|
||||||
sizes.push(`BigInt2Int(${scope[size].label})`);
|
|
||||||
} else {
|
} else {
|
||||||
sizes.push(size.value.toJSNumber());
|
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] = {
|
const res = scope[varName] = {
|
||||||
stack: true,
|
stack: true,
|
||||||
type: "BIGINT",
|
type: "BIGINT",
|
||||||
sizes: vSizes,
|
sizes: sizes,
|
||||||
label: labelName,
|
label: labelName,
|
||||||
used: false,
|
used: false,
|
||||||
};
|
};
|
||||||
@@ -405,7 +349,15 @@ function genGetOffset(ctx, vOffset, vSizes, sels) {
|
|||||||
|
|
||||||
if ((sels)&&(sels.length>0)) {
|
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++) {
|
for (let i=0; i<sels.length; i++) {
|
||||||
const vIdx = gen(ctx, sels[i]);
|
const vIdx = gen(ctx, sels[i]);
|
||||||
@@ -459,7 +411,6 @@ 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);
|
||||||
|
|
||||||
|
|
||||||
if (v.type == "SIGNAL") {
|
if (v.type == "SIGNAL") {
|
||||||
let vOffset;
|
let vOffset;
|
||||||
if (ast.selectors.length>0) {
|
if (ast.selectors.length>0) {
|
||||||
@@ -476,13 +427,15 @@ function genVariable(ctx, ast) {
|
|||||||
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");
|
const res = newRef(ctx, "BIGINT", "_v", v.sizes.slice(ast.sels.length));
|
||||||
instantiateRef(ctx, res);
|
res.used = true;
|
||||||
ctx.code += `${res} = ${ast.name} + ${vOffset};\n`;
|
ctx.codeHeader += `PBigInt ${res.label}`;
|
||||||
|
ctx.code += `${res} = ${ast.name} + ${vOffset.label};\n`;
|
||||||
return res;
|
return res;
|
||||||
} else if (offset.value) {
|
} else if (offset.value) {
|
||||||
const res = newRef(ctx, "BIGINT", "_v");
|
const res = newRef(ctx, "BIGINT", "_v", v.sizes.slice(ast.sels.length));
|
||||||
instantiateRef(ctx, res);
|
res.used = true;
|
||||||
|
ctx.codeHeader += `PBigInt ${res.label}`;
|
||||||
ctx.code += `${res} = ${ast.name} + ${vOffset.value};\n`;
|
ctx.code += `${res} = ${ast.name} + ${vOffset.value};\n`;
|
||||||
return res;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
@@ -490,11 +443,11 @@ function genVariable(ctx, ast) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (offset.used) {
|
if (offset.used) {
|
||||||
instantiateRef(ctx, ast.name);
|
instantiateRef(ctx, ast.name, v.value);
|
||||||
const vConstant = instantiateConstant(ctx, v.value);
|
const res = newRef(ctx, "BIGINT", "_v", v.sizes.slice(ast.sels.length));
|
||||||
const res = newRef(ctx, "BIGINT", "_v");
|
res.used = true;
|
||||||
instantiateRef(ctx, res);
|
ctx.codeHeader += `PBigInt ${res.label}`;
|
||||||
ctx.code += `${res} = ${vConstant} + ${vOffset};\n`;
|
ctx.code += `${res} = ${ast.name} + ${vOffset.label};\n`;
|
||||||
return res;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
const sa = utils.subArray(v.value, ast.selectors);
|
const sa = utils.subArray(v.value, ast.selectors);
|
||||||
@@ -672,22 +625,18 @@ function genVarAssignement(ctx, ast) {
|
|||||||
|
|
||||||
return genSetSignal(ctx, "ctx->cIdx", vsIdx, rName);
|
return genSetSignal(ctx, "ctx->cIdx", vsIdx, rName);
|
||||||
} else if (left.type == "BIGINT") {
|
} else if (left.type == "BIGINT") {
|
||||||
|
if (!utils.sameSizes(left.sizes, right.sizes)) return error(ctx, ast, "Sizes do not match");
|
||||||
if (left.used) {
|
if (left.used) {
|
||||||
if (!right.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 {
|
} else {
|
||||||
if (right.used) {
|
if (right.used) {
|
||||||
instantiateRef(ctx, lName);
|
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 {
|
} else {
|
||||||
if (ctx.conditionalCode) {
|
left.value = right.value;
|
||||||
instantiateRef(ctx, lName);
|
|
||||||
ctx.code += `ctx->field->copy(${left.label}, ${right.label});\n`;
|
|
||||||
} else {
|
|
||||||
left.value = right.value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -718,14 +667,29 @@ function genArray(ctx, ast) {
|
|||||||
|
|
||||||
|
|
||||||
function genFunctionCall(ctx, ast) {
|
function genFunctionCall(ctx, ast) {
|
||||||
let S = "[";
|
const params = [];
|
||||||
for (let i=0; i<ast.params.length; i++) {
|
for (let i=0; i<ast.params.length; i++) {
|
||||||
if (i>0) S += ",";
|
const pName = gen(ctx, ast.params[i]);
|
||||||
S += gen(ctx, ast.params[i]);
|
params.push(getScope(ctx, pName));
|
||||||
}
|
}
|
||||||
S+="]";
|
|
||||||
|
|
||||||
return `ctx.callFunction("${ast.name}", ${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 res;
|
||||||
|
} else {
|
||||||
|
const res = newRef(ctx, "BIGINT", "_retVal", fn.returnValue);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function enterConditionalCode(ctx) {
|
function enterConditionalCode(ctx) {
|
||||||
@@ -857,9 +821,26 @@ function genIf(ctx, ast) {
|
|||||||
|
|
||||||
|
|
||||||
function genReturn(ctx, ast) {
|
function genReturn(ctx, ast) {
|
||||||
const value = gen(ctx, ast.value);
|
const vName = gen(ctx, ast.value);
|
||||||
if (ctx.error) return;
|
const v= getScope(ctx, vName);
|
||||||
return `return ${value};`;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
11
src/utils.js
11
src/utils.js
@@ -11,6 +11,7 @@ module.exports.accSizes = accSizes;
|
|||||||
module.exports.fnvHash = fnvHash;
|
module.exports.fnvHash = fnvHash;
|
||||||
module.exports.stringifyBigInts = stringifyBigInts;
|
module.exports.stringifyBigInts = stringifyBigInts;
|
||||||
module.exports.unstringifyBigInts = unstringifyBigInts;
|
module.exports.unstringifyBigInts = unstringifyBigInts;
|
||||||
|
module.exports.sameSizes = sameSizes;
|
||||||
|
|
||||||
function ident(text) {
|
function ident(text) {
|
||||||
let lines = text.split("\n");
|
let lines = text.split("\n");
|
||||||
@@ -105,5 +106,15 @@ function unstringifyBigInts(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,14 @@ async function doTest(circuit, testVectors) {
|
|||||||
|
|
||||||
describe("basic cases", function () {
|
describe("basic cases", function () {
|
||||||
this.timeout(100000);
|
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 () => {
|
it("add", async () => {
|
||||||
await doTest(
|
await doTest(
|
||||||
"add.circom",
|
"add.circom",
|
||||||
@@ -59,4 +67,24 @@ describe("basic cases", function () {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
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}],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
{"in":[1,2]}
|
|
||||||
12
test/circuits/function1.circom
Normal file
12
test/circuits/function1.circom
Normal file
@@ -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();
|
||||||
13
test/circuits/function2.circom
Normal file
13
test/circuits/function2.circom
Normal file
@@ -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();
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
[
|
|
||||||
"1"
|
|
||||||
,"0"
|
|
||||||
,"0"
|
|
||||||
]
|
|
||||||
@@ -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();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user