Browse Source

optimize optimize constraints

master
Jordi Baylina 4 years ago
parent
commit
9fe8be9828
No known key found for this signature in database GPG Key ID: 7480C80C1BE43112
5 changed files with 265 additions and 34 deletions
  1. +33
    -27
      package-lock.json
  2. +3
    -3
      package.json
  3. +3
    -3
      src/bigarray.js
  4. +225
    -0
      src/compiler.js
  5. +1
    -1
      src/r1csfile.js

+ 33
- 27
package-lock.json

@ -143,6 +143,11 @@
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz",
"integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==" "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w=="
}, },
"blakejs": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.1.0.tgz",
"integrity": "sha1-ad+S75U6qIylGjLfarHFShVfx6U="
},
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -571,9 +576,9 @@
"dev": true "dev": true
}, },
"fastfile": { "fastfile": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/fastfile/-/fastfile-0.0.2.tgz",
"integrity": "sha512-rS9vpAM4DS+xacKSH0MVCqr/Y5SiIAiunJTYSuq1H9nfRpkP37ewgnjH3FztziKBUQB2xPYS/WxEEjHl+pA5Fg=="
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/fastfile/-/fastfile-0.0.7.tgz",
"integrity": "sha512-Zk7sdqsV6DsN/rhjULDfCCowPiMDsziTMFicdkrKN80yybr/6YFf9H91ELXN85dVEf6EYkVR5EHkZNc0dMqZKA=="
}, },
"ffiasm": { "ffiasm": {
"version": "0.0.2", "version": "0.0.2",
@ -586,11 +591,13 @@
} }
}, },
"ffjavascript": { "ffjavascript": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.1.2.tgz",
"integrity": "sha512-zB1dhgBjJlvyk2VQIQzFSpUJmanYQYDR/Fo1KhZnaNW5chMFJT55qz0dx1LMKrAklBbidKzz2/C7dgibxQF94g==",
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.4.tgz",
"integrity": "sha512-XFeWcjUDFPavN+DDOxhE8p5MOhZQJc9oO1Sj4ml1pyjqNhS1ujEamcjFyK0cctdnat61i7lvpTYzdtS3RYDC8w==",
"requires": { "requires": {
"big-integer": "^1.6.48"
"big-integer": "^1.6.48",
"wasmcurves": "0.0.4",
"worker-threads": "^1.0.0"
} }
}, },
"ffwasm": { "ffwasm": {
@ -1154,27 +1161,12 @@
"dev": true "dev": true
}, },
"r1csfile": { "r1csfile": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/r1csfile/-/r1csfile-0.0.5.tgz",
"integrity": "sha512-B+BdKPb/WUTp4N/3X4d1Spgx9Ojx5tFVejGZRJxpTtzq34mC8Vi/czWfiPj85V8kud31lCfYcZ16z7+czvM0Sw==",
"version": "0.0.14",
"resolved": "https://registry.npmjs.org/r1csfile/-/r1csfile-0.0.14.tgz",
"integrity": "sha512-7m4eWpnbjkwGGUaRmIAJc4w+HvaeBPJXUKHIqLkHeD9Yyjem6/EHmlgDVl+4hWNWGZqdhXuMqWSH9+O6QOXBdw==",
"requires": { "requires": {
"fastfile": "0.0.1",
"ffjavascript": "0.1.0"
},
"dependencies": {
"fastfile": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/fastfile/-/fastfile-0.0.1.tgz",
"integrity": "sha512-Fk8PWafGWGEUw7oPq/dJen92ASxknCEy4ZC8n4VEvSwCp/jcReyEmVoWsRIWTf+IvAp2MzvFi54vOPeK2LQZtQ=="
},
"ffjavascript": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.1.0.tgz",
"integrity": "sha512-dmKlUasSfvUcxBm8nCSKl2x7EFJsXA7OVP8XLFA03T2+6mAc3IiVLC2ambEVOcMOhyhl0vJfVZjM9f9d38D1rw==",
"requires": {
"big-integer": "^1.6.48"
}
}
"fastfile": "0.0.7",
"ffjavascript": "0.2.4"
} }
}, },
"regexpp": { "regexpp": {
@ -1472,6 +1464,15 @@
"big-integer": "^1.6.48" "big-integer": "^1.6.48"
} }
}, },
"wasmcurves": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/wasmcurves/-/wasmcurves-0.0.4.tgz",
"integrity": "sha512-c/Tob+F/7jJhep1b2qtj54r4nkGaRifNbQ1OJx8cBBFH1RlHbWIbISHWONClOxiVwy/JZOpbN4SgvSX/4lF80A==",
"requires": {
"big-integer": "^1.6.42",
"blakejs": "^1.1.0"
}
},
"which": { "which": {
"version": "1.3.1", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
@ -1492,6 +1493,11 @@
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
"dev": true "dev": true
}, },
"worker-threads": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/worker-threads/-/worker-threads-1.0.0.tgz",
"integrity": "sha512-vK6Hhvph8oLxocEJIlc3YfGAZhm210uGzjZsXSu+JYLAQ/s/w4Tqgl60JrdH58hW8NSGP4m3bp8a92qPXgX05w=="
},
"wrap-ansi": { "wrap-ansi": {
"version": "6.2.0", "version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",

+ 3
- 3
package.json

@ -31,12 +31,12 @@
"dependencies": { "dependencies": {
"chai": "^4.2.0", "chai": "^4.2.0",
"circom_runtime": "0.0.6", "circom_runtime": "0.0.6",
"fastfile": "0.0.2",
"fastfile": "0.0.7",
"ffiasm": "0.0.2", "ffiasm": "0.0.2",
"ffjavascript": "0.1.2",
"ffjavascript": "0.2.4",
"ffwasm": "0.0.7", "ffwasm": "0.0.7",
"fnv-plus": "^1.3.1", "fnv-plus": "^1.3.1",
"r1csfile": "0.0.5",
"r1csfile": "0.0.14",
"tmp-promise": "^2.0.2", "tmp-promise": "^2.0.2",
"wasmbuilder": "0.0.10" "wasmbuilder": "0.0.10"
}, },

+ 3
- 3
src/bigarray.js

@ -1,4 +1,4 @@
const SUBARRAY_SIZE = 0x10000;
const SUBARRAY_SIZE = 0x40000;
const BigArrayHandler = { const BigArrayHandler = {
get: function(obj, prop) { get: function(obj, prop) {
@ -19,7 +19,7 @@ const BigArrayHandler = {
class _BigArray { class _BigArray {
constructor (initSize) { constructor (initSize) {
this.length = initSize || 0; this.length = initSize || 0;
this.arr = [];
this.arr = new Array(SUBARRAY_SIZE);
for (let i=0; i<initSize; i+=SUBARRAY_SIZE) { for (let i=0; i<initSize; i+=SUBARRAY_SIZE) {
this.arr[i/SUBARRAY_SIZE] = new Array(Math.min(SUBARRAY_SIZE, initSize - i)); this.arr[i/SUBARRAY_SIZE] = new Array(Math.min(SUBARRAY_SIZE, initSize - i));
@ -39,7 +39,7 @@ class _BigArray {
idx = parseInt(idx); idx = parseInt(idx);
const idx1 = Math.floor(idx / SUBARRAY_SIZE); const idx1 = Math.floor(idx / SUBARRAY_SIZE);
if (!this.arr[idx1]) { if (!this.arr[idx1]) {
this.arr[idx1] = [];
this.arr[idx1] = new Array(SUBARRAY_SIZE);
} }
const idx2 = idx % SUBARRAY_SIZE; const idx2 = idx % SUBARRAY_SIZE;
this.arr[idx1][idx2] = value; this.arr[idx1][idx2] = value;

+ 225
- 0
src/compiler.js

@ -65,12 +65,16 @@ async function compile(srcFile, options) {
if (ctx.verbose) console.log("Reduce Constraints"); if (ctx.verbose) console.log("Reduce Constraints");
// Repeat while reductions are performed // Repeat while reductions are performed
/*
let oldNConstrains = -1; let oldNConstrains = -1;
while (ctx.constraints.length != oldNConstrains) { while (ctx.constraints.length != oldNConstrains) {
if (ctx.verbose) console.log("Reducing constraints: "+ctx.constraints.length); if (ctx.verbose) console.log("Reducing constraints: "+ctx.constraints.length);
oldNConstrains = ctx.constraints.length; oldNConstrains = ctx.constraints.length;
reduceConstrains(ctx); reduceConstrains(ctx);
} }
*/
reduceConstrains(ctx);
} }
if (ctx.verbose) console.log("NConstraints After: "+ctx.constraints.length); if (ctx.verbose) console.log("NConstraints After: "+ctx.constraints.length);
@ -252,6 +256,227 @@ function reduceConstants(ctx) {
} }
function reduceConstrains(ctx) { function reduceConstrains(ctx) {
const sig2constraint = {};
let removedSignals = {};
let nRemoved;
let lIdx;
let possibleConstraints = new Array(ctx.constraints.length);
let nextPossibleConstraints;
for (let i=0; i<ctx.constraints.length; i++) {
const insertedSig = {};
const c = ctx.constraints[i];
for (let s in c.a.coefs) {
if (!insertedSig[s]) {
if (!sig2constraint[s]) sig2constraint[s] = [];
sig2constraint[s].push(i);
insertedSig[s] = true;
}
}
for (let s in c.b.coefs) {
if (!insertedSig[s]) {
if (!sig2constraint[s]) sig2constraint[s] = [];
sig2constraint[s].push(i);
insertedSig[s] = true;
}
}
for (let s in c.c.coefs) {
if (!insertedSig[s]) {
if (!sig2constraint[s]) sig2constraint[s] = [];
sig2constraint[s].push(i);
insertedSig[s] = true;
}
}
possibleConstraints[i] = i;
}
while (possibleConstraints.length >0) {
nextPossibleConstraints = {};
removedSignals = {};
nRemoved = 0;
lIdx = {};
for (let i=0;i<possibleConstraints.length;i++) {
if ((ctx.verbose)&&(i%10000 == 0)) {
console.log(`reducing constraints: ${i}/${possibleConstraints.length} reduced: ${nRemoved}`);
}
const c = ctx.constraints[possibleConstraints[i]];
if (!c) continue;
// Swap a and b if b has more variables.
if (Object.keys(c.b).length > Object.keys(c.a).length) {
const aux = c.a;
c.a=c.b;
c.b=aux;
}
// Mov to C if possible.
if (isConstant(c.a)) {
const ct = {t: "N", v: c.a.coefs[sONE]};
c.c = ctx.lc.add(ctx.lc.mul(c.b, ct), c.c);
c.a = { t: "LC", coefs: {} };
c.b = { t: "LC", coefs: {} };
}
if (isConstant(c.b)) {
const ct = {t: "N", v: c.b.coefs[sONE]};
c.c = ctx.lc.add(ctx.lc.mul(c.a, ct), c.c);
c.a = { t: "LC", coefs: {} };
c.b = { t: "LC", coefs: {} };
}
if (ctx.lc.isZero(c.a) || ctx.lc.isZero(c.b)) {
const freeC = substituteRemoved(c.c);
const isolatedSignal = getFirstInternalSignal(ctx, freeC);
if (isolatedSignal) {
// console.log(isolatedSignal);
// console.log(freeC);
removedSignals[isolatedSignal] = isolateSignal(freeC, isolatedSignal);
if (lIdx[isolatedSignal]) {
lIdx[isolatedSignal].forEach( (s) => {
removedSignals[s] = substitute(removedSignals[s], isolatedSignal, removedSignals[isolatedSignal]);
});
}
addTolIdx(removedSignals[isolatedSignal], isolatedSignal);
ctx.constraints[possibleConstraints[i]] = null;
nRemoved ++;
sig2constraint[isolatedSignal].forEach( (s) => {
nextPossibleConstraints[s] = true;
});
}
}
}
nextPossibleConstraints = Object.keys(nextPossibleConstraints);
for (let i=0; i<nextPossibleConstraints.length;i++) {
const c = ctx.constraints[nextPossibleConstraints[i]];
if (c) {
const nc = {
a: substituteRemoved(c.a),
b: substituteRemoved(c.b),
c: substituteRemoved(c.c)
};
if (ctx.lc.isZero(nc)) {
delete ctx.constraints[nextPossibleConstraints[i]];
} else {
ctx.constraints[nextPossibleConstraints[i]] = nc;
}
}
}
for (let s in removedSignals) {
let lSignal = ctx.signals[s];
while (lSignal.e>=0) {
lSignal = ctx.signals[lSignal.e];
}
lSignal.c = ctx.stDISCARDED;
}
possibleConstraints = nextPossibleConstraints;
}
let o=0;
for (let i=0; i<ctx.constraints.length;i++) {
if (ctx.constraints[i]) {
if (!ctx.lc.isZero(ctx.constraints[i])) {
ctx.constraints[o] = ctx.constraints[i];
o++;
}
}
}
ctx.constraints.length = o;
function getFirstInternalSignal(ctx, l) {
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;
}
return null;
}
function isolateSignal(lc, s) {
const eq = {
t: "LC",
coefs: {}
};
const invCoef = ctx.F.inv(lc.coefs[s]);
for (const k in lc.coefs) {
if (k != s) {
const v = ctx.F.mul( ctx.F.neg(lc.coefs[k]), invCoef);
if (!ctx.F.isZero(v)) {
eq.coefs[k] = v;
}
}
}
return eq;
}
function substituteRemoved(lc) {
const newLc = ctx.lc._clone(lc);
for (let k in lc.coefs) {
if (removedSignals[k]) {
delete newLc.coefs[k];
for (let k2 in removedSignals[k].coefs) {
const newP = ctx.F.mul(removedSignals[k].coefs[k2], lc.coefs[k]);
if (!ctx.F.isZero(newP)) {
if (newLc.coefs[k2]) {
newLc.coefs[k2] = ctx.F.add(newLc.coefs[k2], newP);
if (ctx.F.isZero(newLc.coefs[k2])) delete newLc.coefs[k2];
} else {
newLc.coefs[k2] = newP;
}
}
}
}
}
return newLc;
}
function substitute(lc, s, eq) {
if (!lc.coefs[s]) return lc;
const newLc = ctx.lc._clone(lc);
delete newLc.coefs[s];
for (let k2 in eq.coefs) {
const newP = ctx.F.mul(eq.coefs[k2], lc.coefs[s]);
if (!ctx.F.isZero(newP)) {
if (newLc.coefs[k2]) {
newLc.coefs[k2] = ctx.F.add(newLc.coefs[k2], newP);
if (ctx.F.isZero(newLc.coefs[k2])) delete newLc.coefs[k2];
} else {
newLc.coefs[k2] = newP;
}
}
}
return newLc;
}
function isConstant(l) {
for (let k in l.coefs) {
if ((k != sONE) && (!ctx.F.isZero(l.coefs[k]))) return false;
}
if (!l.coefs[sONE] || ctx.F.isZero(l.coefs[sONE])) return false;
return true;
}
function addTolIdx(lc, newS) {
for (let s in lc.coefs) {
if (!lIdx[s]) lIdx[s] = [];
lIdx[s].push(newS);
}
}
}
function reduceConstrains_old(ctx) {
indexVariables(); indexVariables();
let possibleConstraints = ctx.constraints; let possibleConstraints = ctx.constraints;
let ii=0; let ii=0;

+ 1
- 1
src/r1csfile.js

@ -79,7 +79,7 @@ async function buildR1cs(ctx, fileName) {
} }
for (let i=0; i<arr.length; i++) { for (let i=0; i<arr.length; i++) {
await fd.writeULE64(arr[i]); await fd.writeULE64(arr[i]);
if ((ctx.verbose)&&(i%100000)) console.log("writing wire2label map: ", i);
if ((ctx.verbose)&&(i%100000 == 0)) console.log(`writing wire2label map: ${i}/${arr.length}`);
} }
const mapSize = fd.pos - pMapSize - 8; const mapSize = fd.pos - pMapSize - 8;

Loading…
Cancel
Save