Compare commits

...

11 Commits

Author SHA1 Message Date
Jordi Baylina
c39423e411 0.5.17 2020-07-25 14:01:31 +02:00
Jordi Baylina
06b6c1a49e Fast write constraints 2020-07-25 13:55:17 +02:00
Jordi Baylina
6b712f3587 0.5.16 2020-07-23 15:56:47 +02:00
Jordi Baylina
26cad30222 faster write r1cs 2020-07-23 15:55:27 +02:00
Jordi Baylina
f48de61ca9 lIdx BigArray 2020-07-21 14:34:53 +02:00
Jordi Baylina
89cea4755c 0.5.15 2020-07-21 08:47:27 +02:00
Jordi Baylina
9bf6ecc4f3 Reducing constraints big array 2020-07-21 08:47:10 +02:00
Jordi Baylina
59d591c988 0.5.14 2020-07-18 14:55:09 +02:00
Jordi Baylina
9fe8be9828 optimize optimize constraints 2020-07-18 14:55:00 +02:00
Jordi Baylina
7e24d6f57d 0.5.13 2020-07-04 19:55:45 +02:00
Jordi Baylina
8655573b34 r1cs builder fix 2020-07-04 19:54:47 +02:00
6 changed files with 414 additions and 109 deletions

61
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "circom",
"version": "0.5.12",
"version": "0.5.17",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -143,6 +143,11 @@
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz",
"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": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -571,9 +576,9 @@
"dev": true
},
"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.9",
"resolved": "https://registry.npmjs.org/fastfile/-/fastfile-0.0.9.tgz",
"integrity": "sha512-njh6lH2SJiS0u0JofJQf2YfEOSgGfbYPtmFnpEXXy6OilWoX1wGw3klaSKIwhq8+E5MqYpqJXMiaqmptaU2wig=="
},
"ffiasm": {
"version": "0.0.2",
@@ -586,11 +591,13 @@
}
},
"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": {
"big-integer": "^1.6.48"
"big-integer": "^1.6.48",
"wasmcurves": "0.0.4",
"worker-threads": "^1.0.0"
}
},
"ffwasm": {
@@ -1154,26 +1161,18 @@
"dev": true
},
"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": {
"fastfile": "0.0.1",
"ffjavascript": "0.1.0"
"fastfile": "0.0.7",
"ffjavascript": "0.2.4"
},
"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"
}
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/fastfile/-/fastfile-0.0.7.tgz",
"integrity": "sha512-Zk7sdqsV6DsN/rhjULDfCCowPiMDsziTMFicdkrKN80yybr/6YFf9H91ELXN85dVEf6EYkVR5EHkZNc0dMqZKA=="
}
}
},
@@ -1472,6 +1471,15 @@
"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": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
@@ -1492,6 +1500,11 @@
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
"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": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "circom",
"version": "0.5.12",
"version": "0.5.17",
"description": "Language to generate logic circuits",
"main": "index.js",
"directories": {
@@ -31,12 +31,12 @@
"dependencies": {
"chai": "^4.2.0",
"circom_runtime": "0.0.6",
"fastfile": "0.0.2",
"fastfile": "0.0.9",
"ffiasm": "0.0.2",
"ffjavascript": "0.1.2",
"ffjavascript": "0.2.4",
"ffwasm": "0.0.7",
"fnv-plus": "^1.3.1",
"r1csfile": "0.0.5",
"r1csfile": "0.0.14",
"tmp-promise": "^2.0.2",
"wasmbuilder": "0.0.10"
},

View File

@@ -1,4 +1,4 @@
const SUBARRAY_SIZE = 0x10000;
const SUBARRAY_SIZE = 0x40000;
const BigArrayHandler = {
get: function(obj, prop) {
@@ -19,7 +19,7 @@ const BigArrayHandler = {
class _BigArray {
constructor (initSize) {
this.length = initSize || 0;
this.arr = [];
this.arr = new Array(SUBARRAY_SIZE);
for (let i=0; i<initSize; i+=SUBARRAY_SIZE) {
this.arr[i/SUBARRAY_SIZE] = new Array(Math.min(SUBARRAY_SIZE, initSize - i));
@@ -39,13 +39,26 @@ class _BigArray {
idx = parseInt(idx);
const idx1 = Math.floor(idx / SUBARRAY_SIZE);
if (!this.arr[idx1]) {
this.arr[idx1] = [];
this.arr[idx1] = new Array(SUBARRAY_SIZE);
}
const idx2 = idx % SUBARRAY_SIZE;
this.arr[idx1][idx2] = value;
if (idx >= this.length) this.length = idx+1;
return true;
}
getKeys() {
const newA = new BigArray();
for (let i=0; i<this.arr.length; i++) {
if (this.arr[i]) {
for (let j=0; j<this.arr[i].length; j++) {
if (typeof this.arr[i][j] !== "undefined") {
newA.push(i*SUBARRAY_SIZE+j);
}
}
}
}
return newA;
}
}
class BigArray {

View File

@@ -28,8 +28,30 @@ const utils = require("./utils");
const buildR1cs = require("./r1csfile").buildR1cs;
const BigArray = require("./bigarray");
const buildSyms = require("./buildsyms");
const {performance} = require("perf_hooks");
module.exports = compile;
const measures = {};
function ms2String(v) {
v = Math.floor(v);
const ms = v % 1000;
v = Math.floor(v/1000);
const secs = v % 60;
v = Math.floor(v/60);
const mins = v % 60;
v = Math.floor(v/60);
const hours = v % 24;
const days = Math.floor(v/24);
let S = "";
if (days) S = S + days + "D ";
if ((S!="")||(hours)) S = S + hours.toString().padStart(2, "0") + ":";
if ((S!="")||(mins)) S = S + mins.toString().padStart(2, "0") + ":";
if ((S!="")||(secs)) S = S + secs.toString().padStart(2, "0");
S+=".";
S = S + ms.toString().padStart(3, "0");
return S;
}
async function compile(srcFile, options) {
options.prime = options.prime || Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
@@ -44,9 +66,12 @@ async function compile(srcFile, options) {
ctx.mainComponent = options.mainComponent || "main";
ctx.newThreadTemplates = options.newThreadTemplates;
measures.constructionPhase = -performance.now();
constructionPhase(ctx, srcFile);
measures.constructionPhase += performance.now();
if (ctx.verbose) console.log("NConstraints Before: "+ctx.constraints.length);
if (ctx.verbose) console.log("NSignals Before: "+ctx.signals.length);
if (ctx.error) {
throw(ctx.error);
@@ -57,25 +82,38 @@ async function compile(srcFile, options) {
}
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();
reduceConstants(ctx);
measures.reduceConstants += performance.now();
if (options.reduceConstraints) {
if (ctx.verbose) console.log("Reduce Constraints");
// Repeat while reductions are performed
/*
let oldNConstrains = -1;
while (ctx.constraints.length != oldNConstrains) {
if (ctx.verbose) console.log("Reducing constraints: "+ctx.constraints.length);
oldNConstrains = ctx.constraints.length;
reduceConstrains(ctx);
}
*/
measures.reduceConstraints = -performance.now();
await reduceConstrains(ctx);
measures.reduceConstraints += performance.now();
}
if (ctx.verbose) console.log("NConstraints After: "+ctx.constraints.length);
measures.generateWitnessNames = -performance.now();
generateWitnessNames(ctx);
measures.generateWitnessNames += performance.now();
if (ctx.error) {
throw(ctx.error);
@@ -83,16 +121,19 @@ async function compile(srcFile, options) {
if (options.cSourceWriteStream) {
if (ctx.verbose) console.log("Generating c...");
measures.generateC = -performance.now();
ctx.builder = new BuilderC(options.prime);
build(ctx);
const rdStream = ctx.builder.build();
rdStream.pipe(options.cSourceWriteStream);
measures.generateC += performance.now();
// await new Promise(fulfill => options.cSourceWriteStream.on("finish", fulfill));
}
if ((options.wasmWriteStream)||(options.watWriteStream)) {
if (ctx.verbose) console.log("Generating wasm...");
measures.generateWasm = -performance.now();
ctx.builder = new BuilderWasm(options.prime);
build(ctx);
if (options.wasmWriteStream) {
@@ -103,6 +144,7 @@ async function compile(srcFile, options) {
const rdStream = ctx.builder.build("wat");
rdStream.pipe(options.watWriteStream);
}
measures.generateWasm += performance.now();
// await new Promise(fulfill => options.wasmWriteStream.on("finish", fulfill));
}
@@ -111,18 +153,27 @@ async function compile(srcFile, options) {
if (ctx.error) throw(ctx.error);
if (options.r1csFileName) {
measures.generateR1cs = -performance.now();
await buildR1cs(ctx, options.r1csFileName);
measures.generateR1cs += performance.now();
}
if (options.symWriteStream) {
measures.generateSyms = -performance.now();
const rdStream = buildSyms(ctx);
rdStream.pipe(options.symWriteStream);
measures.generateSyms += performance.now();
// await new Promise(fulfill => options.symWriteStream.on("finish", fulfill));
await new Promise(fulfill => options.symWriteStream.on("finish", fulfill));
}
// const def = buildCircuitDef(ctx, mainCode);
if (ctx.verbose) {
for (let [mStr, mValue] of Object.entries(measures)) {
console.log(mStr + ": " + ms2String(mValue));
}
}
}
@@ -148,6 +199,7 @@ function classifySignals(ctx) {
// 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 lSignal = signal;
@@ -251,7 +303,239 @@ function reduceConstants(ctx) {
ctx.constraints = newConstraints;
}
function reduceConstrains(ctx) {
async function reduceConstrains(ctx) {
const sig2constraint = new BigArray();
let removedSignals = new BigArray();
let nRemoved;
let lIdx;
let possibleConstraints = new BigArray(ctx.constraints.length);
let nextPossibleConstraints;
for (let i=0; i<ctx.constraints.length; i++) {
if ((ctx.verbose)&&(i%100000 == 0)) console.log(`indexing constraints: ${i}/${ctx.constraints.length}`);
const insertedSig = { 0: true}; // Do not insert one.
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 = new BigArray();
removedSignals = new BigArray();
nRemoved = 0;
lIdx = new BigArray();
for (let i=0;i<possibleConstraints.length;i++) {
if ((ctx.verbose)&&(i%10000 == 0)) {
await Promise.resolve();
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 = nextPossibleConstraints.getKeys();
for (let i=0; i<nextPossibleConstraints.length;i++) {
if ((ctx.verbose)&&(i%10000 == 0)) {
await Promise.resolve();
console.log(`substituting constraints: ${i}/${nextPossibleConstraints.length}`);
}
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;
}
}
}
const removedSignalsList = removedSignals.getKeys;
for (let i=0; i<removedSignalsList.length; i++) {
if ((ctx.verbose )&&(i%100000 == 0)) console.log(`removing signals: ${i}/${removedSignalsList.length}`);
const s = removedSignalsList[i];
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.verbose)&&(i%100000 == 0)) console.log(`reordering constraints: ${i}/${ctx.constraints.length}`);
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();
let possibleConstraints = ctx.constraints;
let ii=0;

View File

@@ -123,6 +123,7 @@ class LCAlgebra {
}
_signal2lc(a) {
const self = this;
if (a.t == "S") {
const lc = {
t: "LC",

View File

@@ -4,27 +4,32 @@ const assert = require("assert");
module.exports.buildR1cs = buildR1cs;
async function buildR1cs(ctx, fileName) {
const fd = await fastFile.createOverride(fileName);
await fd.write(Buffer.from("r1cs"), 0); // Magic "r1cs"
const buffBigInt = new Uint8Array(ctx.F.n8);
let p = 4;
await writeU32(1); // Version
await writeU32(3); // Number of Sections
const type = "r1cs";
const buff = new Uint8Array(4);
for (let i=0; i<4; i++) buff[i] = type.charCodeAt(i);
await fd.write(buff, 0); // Magic "r1cs"
await fd.writeULE32(1); // Version
await fd.writeULE32(3); // Number of Sections
// Write the header
///////////
await writeU32(1); // Header type
const pHeaderSize = p;
await writeU64(0); // Temporally set to 0 length
await fd.writeULE32(1); // Header type
const pHeaderSize = fd.pos;
await fd.writeULE64(0); // Temporally set to 0 length
const n8 = (Math.floor( (ctx.F.bitLength - 1) / 64) +1)*8;
// Field Def
await writeU32(n8); // Temporally set to 0 length
await fd.writeULE32(n8); // Temporally set to 0 length
await writeBigInt(ctx.F.p);
const NWires =
@@ -34,20 +39,20 @@ async function buildR1cs(ctx, fileName) {
ctx.totals[ctx.stPRVINPUT] +
ctx.totals[ctx.stINTERNAL];
await writeU32(NWires);
await writeU32(ctx.totals[ctx.stOUTPUT]);
await writeU32(ctx.totals[ctx.stPUBINPUT]);
await writeU32(ctx.totals[ctx.stPRVINPUT]);
await writeU64(ctx.signals.length);
await writeU32(ctx.constraints.length);
await fd.writeULE32(NWires);
await fd.writeULE32(ctx.totals[ctx.stOUTPUT]);
await fd.writeULE32(ctx.totals[ctx.stPUBINPUT]);
await fd.writeULE32(ctx.totals[ctx.stPRVINPUT]);
await fd.writeULE64(ctx.signals.length);
await fd.writeULE32(ctx.constraints.length);
const headerSize = p - pHeaderSize - 8;
const headerSize = fd.pos - pHeaderSize - 8;
// Write constraints
///////////
await writeU32(2); // Constraints type
const pConstraintsSize = p;
await writeU64(0); // Temporally set to 0 length
await fd.writeULE32(2); // Constraints type
const pConstraintsSize = fd.pos;
await fd.writeULE64(0); // Temporally set to 0 length
for (let i=0; i<ctx.constraints.length; i++) {
if ((ctx.verbose)&&(i%10000 == 0)) {
@@ -56,13 +61,13 @@ async function buildR1cs(ctx, fileName) {
await writeConstraint(ctx.constraints[i]);
}
const constraintsSize = p - pConstraintsSize - 8;
const constraintsSize = fd.pos - pConstraintsSize - 8;
// Write map
///////////
await writeU32(3); // wires2label type
const pMapSize = p;
await writeU64(0); // Temporally set to 0 length
await fd.writeULE32(3); // wires2label type
const pMapSize = fd.pos;
await fd.writeULE64(0); // Temporally set to 0 length
const arr = new Array(NWires);
@@ -76,75 +81,64 @@ async function buildR1cs(ctx, fileName) {
}
}
for (let i=0; i<arr.length; i++) {
await writeU64(arr[i]);
if ((ctx.verbose)&&(i%100000)) console.log("writing wire2label map: ", i);
await fd.writeULE64(arr[i]);
if ((ctx.verbose)&&(i%100000 == 0)) console.log(`writing wire2label map: ${i}/${arr.length}`);
}
const mapSize = p - pMapSize - 8;
const mapSize = fd.pos - pMapSize - 8;
// Write sizes
await writeU32(headerSize, pHeaderSize);
await writeU32(constraintsSize, pConstraintsSize);
await writeU32(mapSize, pMapSize);
await fd.writeULE32(headerSize, pHeaderSize);
await fd.writeULE32(constraintsSize, pConstraintsSize);
await fd.writeULE32(mapSize, pMapSize);
await fd.close();
async function writeU32(v, pos) {
let o = (typeof pos == "undefined") ? p : pos;
const b = Buffer.allocUnsafe(4);
b.writeInt32LE(v);
await fd.write(b, o);
if (typeof(pos) == "undefined") p += 4;
}
async function writeU64(v, pos) {
let o = (typeof pos == "undefined") ? p : pos;
const b = Buffer.allocUnsafe(8);
const LSB = v & 0xFFFFFFFF;
const MSB = Math.floor(v / 0x100000000);
b.writeInt32LE(LSB, 0);
b.writeInt32LE(MSB, 4);
await fd.write(b, o);
if (typeof(pos) == "undefined") p += 8;
}
async function writeConstraint(c) {
await writeLC(c.a);
await writeLC(c.b);
await writeLC(ctx.lc.neg(c.c));
}
async function writeLC(lc) {
const idxs = Object.keys(lc.coefs);
await writeU32(idxs.length);
for (let s in lc.coefs) {
let lSignal = ctx.signals[s];
function writeConstraint(c) {
const n8 = ctx.F.n8;
const idxA = Object.keys(c.a.coefs);
const idxB = Object.keys(c.b.coefs);
const idxC = Object.keys(c.c.coefs);
const buff = new Uint8Array((idxA.length+idxB.length+idxC.length)*(n8+4) + 12);
const buffV = new DataView(buff.buffer);
let o=0;
buffV.setUint32(o, idxA.length, true); o+=4;
for (let i=0; i<idxA.length; i++) {
const coef = idxA[i];
let lSignal = ctx.signals[coef];
while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e];
await writeU32(lSignal.id);
await writeBigInt(lc.coefs[s]);
buffV.setUint32(o, lSignal.id, true); o+=4;
ctx.F.toRprLE(buff, o, c.a.coefs[coef]); o+=n8;
}
buffV.setUint32(o, idxB.length, true); o+=4;
for (let i=0; i<idxB.length; i++) {
const coef = idxB[i];
let lSignal = ctx.signals[coef];
while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e];
buffV.setUint32(o, lSignal.id, true); o+=4;
ctx.F.toRprLE(buff, o, c.b.coefs[coef]); o+=n8;
}
buffV.setUint32(o, idxC.length, true); o+=4;
for (let i=0; i<idxC.length; i++) {
const coef = idxC[i];
let lSignal = ctx.signals[coef];
while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e];
buffV.setUint32(o, lSignal.id, true); o+=4;
ctx.F.toRprLE(buff, o, ctx.F.neg(c.c.coefs[coef])); o+=n8;
}
return fd.write(buff);
}
async function writeBigInt(n, pos) {
let o = (typeof pos == "undefined") ? p : pos;
ctx.F.toRprLE(buffBigInt, 0, n);
const s = n.toString(16);
const b = Buffer.from(s.padStart(n8*2, "0"), "hex");
const buff = Buffer.allocUnsafe(b.length);
for (let i=0; i<b.length; i++) buff[i] = b[b.length-1-i];
await fd.write(buffBigInt, pos);
await fd.write(buff, o);
if (typeof(pos) == "undefined") p += n8;
}
}