Compare commits

...

8 Commits

Author SHA1 Message Date
Jordi Baylina
0d5077106a 0.5.34 2020-12-07 12:20:56 +01:00
Jordi Baylina
b68c9fa5d2 NPublic in code 2020-12-07 12:20:50 +01:00
Jordi Baylina
94cb37bd9e 0.5.33 2020-11-26 07:23:06 +01:00
Jordi Baylina
9f15dd2e29 Allows pass signal arrays to a function 2020-11-26 07:22:59 +01:00
Jordi Baylina
334697dd0c 0.5.32 2020-11-21 23:02:06 +01:00
Jordi Baylina
6c48e9ba01 FIX discard unused signals 2020-11-21 23:01:57 +01:00
Jordi Baylina
42162b10c1 0.5.31 2020-11-21 20:40:27 +01:00
Jordi Baylina
a84873161f FIX discard unused signals 2020-11-21 20:40:11 +01:00
12 changed files with 198 additions and 52 deletions

8
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "circom",
"version": "0.5.30",
"version": "0.5.34",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -208,9 +208,9 @@
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII="
},
"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.9",
"resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.1.9.tgz",
"integrity": "sha512-eh34quaGpeEWXthnhmC9zpoBL/5zJ0mGDbPT/plb/xVmFaKxJDcLuCr2sma5s3il8AYlEIb/nbqytojyI3TWDQ==",
"requires": {
"ffjavascript": "0.2.10",
"fnv-plus": "^1.3.1"

View File

@@ -1,6 +1,6 @@
{
"name": "circom",
"version": "0.5.30",
"version": "0.5.34",
"description": "Language to generate logic circuits",
"main": "index.js",
"directories": {
@@ -30,7 +30,7 @@
},
"dependencies": {
"chai": "^4.2.0",
"circom_runtime": "0.1.5",
"circom_runtime": "0.1.9",
"fastfile": "0.0.18",
"ffiasm": "0.1.1",
"ffjavascript": "0.2.22",

View File

@@ -59,8 +59,9 @@ class CodeBuilderC {
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) {
@@ -181,7 +182,7 @@ class CodeBuilderC {
} else if (o.op == "SETSIGNAL") {
code.push(`ctx->setSignal(__cIdx, ${ref2src(o.component)}, ${ref2src(o.signal)}, ${ref2src(o.value)});`);
} 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") {
const oS = ref2src(o.offset);
const dLabel = (oS != "0") ? (o.dLabel + "+" + oS) : o.dLabel;
@@ -432,6 +433,7 @@ class BuilderC {
`#define NOutputs ${this.header.NOutputs}`,
`#define NInputs ${this.header.NInputs}`,
`#define NVars ${this.header.NVars}`,
`#define NPublic ${this.header.NPublic}`,
`#define __P__ "${this.header.P.toString()}"`,
""
);
@@ -661,7 +663,7 @@ class BuilderC {
async _buildCircuitVar(fdData) {
const buff = new Uint8Array(72);
const buff = new Uint8Array(76);
const buffV = new DataView(buff.buffer);
utils.setUint64(buffV, 0, this.pWit2Sig, true);
@@ -677,6 +679,7 @@ class BuilderC {
buffV.setUint32(60, this.header.NInputs, true);
buffV.setUint32(64, this.header.NVars, true);
buffV.setUint32(68, this.nCets, true);
buffV.setUint32(72, this.header.NPublic, true);
fdData.pos = 0;
@@ -696,7 +699,7 @@ class BuilderC {
async build(fdCode, fdData) {
const encoder = new TextEncoder("utf-8");
fdData.pos = 72;
fdData.pos = 76;
while (fdData.pos % 8) fdData.pos++;
const code=new BigArray();

View File

@@ -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() {
const f = module.addFunction("setSignal");
@@ -657,6 +693,15 @@ module.exports = function buildRuntime(module, builder) {
f.addCode(c.i32_const(builder.header.NVars));
}
function buildGetNPublic() {
const f = module.addFunction("getNPublic");
f.setReturnType("i32");
const c = f.getCodeBuilder();
f.addCode(c.i32_const(builder.header.NPublic));
}
function buildGetFrLen() {
const f = module.addFunction("getFrLen");
f.setReturnType("i32");
@@ -847,6 +892,7 @@ module.exports = function buildRuntime(module, builder) {
buildGetSignal();
buildSetSignal();
buildMultiGetSignal();
buildComponentStarted();
buildComponentFinished();
@@ -855,6 +901,7 @@ module.exports = function buildRuntime(module, builder) {
buildCheckAssert();
buildGetNVars();
buildGetNPublic();
buildGetFrLen();
buildGetPWitness();
buildGetPRawPrime();
@@ -864,9 +911,11 @@ module.exports = function buildRuntime(module, builder) {
module.exportFunction("init");
module.exportFunction("getNVars");
module.exportFunction("getNPublic");
module.exportFunction("getFrLen");
module.exportFunction("getSignalOffset32");
module.exportFunction("setSignal");
module.exportFunction("multiGetSignal");
module.exportFunction("getPWitness");
module.exportFunction("Fr_toInt");
module.exportFunction("getPRawPrime");

View File

@@ -62,8 +62,9 @@ class CodeBuilderWasm {
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) {
@@ -251,11 +252,12 @@ class CodeBuilderWasm {
} else if (o.op == "GETSIGNAL") {
code.push(
c.call(
"getSignal",
"multiGetSignal",
c.getLocal("cIdx"),
this.fnBuilder._getPtr(c, o.dLabel),
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") {
@@ -779,20 +781,21 @@ class BuilderWasm {
_buildHeader(module) {
this.pCircuit = module.alloc(48);
this.pCircuit = module.alloc(52);
this.pNSignals = this.pCircuit;
this.pNComponents = this.pCircuit + 4;
this.pNInputs = this.pCircuit + 8;
this.pNOutputs = this.pCircuit + 12;
this.pNVars = this.pCircuit + 16;
this.ppWit2sig = this.pCircuit + 20;
this.ppComponents = this.pCircuit + 24;
this.ppMapIsInput = this.pCircuit + 28;
this.ppConstants = this.pCircuit + 32;
this.ppSignals = this.pCircuit + 36;
this.ppInputSignalsToTrigger = this.pCircuit + 40;
this.ppSignalsAssigned = this.pCircuit + 44;
this.pNPublic = this.pCircuit + 20;
this.ppWit2sig = this.pCircuit + 24;
this.ppComponents = this.pCircuit + 28;
this.ppMapIsInput = this.pCircuit + 32;
this.ppConstants = this.pCircuit + 36;
this.ppSignals = this.pCircuit + 40;
this.ppInputSignalsToTrigger = this.pCircuit + 44;
this.ppSignalsAssigned = this.pCircuit + 48;
}
_buildSizes(module) {
@@ -983,6 +986,7 @@ class BuilderWasm {
module.addData(this.pNInputs, intToBytes32(this.header.NInputs));
module.addData(this.pNOutputs, intToBytes32(this.header.NOutputs));
module.addData(this.pNVars, intToBytes32(this.header.NVars));
module.addData(this.pNPublic, intToBytes32(this.header.NPublic));
module.addData(this.ppWit2sig, intToBytes32(this.pWit2sig));
module.addData(this.ppComponents, intToBytes32(this.pComponents));
module.addData(this.ppMapIsInput, intToBytes32(this.pMapIsInput));

View File

@@ -196,6 +196,7 @@ function buildHeader(ctx) {
NInputs: ctx.components[ ctx.getComponentIdx("main") ].nInSignals,
NOutputs: ctx.totals[ ctx.stOUTPUT ],
NVars: ctx.totals[ctx.stONE] + ctx.totals[ctx.stOUTPUT] + ctx.totals[ctx.stPUBINPUT] + ctx.totals[ctx.stPRVINPUT] + ctx.totals[ctx.stINTERNAL],
NPublic: ctx.totals[ctx.stOUTPUT] + ctx.totals[ctx.stPUBINPUT],
P: ctx.F.p
});
}

View File

@@ -81,10 +81,6 @@ async function compile(srcFile, options) {
throw new Error("A main component must be defined");
}
if (ctx.verbose) console.log("Classify Signals");
measures.classifySignals = -performance.now();
classifySignals(ctx);
measures.classifySignals += performance.now();
if (ctx.verbose) console.log("Reduce Constants");
measures.reduceConstants = -performance.now();
@@ -108,9 +104,13 @@ async function compile(srcFile, options) {
measures.reduceConstraints += performance.now();
}
if (ctx.verbose) console.log("NConstraints After: "+ctx.constraints.length);
if (ctx.verbose) console.log("Classify Signals");
measures.classifySignals = -performance.now();
classifySignals(ctx);
measures.classifySignals += performance.now();
measures.generateWitnessNames = -performance.now();
generateWitnessNames(ctx);
measures.generateWitnessNames += performance.now();
@@ -183,28 +183,36 @@ function classifySignals(ctx) {
function priorize(t1, t2) {
if ((t1 == ERROR) || (t2==ERROR)) return ERROR;
if (t1 == ctx.stINTERNAL) {
return t2;
} else if (t2==ctx.stINTERNAL) {
return t1;
}
if ((t1 == ctx.stONE) || (t2 == ctx.stONE)) return ctx.stONE;
if ((t1 == ctx.stOUTPUT) || (t2 == ctx.stOUTPUT)) return ctx.stOUTPUT;
if ((t1 == ctx.stPUBINPUT) || (t2 == ctx.stPUBINPUT)) return ctx.stPUBINPUT;
if ((t1 == ctx.stPRVINPUT) || (t2 == ctx.stPRVINPUT)) return ctx.stPRVINPUT;
if ((t1 == ctx.stINTERNAL) || (t2 == ctx.stINTERNAL)) return ctx.stINTERNAL;
if ((t1 == ctx.stCONSTANT) || (t2 == ctx.stCONSTANT)) return ctx.stCONSTANT;
if ((t1 == ctx.stDISCARDED) || (t2 == ctx.stDISCARDED)) return ctx.stDISCARDED;
if (t1!=t2) return ERROR;
return t1;
}
for (let i=0; i<ctx.constraints.length; i++) {
if ((ctx.verbose)&&(i%100000 == 0)) console.log(`marking as internal: ${i}/${ctx.constraints.length}`);
const c = ctx.constraints[i];
for (let s in c.a.coefs) ctx.signals[s].c = ctx.stINTERNAL;
for (let s in c.b.coefs) ctx.signals[s].c = ctx.stINTERNAL;
for (let s in c.c.coefs) ctx.signals[s].c = ctx.stINTERNAL;
}
// First classify the signals
for (let s=0; s<ctx.signals.length; s++) {
if ((ctx.verbose)&&(s%100000 == 0)) console.log(`classify signals: ${s}/${ctx.signals.length}`);
const signal = ctx.signals[s];
let tAll = ctx.stINTERNAL;
let tAll = ctx.stDISCARDED;
let lSignal = signal;
let end = false;
while (!end) {
let t = lSignal.c || ctx.stINTERNAL;
let t = lSignal.c || ctx.stDISCARDED;
if (s == 0) {
t = ctx.stONE;
} else if (lSignal.o & ctx.MAIN) {
@@ -454,7 +462,6 @@ async function reduceConstrains(ctx) {
}
sig2constraint[s] = null;
lSignal.c = ctx.stDISCARDED;
}
/*
@@ -488,7 +495,12 @@ async function reduceConstrains(ctx) {
for (let k in l.coefs) {
k = Number(k);
const signal = ctx.signals[k];
if ((signal.c == ctx.stINTERNAL)&&(!ctx.F.isZero(l.coefs[k])) &&(!removedSignals[k])) return k;
if ( ( ((signal.o & ctx.MAIN) == 0)
||( ((signal.o & ctx.IN) == 0)
&&((signal.o & ctx.OUT) == 0)))
&&((signal.o & ctx.ONE) ==0)
&&(!ctx.F.isZero(l.coefs[k]))
&&(!removedSignals[k])) return k;
}
return null;
}

View File

@@ -428,10 +428,17 @@ function execAssignement(ctx, ast) {
}
// Skip if an out is assigned directly to an input.
if ((!isIn)||(!isOut)) {
sDest.e = sIdx;
} else {
if (utils.isDefined(sSrc.v)) sDest.v = sSrc.v;
if (!(isIn&&isOut)) {
if (isIn) {
sDest.e = sIdx;
} else if (isOut) {
sSrc.e = dIdx;
} else {
sDest.e = sIdx;
}
if (!isOut) {
if (utils.isDefined(sSrc.v)) sDest.v = sSrc.v;
}
}
}
}
@@ -881,7 +888,8 @@ function execOpOp(ctx, ast, op, lr) {
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);
left.v[o] = resAfter;

View File

@@ -284,6 +284,32 @@ function genDeclareComponent(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;
}
@@ -414,12 +440,13 @@ function genVariable(ctx, ast) {
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];
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;
} else if (v.type == "BIGINT") {
const refOffset = genGetOffset(ctx, 0, v.sizes, ast.selectors );
const offset = ctx.refs[refOffset];
@@ -486,13 +513,18 @@ function genPin(ctx, ast) {
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];
instantiateRef(ctx, resRef);
ctx.codeBuilder.getSignal(
res.label,
toRefA_Int1(ctx, ast.component, vcIdx),
toRefA_Int1(ctx, ast.pin, vsIdx)
toRefA_Int1(ctx, ast.pin, vsIdx),
sizes[0]
);
return resRef;
}
@@ -951,7 +983,7 @@ function genLoop(ctx, ast) {
if (ctx.error) return;
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) {
inLoop = true;
@@ -1028,7 +1060,7 @@ function genIf(ctx, ast) {
const condRef = gen(ctx, ast.condition);
if (ctx.error) return;
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) {
let thenCode, elseCode;
@@ -1148,7 +1180,12 @@ function genOp(ctx, ast, op, nOps, adjustBool) {
valRefs.push(ref);
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)
&&( (!utils.isDefined(v.value))
||(!utils.isDefined(v.value[0]))))
@@ -1184,7 +1221,7 @@ function genTerCon(ctx, ast) {
const condRef = gen(ctx, ast.values[0]);
if (ctx.error) return;
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) {
let thenCode, elseCode;

View File

@@ -46,7 +46,7 @@ async function doTest(tester, circuit, testVectors) {
describe("basic cases", function () {
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 () => {
await doTest(c_tester, basicCases[i].circuit, basicCases[i].tv);
});

View File

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

View File

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