Compare commits

...

7 Commits

Author SHA1 Message Date
Jordi Baylina
6985892f86 0.0.34 2019-09-18 17:43:39 +02:00
Jordi Baylina
bacb7afde7 Merge branch 'master' of github.com:iden3/circom 2019-09-18 17:43:26 +02:00
Jordi Baylina
d04eff6c0d Optimize optimization and fix out<==in 2019-09-18 17:43:14 +02:00
Jordi Baylina
230894921e Merge pull request #41 from k06a/fix/error-message
Fix error message, for most IDEs recognises as URI to file row and column
2019-09-16 22:10:12 +02:00
Anton Bukov
64029e1842 Fix error message, for most IDEs recognises as URI to file row and column 2019-09-15 22:57:18 +03:00
Jordi Baylina
700412f23d 0.0.33 2019-09-15 18:55:40 +02:00
Jordi Baylina
832077fbe9 Fix Optimization 2019-09-15 18:55:28 +02:00
8 changed files with 237 additions and 56 deletions

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "circom", "name": "circom",
"version": "0.0.32", "version": "0.0.34",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "circom", "name": "circom",
"version": "0.0.32", "version": "0.0.34",
"description": "Language to generate logic circuits", "description": "Language to generate logic circuits",
"main": "index.js", "main": "index.js",
"directories": { "directories": {

View File

@@ -226,8 +226,12 @@ function reduceConstants(ctx) {
} }
function reduceConstrains(ctx) { function reduceConstrains(ctx) {
const newConstraints = []; indexVariables();
for (let i=0; i<ctx.constraints.length; i++) { let possibleConstraints = Object.keys(ctx.constraints);
while (possibleConstraints.length>0) {
let nextPossibleConstraints = {};
for (let i in possibleConstraints) {
if (!ctx.constraints[i]) continue;
const c = ctx.constraints[i]; const c = ctx.constraints[i];
// Swap a and b if b has more variables. // Swap a and b if b has more variables.
@@ -254,6 +258,13 @@ function reduceConstrains(ctx) {
if (lc.isZero(c.a) || lc.isZero(c.b)) { if (lc.isZero(c.a) || lc.isZero(c.b)) {
const isolatedSignal = getFirstInternalSignal(ctx, c.c); const isolatedSignal = getFirstInternalSignal(ctx, c.c);
if (isolatedSignal) { if (isolatedSignal) {
let lSignal = ctx.signals[isolatedSignal];
while (lSignal.equivalence) {
lSignal = ctx.signals[lSignal.equivalence];
}
const isolatedSignalEquivalence = { const isolatedSignalEquivalence = {
type: "LINEARCOMBINATION", type: "LINEARCOMBINATION",
values: {} values: {}
@@ -268,24 +279,81 @@ function reduceConstrains(ctx) {
} }
} }
for (let j=0; j<newConstraints.length; j++) { for (let j in lSignal.inConstraints) {
newConstraints[j] = lc.substitute(newConstraints[j], isolatedSignal, isolatedSignalEquivalence); if ((j!=i)&&(ctx.constraints[j])) {
}
for (let j=i+1; j<ctx.constraints.length; j++ ) {
ctx.constraints[j] = lc.substitute(ctx.constraints[j], isolatedSignal, isolatedSignalEquivalence); ctx.constraints[j] = lc.substitute(ctx.constraints[j], isolatedSignal, isolatedSignalEquivalence);
linkSignalsConstraint(j);
if (j<i) {
nextPossibleConstraints[j] = true;
} }
c.a={ type: "LINEARCOMBINATION", values: {} };
c.b={ type: "LINEARCOMBINATION", values: {} };
c.c={ type: "LINEARCOMBINATION", values: {} };
isolatedSignal.category = "constant";
} }
} }
if (!lc.isZero(c)) { ctx.constraints[i] = null;
newConstraints.push(c);
lSignal.category = "constant";
} else {
if (lc.isZero(c.c)) ctx.constraints[i] = null;
} }
} }
ctx.constraints = newConstraints; }
possibleConstraints = Object.keys(nextPossibleConstraints);
}
unindexVariables();
// Pack the constraints
let o = 0;
for (let i=0; i<ctx.constraints.length; i++) {
if (ctx.constraints[i]) {
if (o != i) {
ctx.constraints[o] = ctx.constraints[i];
}
o++;
}
}
ctx.constraints.length = o;
function indexVariables() {
for (let i=0; i<ctx.constraints.length; i++) linkSignalsConstraint(i);
}
function linkSignalsConstraint(cidx) {
const ct = ctx.constraints[cidx];
for (let k in ct.a.values) linkSignal(k, cidx);
for (let k in ct.b.values) linkSignal(k, cidx);
for (let k in ct.c.values) linkSignal(k, cidx);
}
function unindexVariables() {
for (let s in ctx.signals) {
let lSignal = ctx.signals[s];
while (lSignal.equivalence) {
lSignal = ctx.signals[lSignal.equivalence];
}
if (lSignal.inConstraints) delete lSignal.inConstraints;
}
}
/*
function unlinkSignal(signalName, cidx) {
let lSignal = ctx.signals[signalName];
while (lSignal.equivalence) {
lSignal = ctx.signals[lSignal.equivalence];
}
if ((lSignal.inConstraints)&&(lSignal.inConstraints[cidx])) {
delete lSignal.inConstraints[cidx];
}
}
*/
function linkSignal(signalName, cidx) {
let lSignal = ctx.signals[signalName];
while (lSignal.equivalence) {
lSignal = ctx.signals[lSignal.equivalence];
}
if (!lSignal.inConstraints) lSignal.inConstraints = {};
lSignal.inConstraints[cidx] = true;
}
function getFirstInternalSignal(ctx, l) { function getFirstInternalSignal(ctx, l) {
for (let k in l.values) { for (let k in l.values) {

View File

@@ -996,7 +996,12 @@ function execSignalAssign(ctx, ast) {
let sDest=ctx.signals[dst.fullName]; let sDest=ctx.signals[dst.fullName];
if (!sDest) return error(ctx, ast, "Invalid signal: "+dst.fullName); if (!sDest) return error(ctx, ast, "Invalid signal: "+dst.fullName);
while (sDest.equivalence) sDest=ctx.signals[sDest.equivalence];
let isOut = (sDest.component == "main")&&(sDest.direction=="OUT");
while (sDest.equivalence) {
sDest=ctx.signals[sDest.equivalence];
isOut = isOut || ((sDest.component == "main")&&(sDest.direction=="OUT"));
}
if (sDest.value) return error(ctx, ast, "Signals cannot be assigned twice"); if (sDest.value) return error(ctx, ast, "Signals cannot be assigned twice");
@@ -1024,11 +1029,21 @@ function execSignalAssign(ctx, ast) {
let assignValue = true; let assignValue = true;
if (src.type == "SIGNAL") { if (src.type == "SIGNAL") {
let sSrc = ctx.signals[src.fullName];
let isIn = (sSrc.component == "main")&&(sSrc.direction == "IN");
while (sSrc.equivalence) {
sSrc=ctx.signals[sSrc.equivalence];
isIn = isIn || ((sSrc.component == "main")&&(sSrc.direction == "IN"));
}
// Skip if an out is assigned directly to an input.
if ((!isIn)||(!isOut)) {
sDest.equivalence = src.fullName; sDest.equivalence = src.fullName;
sDest.alias = sDest.alias.concat(src.alias); sDest.alias = sDest.alias.concat(src.alias);
while (sDest.equivalence) sDest=ctx.signals[sDest.equivalence]; while (sDest.equivalence) sDest=ctx.signals[sDest.equivalence];
assignValue = false; assignValue = false;
} }
}
if (assignValue) { if (assignValue) {
// const resLC = exec(ctx, vSrc); // const resLC = exec(ctx, vSrc);

View File

@@ -422,7 +422,7 @@ function genConstrain(ctx, ast) {
if (ctx.error) return; if (ctx.error) return;
const b = gen(ctx, ast.values[1]); const b = gen(ctx, ast.values[1]);
if (ctx.error) return; if (ctx.error) return;
const strErr = ast.fileName +": "+ast.first_line; const strErr = ast.fileName + ":" + ast.first_line + ":" + ast.first_column;
return `ctx.assert(${a}, ${b}, \"${strErr}\")`; return `ctx.assert(${a}, ${b}, \"${strErr}\")`;
} }

View File

@@ -59,4 +59,9 @@ describe("Sum test", () => {
assert(witness[1].equals(bigInt(37))); assert(witness[1].equals(bigInt(37)));
assert(witness[2].equals(bigInt(6))); assert(witness[2].equals(bigInt(6)));
}); });
it("Should compile a code with compute", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "inout.circom"));
assert.equal(cirDef.constraints.length, 1);
});
}); });

View File

@@ -0,0 +1,75 @@
{
"mainCode": "{\n}\n",
"signalName2Idx": {
"one": 0,
"main.in": 2,
"main.out": 1,
"main.internal.in": 2,
"main.internal.out": 2
},
"components": [
{
"name": "main",
"params": {},
"template": "InOut",
"inputSignals": 1
},
{
"name": "main.internal",
"params": {},
"template": "Internal",
"inputSignals": 1
}
],
"componentName2Idx": {
"main": 0,
"main.internal": 1
},
"signals": [
{
"names": [
"one"
],
"triggerComponents": []
},
{
"names": [
"main.out"
],
"triggerComponents": []
},
{
"names": [
"main.in",
"main.internal.in",
"main.internal.out"
],
"triggerComponents": [
0,
1
]
}
],
"constraints": [
[
{},
{},
{
"1": "21888242871839275222246405745257275088548364400416034343698204186575808495616",
"2": "1"
}
]
],
"templates": {
"Internal": "function(ctx) {\n ctx.setSignal(\"out\", [], ctx.getSignal(\"in\", []));\n}\n",
"InOut": "function(ctx) {\n ctx.setPin(\"internal\", [], \"in\", [], ctx.getSignal(\"in\", []));\n ctx.setSignal(\"out\", [], ctx.getPin(\"internal\", [], \"out\", []));\n}\n"
},
"functions": {},
"nPrvInputs": 0,
"nPubInputs": 1,
"nInputs": 1,
"nOutputs": 1,
"nVars": 3,
"nConstants": 0,
"nSignals": 3
}

View File

@@ -0,0 +1,18 @@
template Internal() {
signal input in;
signal output out;
out <== in;
}
template InOut() {
signal input in;
signal output out;
component internal = Internal();
internal.in <== in;
internal.out ==> out;
}
component main = InOut();