Browse Source

Allows pass signal arrays to a function

master
Jordi Baylina 4 years ago
parent
commit
9f15dd2e29
No known key found for this signature in database GPG Key ID: 7480C80C1BE43112
10 changed files with 133 additions and 22 deletions
  1. +3
    -3
      package-lock.json
  2. +1
    -1
      package.json
  3. +4
    -3
      ports/c/builder.js
  4. +38
    -0
      ports/wasm/build_runtime.js
  5. +6
    -4
      ports/wasm/builder.js
  6. +2
    -1
      src/construction_phase.js
  7. +46
    -9
      src/gencode.js
  8. +1
    -1
      test/basiccases.js
  9. +11
    -0
      test/basiccases.json
  10. +21
    -0
      test/circuits/fnarray.circom

+ 3
- 3
package-lock.json

@ -208,9 +208,9 @@
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII="
}, },
"circom_runtime": { "circom_runtime": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.1.5.tgz",
"integrity": "sha512-BT3d9VCrH/rBRbThDXG731JwezKyskxyE46nACO6Tt/jaorn27LDxFDORdAAjyD0RAoBt+6FpaTp3qlYSx7Pjg==",
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.1.8.tgz",
"integrity": "sha512-5ZmzCyidkNPb1zZsJGRXTuWcJ6kW6+gRBtHgf2tFqTh5dUyWVVPH0Zg7AsU2ijPr1AmYZUlme0yORUZK5HrjOA==",
"requires": { "requires": {
"ffjavascript": "0.2.10", "ffjavascript": "0.2.10",
"fnv-plus": "^1.3.1" "fnv-plus": "^1.3.1"

+ 1
- 1
package.json

@ -30,7 +30,7 @@
}, },
"dependencies": { "dependencies": {
"chai": "^4.2.0", "chai": "^4.2.0",
"circom_runtime": "0.1.5",
"circom_runtime": "0.1.8",
"fastfile": "0.0.18", "fastfile": "0.0.18",
"ffiasm": "0.1.1", "ffiasm": "0.1.1",
"ffjavascript": "0.2.22", "ffjavascript": "0.2.22",

+ 4
- 3
ports/c/builder.js

@ -59,8 +59,9 @@ class CodeBuilderC {
this.ops.push({op: "SETSIGNAL", component, signal, value}); this.ops.push({op: "SETSIGNAL", component, signal, value});
} }
getSignal(dLabel, component, signal) {
this.ops.push({op: "GETSIGNAL", dLabel, component, signal});
getSignal(dLabel, component, signal, n) {
if (typeof(n) == "undefined") n=1;
this.ops.push({op: "GETSIGNAL", dLabel, component, signal, n});
} }
copyN(dLabel, offset, src, n) { copyN(dLabel, offset, src, n) {
@ -181,7 +182,7 @@ class CodeBuilderC {
} else if (o.op == "SETSIGNAL") { } else if (o.op == "SETSIGNAL") {
code.push(`ctx->setSignal(__cIdx, ${ref2src(o.component)}, ${ref2src(o.signal)}, ${ref2src(o.value)});`); code.push(`ctx->setSignal(__cIdx, ${ref2src(o.component)}, ${ref2src(o.signal)}, ${ref2src(o.value)});`);
} else if (o.op == "GETSIGNAL") { } else if (o.op == "GETSIGNAL") {
code.push(`ctx->getSignal(__cIdx, ${ref2src(o.component)}, ${ref2src(o.signal)}, ${o.dLabel});`);
code.push(`ctx->multiGetSignal(__cIdx, ${ref2src(o.component)}, ${ref2src(o.signal)}, ${o.dLabel}, ${o.n});`);
} else if (o.op == "COPYN") { } else if (o.op == "COPYN") {
const oS = ref2src(o.offset); const oS = ref2src(o.offset);
const dLabel = (oS != "0") ? (o.dLabel + "+" + oS) : o.dLabel; const dLabel = (oS != "0") ? (o.dLabel + "+" + oS) : o.dLabel;

+ 38
- 0
ports/wasm/build_runtime.js

@ -412,6 +412,42 @@ module.exports = function buildRuntime(module, builder) {
} }
function buildMultiGetSignal() {
const f = module.addFunction("multiGetSignal");
f.addParam("cIdx", "i32");
f.addParam("pR", "i32");
f.addParam("component", "i32");
f.addParam("signal", "i32");
f.addParam("n", "i32");
f.addLocal("i", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.setLocal("i", c.i32_const(0)),
c.block(c.loop(
c.br_if(1, c.i32_eq(c.getLocal("i"), c.getLocal("n"))),
c.call(
"getSignal",
c.getLocal("cIdx"),
c.i32_add(
c.getLocal("pR"),
c.i32_mul(
c.getLocal("i"),
c.i32_const(builder.sizeFr)
)
),
c.getLocal("component"),
c.i32_add(
c.getLocal("signal"),
c.getLocal("i")
)
),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
c.br(0)
))
);
}
function buildSetSignal() { function buildSetSignal() {
const f = module.addFunction("setSignal"); const f = module.addFunction("setSignal");
@ -847,6 +883,7 @@ module.exports = function buildRuntime(module, builder) {
buildGetSignal(); buildGetSignal();
buildSetSignal(); buildSetSignal();
buildMultiGetSignal();
buildComponentStarted(); buildComponentStarted();
buildComponentFinished(); buildComponentFinished();
@ -867,6 +904,7 @@ module.exports = function buildRuntime(module, builder) {
module.exportFunction("getFrLen"); module.exportFunction("getFrLen");
module.exportFunction("getSignalOffset32"); module.exportFunction("getSignalOffset32");
module.exportFunction("setSignal"); module.exportFunction("setSignal");
module.exportFunction("multiGetSignal");
module.exportFunction("getPWitness"); module.exportFunction("getPWitness");
module.exportFunction("Fr_toInt"); module.exportFunction("Fr_toInt");
module.exportFunction("getPRawPrime"); module.exportFunction("getPRawPrime");

+ 6
- 4
ports/wasm/builder.js

@ -62,8 +62,9 @@ class CodeBuilderWasm {
this.ops.push({op: "SETSIGNAL", component, signal, value}); this.ops.push({op: "SETSIGNAL", component, signal, value});
} }
getSignal(dLabel, component, signal) {
this.ops.push({op: "GETSIGNAL", dLabel, component, signal});
getSignal(dLabel, component, signal, n) {
if (typeof n == "undefined") n=1;
this.ops.push({op: "GETSIGNAL", dLabel, component, signal, n});
} }
copyN(dLabel, offset, src, n) { copyN(dLabel, offset, src, n) {
@ -251,11 +252,12 @@ class CodeBuilderWasm {
} else if (o.op == "GETSIGNAL") { } else if (o.op == "GETSIGNAL") {
code.push( code.push(
c.call( c.call(
"getSignal",
"multiGetSignal",
c.getLocal("cIdx"), c.getLocal("cIdx"),
this.fnBuilder._getPtr(c, o.dLabel), this.fnBuilder._getPtr(c, o.dLabel),
this.fnBuilder._deRefInt(c, o.component), this.fnBuilder._deRefInt(c, o.component),
this.fnBuilder._deRefInt(c, o.signal)
this.fnBuilder._deRefInt(c, o.signal),
c.i32_const(o.n)
) )
); );
} else if (o.op == "COPYN") { } else if (o.op == "COPYN") {

+ 2
- 1
src/construction_phase.js

@ -888,7 +888,8 @@ function execOpOp(ctx, ast, op, lr) {
right = {t:"N", v: ctx.F.one}; right = {t:"N", v: ctx.F.one};
} }
if (!right) return ctx.throwError(ast, "adding a no number");
if (!right) return ctx.throwError(ast, "right operand is not initialized");
if (!resBefore) return ctx.throwError(ast, "left operand is not initialized");
const resAfter = ctx.lc[op](resBefore, right); const resAfter = ctx.lc[op](resBefore, right);
left.v[o] = resAfter; left.v[o] = resAfter;

+ 46
- 9
src/gencode.js

@ -284,6 +284,32 @@ function genDeclareComponent(ctx, ast) {
} }
function genDeclareSignal(ctx, ast) { function genDeclareSignal(ctx, ast) {
const v = ctx.refs[ast.refId];
let sizes;
if (ast.name.selectors.length>0) {
sizes=[];
for (let i=0; i< ast.name.selectors.length; i++) {
const sizeRef = gen(ctx, ast.name.selectors[i]);
const size = ctx.refs[sizeRef];
if (size.sizes[0] != 1) return ctx.throwError(ast, "A selector cannot be an array");
if (size.used) return ctx.throwError(ast, "Signal size variables not allowed");
sizes.push(Scalar.toNumber(size.value[0]));
}
sizes = utils.accSizes(sizes);
} else {
sizes = [1,0];
}
if ((!v.sizes)&&(sizes)) {
v.sizes = sizes;
}
if (v.sizes) {
if (!utils.sameSizes(v.sizes, sizes)) return ctx.throwError(ast, "Redefined a signal with different sized");
}
return ast.refId; return ast.refId;
} }
@ -414,12 +440,13 @@ function genVariable(ctx, ast) {
vOffset = genGetSignalOffset(ctx, -1, ast.name); vOffset = genGetSignalOffset(ctx, -1, ast.name);
} }
const resRef = newRef(ctx, "BIGINT", "_sigValue");
const sizes = v.sizes.slice(l);
const resRef = newRef(ctx, "BIGINT", "_sigValue", null, sizes);
const res = ctx.refs[resRef]; const res = ctx.refs[resRef];
instantiateRef(ctx, resRef); instantiateRef(ctx, resRef);
ctx.codeBuilder.getSignal(res.label, ["CC"], toRefA_Int1(ctx, ast, vOffset));
ctx.codeBuilder.getSignal(res.label, ["CC"], toRefA_Int1(ctx, ast, vOffset), sizes[0]);
return resRef; return resRef;
} else if (v.type == "BIGINT") { } else if (v.type == "BIGINT") {
const refOffset = genGetOffset(ctx, 0, v.sizes, ast.selectors ); const refOffset = genGetOffset(ctx, 0, v.sizes, ast.selectors );
const offset = ctx.refs[refOffset]; const offset = ctx.refs[refOffset];
@ -486,13 +513,18 @@ function genPin(ctx, ast) {
vsIdx = genGetSignalOffset(ctx, vcIdx, ast.pin.name); vsIdx = genGetSignalOffset(ctx, vcIdx, ast.pin.name);
} }
const resRef = newRef(ctx, "BIGINT", "_sigValue");
const l = ast.selectors ? ast.selectors.length : 0;
const sizes = [1,0]; // TODO, Treat array
const resRef = newRef(ctx, "BIGINT", "_sigValue", null, sizes);
const res = ctx.refs[resRef]; const res = ctx.refs[resRef];
instantiateRef(ctx, resRef); instantiateRef(ctx, resRef);
ctx.codeBuilder.getSignal( ctx.codeBuilder.getSignal(
res.label, res.label,
toRefA_Int1(ctx, ast.component, vcIdx), toRefA_Int1(ctx, ast.component, vcIdx),
toRefA_Int1(ctx, ast.pin, vsIdx)
toRefA_Int1(ctx, ast.pin, vsIdx),
sizes[0]
); );
return resRef; return resRef;
} }
@ -951,7 +983,7 @@ function genLoop(ctx, ast) {
if (ctx.error) return; if (ctx.error) return;
const cond = ctx.refs[condRef]; const cond = ctx.refs[condRef];
if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "Operation cannot be done on an array");
if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "genLoop: Operation cannot be done on an array");
if (cond.used) { if (cond.used) {
inLoop = true; inLoop = true;
@ -1028,7 +1060,7 @@ function genIf(ctx, ast) {
const condRef = gen(ctx, ast.condition); const condRef = gen(ctx, ast.condition);
if (ctx.error) return; if (ctx.error) return;
const cond = ctx.refs[condRef]; const cond = ctx.refs[condRef];
if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "Operation cannot be done on an array");
if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "genIf: Operation cannot be done on an array");
if (cond.used) { if (cond.used) {
let thenCode, elseCode; let thenCode, elseCode;
@ -1148,7 +1180,12 @@ function genOp(ctx, ast, op, nOps, adjustBool) {
valRefs.push(ref); valRefs.push(ref);
vals.push(v); vals.push(v);
if (!utils.sameSizes(v.sizes, [1,0])) return ctx.throwError(ast, "Operation cannot be done on an array");
if (!utils.sameSizes(v.sizes, [1,0])) {
console.log("xx");
console.log(i);
console.log(v);
return ctx.throwError(ast, "genOp2: Operation cannot be done on an array");
}
if ( (!v.used) if ( (!v.used)
&&( (!utils.isDefined(v.value)) &&( (!utils.isDefined(v.value))
||(!utils.isDefined(v.value[0])))) ||(!utils.isDefined(v.value[0]))))
@ -1184,7 +1221,7 @@ function genTerCon(ctx, ast) {
const condRef = gen(ctx, ast.values[0]); const condRef = gen(ctx, ast.values[0]);
if (ctx.error) return; if (ctx.error) return;
const cond = ctx.refs[condRef]; const cond = ctx.refs[condRef];
if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "Operation cannot be done on an array");
if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "genTer: Operation cannot be done on an array");
if (cond.used) { if (cond.used) {
let thenCode, elseCode; let thenCode, elseCode;

+ 1
- 1
test/basiccases.js

@ -46,7 +46,7 @@ async function doTest(tester, circuit, testVectors) {
describe("basic cases", function () { describe("basic cases", function () {
this.timeout(100000); this.timeout(100000);
for (let i=0; i<basicCases.length; i++) {
for (let i=0; i< basicCases.length; i++) {
it("c/c++ " + basicCases[i].name, async () => { it("c/c++ " + basicCases[i].name, async () => {
await doTest(c_tester, basicCases[i].circuit, basicCases[i].tv); await doTest(c_tester, basicCases[i].circuit, basicCases[i].tv);
}); });

+ 11
- 0
test/basiccases.json

@ -14,6 +14,17 @@
}] }]
] ]
}, },
{
"name": "fnarray",
"circuit": "fnarray.circom",
"tv": [
[{
"in": [1, 8, 25]
}, {
"out": [2, 16, 50]
}]
]
},
{ {
"name": "add", "name": "add",
"circuit": "add.circom", "circuit": "add.circom",

+ 21
- 0
test/circuits/fnarray.circom

@ -0,0 +1,21 @@
function calc(h) {
var res[3];
for (var i=0; i<3; i++) res[i] = h[i]*2;
return res;
}
template Test() {
signal input in[3];
signal output out[3];
var cout[3] = calc(in);
for (var i=0; i<3; i++) out[i] <-- cout[i];
for (var i=0; i<3; i++) out[i] === in[i]*2;
}
component main = Test();

Loading…
Cancel
Save