mirror of
https://github.com/arnaucube/circom.git
synced 2026-02-07 03:06:42 +01:00
Optimize optimization and fix out<==in
This commit is contained in:
167
src/compiler.js
167
src/compiler.js
@@ -226,71 +226,134 @@ 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);
|
||||||
const c = ctx.constraints[i];
|
while (possibleConstraints.length>0) {
|
||||||
|
let nextPossibleConstraints = {};
|
||||||
|
for (let i in possibleConstraints) {
|
||||||
|
if (!ctx.constraints[i]) continue;
|
||||||
|
const c = ctx.constraints[i];
|
||||||
|
|
||||||
// Swap a and b if b has more variables.
|
// Swap a and b if b has more variables.
|
||||||
if (Object.keys(c.b).length > Object.keys(c.a).length) {
|
if (Object.keys(c.b).length > Object.keys(c.a).length) {
|
||||||
const aux = c.a;
|
const aux = c.a;
|
||||||
c.a=c.b;
|
c.a=c.b;
|
||||||
c.b=aux;
|
c.b=aux;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mov to C if possible.
|
// Mov to C if possible.
|
||||||
if (isConstant(c.a)) {
|
if (isConstant(c.a)) {
|
||||||
const ct = {type: "NUMBER", value: c.a.values["one"]};
|
const ct = {type: "NUMBER", value: c.a.values["one"]};
|
||||||
c.c = lc.add(lc.mul(c.b, ct), c.c);
|
c.c = lc.add(lc.mul(c.b, ct), c.c);
|
||||||
c.a = { type: "LINEARCOMBINATION", values: {} };
|
c.a = { type: "LINEARCOMBINATION", values: {} };
|
||||||
c.b = { type: "LINEARCOMBINATION", values: {} };
|
c.b = { type: "LINEARCOMBINATION", values: {} };
|
||||||
}
|
}
|
||||||
if (isConstant(c.b)) {
|
if (isConstant(c.b)) {
|
||||||
const ct = {type: "NUMBER", value: c.b.values["one"]};
|
const ct = {type: "NUMBER", value: c.b.values["one"]};
|
||||||
c.c = lc.add(lc.mul(c.a, ct), c.c);
|
c.c = lc.add(lc.mul(c.a, ct), c.c);
|
||||||
c.a = { type: "LINEARCOMBINATION", values: {} };
|
c.a = { type: "LINEARCOMBINATION", values: {} };
|
||||||
c.b = { type: "LINEARCOMBINATION", values: {} };
|
c.b = { type: "LINEARCOMBINATION", values: {} };
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
const isolatedSignalEquivalence = {
|
|
||||||
type: "LINEARCOMBINATION",
|
let lSignal = ctx.signals[isolatedSignal];
|
||||||
values: {}
|
while (lSignal.equivalence) {
|
||||||
};
|
lSignal = ctx.signals[lSignal.equivalence];
|
||||||
const invCoef = c.c.values[isolatedSignal].modInv(__P__);
|
}
|
||||||
for (const s in c.c.values) {
|
|
||||||
if (s != isolatedSignal) {
|
|
||||||
const v = __P__.minus(c.c.values[s]).times(invCoef).mod(__P__);
|
const isolatedSignalEquivalence = {
|
||||||
if (!v.isZero()) {
|
type: "LINEARCOMBINATION",
|
||||||
isolatedSignalEquivalence.values[s] = v;
|
values: {}
|
||||||
|
};
|
||||||
|
const invCoef = c.c.values[isolatedSignal].modInv(__P__);
|
||||||
|
for (const s in c.c.values) {
|
||||||
|
if (s != isolatedSignal) {
|
||||||
|
const v = __P__.minus(c.c.values[s]).times(invCoef).mod(__P__);
|
||||||
|
if (!v.isZero()) {
|
||||||
|
isolatedSignalEquivalence.values[s] = v;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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])) {
|
||||||
}
|
ctx.constraints[j] = lc.substitute(ctx.constraints[j], isolatedSignal, isolatedSignalEquivalence);
|
||||||
for (let j=i+1; j<ctx.constraints.length; j++ ) {
|
linkSignalsConstraint(j);
|
||||||
ctx.constraints[j] = lc.substitute(ctx.constraints[j], isolatedSignal, isolatedSignalEquivalence);
|
if (j<i) {
|
||||||
}
|
nextPossibleConstraints[j] = true;
|
||||||
c.a={ type: "LINEARCOMBINATION", values: {} };
|
}
|
||||||
c.b={ type: "LINEARCOMBINATION", values: {} };
|
}
|
||||||
c.c={ type: "LINEARCOMBINATION", values: {} };
|
}
|
||||||
|
|
||||||
let lSignal = ctx.signals[isolatedSignal];
|
ctx.constraints[i] = null;
|
||||||
while (lSignal.equivalence) {
|
|
||||||
lSignal = ctx.signals[lSignal.equivalence];
|
lSignal.category = "constant";
|
||||||
|
} else {
|
||||||
|
if (lc.isZero(c.c)) ctx.constraints[i] = null;
|
||||||
}
|
}
|
||||||
lSignal.category = "constant";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
possibleConstraints = Object.keys(nextPossibleConstraints);
|
||||||
|
}
|
||||||
|
unindexVariables();
|
||||||
|
|
||||||
if (!lc.isZero(c)) {
|
// Pack the constraints
|
||||||
newConstraints.push(c);
|
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 = newConstraints;
|
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) {
|
||||||
|
|||||||
25
src/exec.js
25
src/exec.js
@@ -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,10 +1029,20 @@ function execSignalAssign(ctx, ast) {
|
|||||||
|
|
||||||
let assignValue = true;
|
let assignValue = true;
|
||||||
if (src.type == "SIGNAL") {
|
if (src.type == "SIGNAL") {
|
||||||
sDest.equivalence = src.fullName;
|
let sSrc = ctx.signals[src.fullName];
|
||||||
sDest.alias = sDest.alias.concat(src.alias);
|
let isIn = (sSrc.component == "main")&&(sSrc.direction == "IN");
|
||||||
while (sDest.equivalence) sDest=ctx.signals[sDest.equivalence];
|
while (sSrc.equivalence) {
|
||||||
assignValue = false;
|
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.alias = sDest.alias.concat(src.alias);
|
||||||
|
while (sDest.equivalence) sDest=ctx.signals[sDest.equivalence];
|
||||||
|
assignValue = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (assignValue) {
|
if (assignValue) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
75
test/circuits/circuit.json
Normal file
75
test/circuits/circuit.json
Normal 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
|
||||||
|
}
|
||||||
18
test/circuits/inout.circom
Normal file
18
test/circuits/inout.circom
Normal 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();
|
||||||
Reference in New Issue
Block a user