circom/src/compiler.js
src/compiler.jsRaw
1/*
2 Copyright 2018 0KIMS association.
3
4 This file is part of circom (Zero Knowledge Circuit Compiler).
5
6 circom is a free software: you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 circom is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with circom. If not, see <https://www.gnu.org/licenses/>.
18*/
19
20const Scalar = require("ffjavascript").Scalar;
21const sONE = 0;
22const build = require("./build");
23const BuilderC = require("../ports/c/builder.js");
24const BuilderWasm = require("../ports/wasm/builder.js");
25const constructionPhase = require("./construction_phase");
26const Ctx = require("./ctx");
27const utils = require("./utils");
28const buildR1cs = require("./r1csfile").buildR1cs;
29const BigArray = require("./bigarray");
30const buildSyms = require("./buildsyms");
31const {performance} = require("perf_hooks");
32
33module.exports = compile;
34const measures = {};
35
36function ms2String(v) {
37 v = Math.floor(v);
38 const ms = v % 1000;
39 v = Math.floor(v/1000);
40 const secs = v % 60;
41 v = Math.floor(v/60);
42 const mins = v % 60;
43 v = Math.floor(v/60);
44 const hours = v % 24;
45 const days = Math.floor(v/24);
46 let S = "";
47 if (days) S = S + days + "D ";
48 if ((S!="")||(hours)) S = S + hours.toString().padStart(2, "0") + ":";
49 if ((S!="")||(mins)) S = S + mins.toString().padStart(2, "0") + ":";
50 if ((S!="")||(secs)) S = S + secs.toString().padStart(2, "0");
51 S+=".";
52 S = S + ms.toString().padStart(3, "0");
53 return S;
54}
55
56async function compile(srcFile, options) {
57 options.prime = options.prime || Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
58 if (!options) {
59 options = {};
60 }
61 if (typeof options.reduceConstraints === "undefined") {
62 options.reduceConstraints = true;
63 }
64 const ctx = new Ctx(options.prime);
65 ctx.verbose= options.verbose || false;
66 ctx.mainComponent = options.mainComponent || "main";
67 ctx.newThreadTemplates = options.newThreadTemplates;
68
69 measures.constructionPhase = -performance.now();
70 constructionPhase(ctx, srcFile);
71 measures.constructionPhase += performance.now();
72
73 if (ctx.verbose) console.log("NConstraints Before: "+ctx.constraints.length);
74 if (ctx.verbose) console.log("NSignals Before: "+ctx.signals.length);
75
76 if (ctx.error) {
77 throw(ctx.error);
78 }
79
80 if (ctx.getComponentIdx(ctx.mainComponent)<0) {
81 throw new Error("A main component must be defined");
82 }
83
84 if (ctx.verbose) console.log("Classify Signals");
85 measures.classifySignals = -performance.now();
86 classifySignals(ctx);
87 measures.classifySignals += performance.now();
88
89 if (ctx.verbose) console.log("Reduce Constants");
90 measures.reduceConstants = -performance.now();
91 reduceConstants(ctx);
92 measures.reduceConstants += performance.now();
93
94 if (options.reduceConstraints) {
95
96 if (ctx.verbose) console.log("Reduce Constraints");
97 // Repeat while reductions are performed
98/*
99 let oldNConstrains = -1;
100 while (ctx.constraints.length != oldNConstrains) {
101 if (ctx.verbose) console.log("Reducing constraints: "+ctx.constraints.length);
102 oldNConstrains = ctx.constraints.length;
103 reduceConstrains(ctx);
104 }
105*/
106 measures.reduceConstraints = -performance.now();
107 await reduceConstrains(ctx);
108 measures.reduceConstraints += performance.now();
109
110 }
111
112 if (ctx.verbose) console.log("NConstraints After: "+ctx.constraints.length);
113
114 measures.generateWitnessNames = -performance.now();
115 generateWitnessNames(ctx);
116 measures.generateWitnessNames += performance.now();
117
118 if (ctx.error) {
119 throw(ctx.error);
120 }
121
122 if (options.cSourceWriteStream) {
123 if (ctx.verbose) console.log("Generating c...");
124 measures.generateC = -performance.now();
125 ctx.builder = new BuilderC(options.prime);
126 build(ctx);
127 const rdStream = ctx.builder.build();
128 rdStream.pipe(options.cSourceWriteStream);
129 measures.generateC += performance.now();
130
131 // await new Promise(fulfill => options.cSourceWriteStream.on("finish", fulfill));
132 }
133
134 if ((options.wasmWriteStream)||(options.watWriteStream)) {
135 if (ctx.verbose) console.log("Generating wasm...");
136 measures.generateWasm = -performance.now();
137 ctx.builder = new BuilderWasm(options.prime);
138 build(ctx);
139 if (options.wasmWriteStream) {
140 const rdStream = ctx.builder.build("wasm");
141 rdStream.pipe(options.wasmWriteStream);
142 }
143 if (options.watWriteStream) {
144 const rdStream = ctx.builder.build("wat");
145 rdStream.pipe(options.watWriteStream);
146 }
147 measures.generateWasm += performance.now();
148
149 // await new Promise(fulfill => options.wasmWriteStream.on("finish", fulfill));
150 }
151
152 // const mainCode = gen(ctx,ast);
153 if (ctx.error) throw(ctx.error);
154
155 if (options.r1csFileName) {
156 measures.generateR1cs = -performance.now();
157 await buildR1cs(ctx, options.r1csFileName);
158 measures.generateR1cs += performance.now();
159 }
160
161 if (options.symWriteStream) {
162 measures.generateSyms = -performance.now();
163 const rdStream = buildSyms(ctx);
164 rdStream.pipe(options.symWriteStream);
165 measures.generateSyms += performance.now();
166
167 await new Promise(fulfill => options.symWriteStream.on("finish", fulfill));
168 }
169
170// const def = buildCircuitDef(ctx, mainCode);
171
172 if (ctx.verbose) {
173 for (let [mStr, mValue] of Object.entries(measures)) {
174 console.log(mStr + ": " + ms2String(mValue));
175 }
176 }
177}
178
179
180
181function classifySignals(ctx) {
182
183 const ERROR = 0xFFFF;
184
185 function priorize(t1, t2) {
186 if ((t1 == ERROR) || (t2==ERROR)) return ERROR;
187 if (t1 == ctx.stINTERNAL) {
188 return t2;
189 } else if (t2==ctx.stINTERNAL) {
190 return t1;
191 }
192 if ((t1 == ctx.stONE) || (t2 == ctx.stONE)) return ctx.stONE;
193 if ((t1 == ctx.stOUTPUT) || (t2 == ctx.stOUTPUT)) return ctx.stOUTPUT;
194 if ((t1 == ctx.stCONSTANT) || (t2 == ctx.stCONSTANT)) return ctx.stCONSTANT;
195 if ((t1 == ctx.stDISCARDED) || (t2 == ctx.stDISCARDED)) return ctx.stDISCARDED;
196 if (t1!=t2) return ERROR;
197 return t1;
198 }
199
200 // First classify the signals
201 for (let s=0; s<ctx.signals.length; s++) {
202 if ((ctx.verbose)&&(s%100000 == 0)) console.log(`classify signals: ${s}/${ctx.signals.length}`);
203 const signal = ctx.signals[s];
204 let tAll = ctx.stINTERNAL;
205 let lSignal = signal;
206 let end = false;
207 while (!end) {
208 let t = lSignal.c || ctx.stINTERNAL;
209 if (s == 0) {
210 t = ctx.stONE;
211 } else if (lSignal.o & ctx.MAIN) {
212 if (lSignal.o & ctx.IN) {
213 if (lSignal.o & ctx.PRV) {
214 t = ctx.stPRVINPUT;
215 } else {
216 t = ctx.stPUBINPUT;
217 }
218 } else if (lSignal.o & ctx.OUT) {
219 t = ctx.stOUTPUT;
220 }
221 } else if (utils.isDefined(lSignal.v)) {
222 t = ctx.stCONSTANT;
223 }
224 tAll = priorize(t,tAll);
225 if (lSignal.e>=0) {
226 lSignal = ctx.signals[lSignal.e];
227 } else {
228 end=true;
229 }
230 }
231 if (tAll == ERROR) {
232 throw new Error("Incompatible types in signal: " + s);
233 }
234 lSignal.c = tAll;
235 }
236}
237
238
239function generateWitnessNames(ctx) {
240 const totals = {};
241 totals[ctx.stONE] = 0;
242 totals[ctx.stOUTPUT] = 0;
243 totals[ctx.stPUBINPUT] = 0;
244 totals[ctx.stPRVINPUT] = 0;
245 totals[ctx.stINTERNAL] = 0;
246 totals[ctx.stDISCARDED] = 0;
247 totals[ctx.stCONSTANT] = 0;
248 const ids = {};
249
250 // First classify the signals
251 for (let s=0; s<ctx.signals.length; s++) {
252
253 if ((ctx.verbose)&&(s%10000 == 0)) console.log("generate witness (counting): ", s);
254
255 const signal = ctx.signals[s];
256 let lSignal = signal;
257 while (lSignal.e>=0) lSignal = ctx.signals[lSignal.e];
258
259 if (!( lSignal.o & ctx.COUNTED) ) {
260 lSignal.o |= ctx.COUNTED;
261 totals[lSignal.c] ++;
262 }
263 }
264
265 ids[ctx.stONE] = 0;
266 ids[ctx.stOUTPUT] = 1;
267 ids[ctx.stPUBINPUT] = ids[ctx.stOUTPUT] + totals[ctx.stOUTPUT];
268 ids[ctx.stPRVINPUT] = ids[ctx.stPUBINPUT] + totals[ctx.stPUBINPUT];
269 ids[ctx.stINTERNAL] = ids[ctx.stPRVINPUT] + totals[ctx.stPRVINPUT];
270 ids[ctx.stDISCARDED] = ids[ctx.stINTERNAL] + totals[ctx.stINTERNAL];
271 ids[ctx.stCONSTANT] = ids[ctx.stDISCARDED] + totals[ctx.stDISCARDED];
272 const nSignals = ids[ctx.stCONSTANT] + totals[ctx.stCONSTANT];
273
274 for (let s=0; s<ctx.signals.length; s++) {
275
276 if ((ctx.verbose)&&(s%10000 == 0)) console.log("seting id: ", s);
277
278 const signal = ctx.signals[s];
279 let lSignal = signal;
280 while (lSignal.e>=0) {
281 lSignal = ctx.signals[lSignal.e];
282 }
283 if ( typeof(lSignal.id) === "undefined" ) {
284 lSignal.id = ids[lSignal.c] ++;
285 }
286
287 signal.id = lSignal.id;
288 }
289
290 ctx.totals = totals;
291}
292
293function reduceConstants(ctx) {
294 const newConstraints = new BigArray();
295 for (let i=0; i<ctx.constraints.length; i++) {
296 if ((ctx.verbose)&&(i%10000 == 0)) console.log("reducing constants: ", i);
297 const c = ctx.lc.canonize(ctx, ctx.constraints[i]);
298 if (!ctx.lc.isZero(c)) {
299 newConstraints.push(c);
300 }
301 delete ctx.constraints[i];
302 }
303 ctx.constraints = newConstraints;
304}
305
306async function reduceConstrains(ctx) {
307 const sig2constraint = new BigArray();
308 let removedSignals = new BigArray();
309 let nRemoved;
310 let lIdx;
311
312
313 let possibleConstraints = new BigArray(ctx.constraints.length);
314 let nextPossibleConstraints;
315 for (let i=0; i<ctx.constraints.length; i++) {
316 if ((ctx.verbose)&&(i%100000 == 0)) console.log(`indexing constraints: ${i}/${ctx.constraints.length}`);
317
318 const insertedSig = { 0: true}; // Do not insert one.
319 const c = ctx.constraints[i];
320 for (let s in c.a.coefs) {
321 if (!insertedSig[s]) {
322 if (!sig2constraint[s]) sig2constraint[s] = [];
323 sig2constraint[s].push(i);
324 insertedSig[s] = true;
325 }
326 }
327 for (let s in c.b.coefs) {
328 if (!insertedSig[s]) {
329 if (!sig2constraint[s]) sig2constraint[s] = [];
330 sig2constraint[s].push(i);
331 insertedSig[s] = true;
332 }
333 }
334 for (let s in c.c.coefs) {
335 if (!insertedSig[s]) {
336 if (!sig2constraint[s]) sig2constraint[s] = [];
337 sig2constraint[s].push(i);
338 insertedSig[s] = true;
339 }
340 }
341 possibleConstraints[i] = i;
342 }
343
344 while (possibleConstraints.length >0) {
345 nextPossibleConstraints = new BigArray();
346 removedSignals = new BigArray();
347 nRemoved = 0;
348 lIdx = new BigArray();
349 for (let i=0;i<possibleConstraints.length;i++) {
350 if ((ctx.verbose)&&(i%10000 == 0)) {
351 await Promise.resolve();
352 console.log(`reducing constraints: ${i}/${possibleConstraints.length} reduced: ${nRemoved}`);
353 }
354 const c = ctx.constraints[possibleConstraints[i]];
355 if (!c) continue;
356
357 // Swap a and b if b has more variables.
358 if (Object.keys(c.b).length > Object.keys(c.a).length) {
359 const aux = c.a;
360 c.a=c.b;
361 c.b=aux;
362 }
363
364 // Mov to C if possible.
365 if (isConstant(c.a)) {
366 const ct = {t: "N", v: c.a.coefs[sONE]};
367 c.c = ctx.lc.add(ctx.lc.mul(c.b, ct), c.c);
368 c.a = { t: "LC", coefs: {} };
369 c.b = { t: "LC", coefs: {} };
370 }
371 if (isConstant(c.b)) {
372 const ct = {t: "N", v: c.b.coefs[sONE]};
373 c.c = ctx.lc.add(ctx.lc.mul(c.a, ct), c.c);
374 c.a = { t: "LC", coefs: {} };
375 c.b = { t: "LC", coefs: {} };
376 }
377
378 if (ctx.lc.isZero(c.a) || ctx.lc.isZero(c.b)) {
379 const freeC = substituteRemoved(c.c);
380 const isolatedSignal = getFirstInternalSignal(ctx, freeC);
381 if (isolatedSignal) {
382 // console.log(isolatedSignal);
383 // console.log(freeC);
384 removedSignals[isolatedSignal] = isolateSignal(freeC, isolatedSignal);
385 if (lIdx[isolatedSignal]) {
386 lIdx[isolatedSignal].forEach( (s) => {
387 removedSignals[s] = substitute(removedSignals[s], isolatedSignal, removedSignals[isolatedSignal]);
388 });
389 }
390
391 addTolIdx(removedSignals[isolatedSignal], isolatedSignal);
392 ctx.constraints[possibleConstraints[i]] = null;
393 nRemoved ++;
394
395 sig2constraint[isolatedSignal].forEach( (s) => {
396 nextPossibleConstraints[s] = true;
397 });
398 }
399 }
400 }
401
402 nextPossibleConstraints = nextPossibleConstraints.getKeys();
403
404 for (let i=0; i<nextPossibleConstraints.length;i++) {
405 if ((ctx.verbose)&&(i%10000 == 0)) {
406 await Promise.resolve();
407 console.log(`substituting constraints: ${i}/${nextPossibleConstraints.length}`);
408 }
409 const c = ctx.constraints[nextPossibleConstraints[i]];
410 if (c) {
411 const nc = {
412 a: substituteRemoved(c.a),
413 b: substituteRemoved(c.b),
414 c: substituteRemoved(c.c)
415 };
416 if (ctx.lc.isZero(nc)) {
417 delete ctx.constraints[nextPossibleConstraints[i]];
418 } else {
419 ctx.constraints[nextPossibleConstraints[i]] = nc;
420 }
421 }
422 }
423
424 const removedSignalsList = removedSignals.getKeys;
425
426 for (let i=0; i<removedSignalsList.length; i++) {
427 if ((ctx.verbose )&&(i%100000 == 0)) console.log(`removing signals: ${i}/${removedSignalsList.length}`);
428 const s = removedSignalsList[i];
429
430 let lSignal = ctx.signals[s];
431 while (lSignal.e>=0) {
432 lSignal = ctx.signals[lSignal.e];
433 }
434
435 lSignal.c = ctx.stDISCARDED;
436 }
437
438 possibleConstraints = nextPossibleConstraints;
439 }
440
441 let o=0;
442 for (let i=0; i<ctx.constraints.length;i++) {
443 if ((ctx.verbose)&&(i%100000 == 0)) console.log(`reordering constraints: ${i}/${ctx.constraints.length}`);
444 if (ctx.constraints[i]) {
445 if (!ctx.lc.isZero(ctx.constraints[i])) {
446 ctx.constraints[o] = ctx.constraints[i];
447 o++;
448 }
449 }
450 }
451
452 ctx.constraints.length = o;
453
454 function getFirstInternalSignal(ctx, l) {
455 for (let k in l.coefs) {
456 k = Number(k);
457 const signal = ctx.signals[k];
458 if ((signal.c == ctx.stINTERNAL)&&(!ctx.F.isZero(l.coefs[k])) &&(!removedSignals[k])) return k;
459 }
460 return null;
461 }
462
463 function isolateSignal(lc, s) {
464 const eq = {
465 t: "LC",
466 coefs: {}
467 };
468 const invCoef = ctx.F.inv(lc.coefs[s]);
469 for (const k in lc.coefs) {
470 if (k != s) {
471 const v = ctx.F.mul( ctx.F.neg(lc.coefs[k]), invCoef);
472 if (!ctx.F.isZero(v)) {
473 eq.coefs[k] = v;
474 }
475 }
476 }
477 return eq;
478 }
479
480 function substituteRemoved(lc) {
481 const newLc = ctx.lc._clone(lc);
482 for (let k in lc.coefs) {
483 if (removedSignals[k]) {
484 delete newLc.coefs[k];
485 for (let k2 in removedSignals[k].coefs) {
486 const newP = ctx.F.mul(removedSignals[k].coefs[k2], lc.coefs[k]);
487 if (!ctx.F.isZero(newP)) {
488 if (newLc.coefs[k2]) {
489 newLc.coefs[k2] = ctx.F.add(newLc.coefs[k2], newP);
490 if (ctx.F.isZero(newLc.coefs[k2])) delete newLc.coefs[k2];
491 } else {
492 newLc.coefs[k2] = newP;
493 }
494 }
495 }
496 }
497 }
498 return newLc;
499 }
500
501 function substitute(lc, s, eq) {
502 if (!lc.coefs[s]) return lc;
503 const newLc = ctx.lc._clone(lc);
504 delete newLc.coefs[s];
505 for (let k2 in eq.coefs) {
506 const newP = ctx.F.mul(eq.coefs[k2], lc.coefs[s]);
507 if (!ctx.F.isZero(newP)) {
508 if (newLc.coefs[k2]) {
509 newLc.coefs[k2] = ctx.F.add(newLc.coefs[k2], newP);
510 if (ctx.F.isZero(newLc.coefs[k2])) delete newLc.coefs[k2];
511 } else {
512 newLc.coefs[k2] = newP;
513 }
514 }
515 }
516 return newLc;
517 }
518
519 function isConstant(l) {
520 for (let k in l.coefs) {
521 if ((k != sONE) && (!ctx.F.isZero(l.coefs[k]))) return false;
522 }
523 if (!l.coefs[sONE] || ctx.F.isZero(l.coefs[sONE])) return false;
524 return true;
525 }
526
527 function addTolIdx(lc, newS) {
528 for (let s in lc.coefs) {
529 if (!lIdx[s]) lIdx[s] = [];
530 lIdx[s].push(newS);
531 }
532 }
533
534
535}
536
537
538function reduceConstrains_old(ctx) {
539 indexVariables();
540 let possibleConstraints = ctx.constraints;
541 let ii=0;
542 while (possibleConstraints.length>0) {
543 let nextPossibleConstraints = new BigArray();
544 for (let i=0; i<possibleConstraints.length; i++) {
545 ii++;
546 if ((ctx.verbose)&&(ii%10000 == 0)) console.log("reducing constraints: ", i);
547 if (!ctx.constraints[i]) continue;
548 const c = ctx.constraints[i];
549
550 // Swap a and b if b has more variables.
551 if (Object.keys(c.b).length > Object.keys(c.a).length) {
552 const aux = c.a;
553 c.a=c.b;
554 c.b=aux;
555 }
556
557 // Mov to C if possible.
558 if (isConstant(c.a)) {
559 const ct = {t: "N", v: c.a.coefs[sONE]};
560 c.c = ctx.lc.add(ctx.lc.mul(c.b, ct), c.c);
561 c.a = { t: "LC", coefs: {} };
562 c.b = { t: "LC", coefs: {} };
563 }
564 if (isConstant(c.b)) {
565 const ct = {t: "N", v: c.b.coefs[sONE]};
566 c.c = ctx.lc.add(ctx.lc.mul(c.a, ct), c.c);
567 c.a = { t: "LC", coefs: {} };
568 c.b = { t: "LC", coefs: {} };
569 }
570
571 if (ctx.lc.isZero(c.a) || ctx.lc.isZero(c.b)) {
572 const isolatedSignal = getFirstInternalSignal(ctx, c.c);
573 if (isolatedSignal) {
574
575 let lSignal = ctx.signals[isolatedSignal];
576 while (lSignal.e>=0) {
577 lSignal = ctx.signals[lSignal.e];
578 }
579
580
581 const isolatedSignalEquivalence = {
582 t: "LC",
583 coefs: {}
584 };
585 const invCoef = ctx.F.inv(c.c.coefs[isolatedSignal]);
586 for (const s in c.c.coefs) {
587 if (s != isolatedSignal) {
588 const v = ctx.F.mul( ctx.F.neg(c.c.coefs[s]), invCoef);
589 if (!ctx.F.isZero(v)) {
590 isolatedSignalEquivalence.coefs[s] = v;
591 }
592 }
593 }
594
595 for (let j in lSignal.inConstraints) {
596 if ((j!=i)&&(ctx.constraints[j])) {
597 ctx.constraints[j] = ctx.lc.substitute(ctx.constraints[j], isolatedSignal, isolatedSignalEquivalence);
598 linkSignalsConstraint(j);
599 if (j<i) {
600 nextPossibleConstraints.push(j);
601 }
602 }
603 }
604
605 ctx.constraints[i] = null;
606
607 lSignal.c = ctx.stDISCARDED;
608 } else {
609 if (ctx.lc.isZero(c.c)) ctx.constraints[i] = null;
610 }
611 }
612 }
613 possibleConstraints = nextPossibleConstraints;
614 }
615 unindexVariables();
616
617 // Pack the constraints
618 let o = 0;
619 for (let i=0; i<ctx.constraints.length; i++) {
620 if (ctx.constraints[i]) {
621 if (o != i) {
622 ctx.constraints[o] = ctx.constraints[i];
623 }
624 o++;
625 }
626 }
627 ctx.constraints.length = o;
628
629 function indexVariables() {
630 for (let i=0; i<ctx.constraints.length; i++) linkSignalsConstraint(i);
631 }
632
633 function linkSignalsConstraint(cidx) {
634 const ct = ctx.constraints[cidx];
635 for (let k in ct.a.coefs) linkSignal(k, cidx);
636 for (let k in ct.b.coefs) linkSignal(k, cidx);
637 for (let k in ct.c.coefs) linkSignal(k, cidx);
638 }
639
640 function unindexVariables() {
641 for (let s=0; s<ctx.signals.length; s++) {
642 let lSignal = ctx.signals[s];
643 while (lSignal.e>=0) {
644 lSignal = ctx.signals[lSignal.e];
645 }
646 if (lSignal.inConstraints) delete lSignal.inConstraints;
647 }
648 }
649
650/*
651 function unlinkSignal(signalName, cidx) {
652 let lSignal = ctx.signals[signalName];
653 while (lSignal.e>=0) {
654 lSignal = ctx.signals[lSignal.e];
655 }
656 if ((lSignal.inConstraints)&&(lSignal.inConstraints[cidx])) {
657 delete lSignal.inConstraints[cidx];
658 }
659 }
660*/
661
662 function linkSignal(signalName, cidx) {
663 let lSignal = ctx.signals[signalName];
664 while (lSignal.e>=0) {
665 lSignal = ctx.signals[lSignal.e];
666 }
667 if (!lSignal.inConstraints) lSignal.inConstraints = {};
668 lSignal.inConstraints[cidx] = true;
669 }
670
671 function getFirstInternalSignal(ctx, l) {
672 for (let k in l.coefs) {
673 const signal = ctx.signals[k];
674 if (signal.c == ctx.stINTERNAL) return k;
675 }
676 return null;
677 }
678
679 function isConstant(l) {
680 for (let k in l.coefs) {
681 if ((k != sONE) && (!ctx.F.isZero(l.coefs[k]))) return false;
682 }
683 if (!l.coefs[sONE] || ctx.F.isZero(l.coefs[sONE])) return false;
684 return true;
685 }
686
687}
688
689/*
690
691function buildCircuitDef(ctx, mainCode) {
692 const res = {
693 mainCode: mainCode
694 };
695 res.signalName2Idx = ctx.signalName2Idx;
696
697 res.components = [];
698 res.componentName2Idx = {};
699 for (let c in ctx.components) {
700 const idCoponent = res.components.length;
701 res.components.push({
702 name: c,
703 params: ctx.components[c].params,
704 template: ctx.components[c].template,
705 inputSignals: 0
706 });
707 res.componentName2Idx[c] = idCoponent;
708 }
709
710 res.signals = new Array(ctx.signalNames.length);
711 for (let i=0; i<ctx.signalNames.length; i++) {
712 res.signals[i] = {
713 names: ctx.signalNames[i],
714 triggerComponents: []
715 };
716 ctx.signalNames[i].map( (fullName) => {
717 const idComponet = res.componentName2Idx[ctx.signals[fullName].component];
718 if (ctx.signals[fullName].direction == "IN") {
719 res.signals[i].triggerComponents.push(idComponet);
720 res.components[idComponet].inputSignals++;
721 }
722 });
723 }
724
725 res.constraints = buildConstraints(ctx);
726
727 res.templates = ctx.templates;
728
729 res.functions = {};
730 for (let f in ctx.functions) {
731 res.functions[f] = {
732 params: ctx.functionParams[f],
733 func: ctx.functions[f]
734 };
735 }
736
737 res.nPrvInputs = ctx.totals.prvInput;
738 res.nPubInputs = ctx.totals.pubInput;
739 res.nInputs = res.nPrvInputs + res.nPubInputs;
740 res.nOutputs = ctx.totals.output;
741 res.nVars = res.nInputs + res.nOutputs + ctx.totals.one + ctx.totals.internal;
742 res.nConstants = ctx.totals.constant;
743 res.nSignals = res.nVars + res.nConstants;
744
745 return res;
746}
747
748*/
749
750
751/*
752 Build constraints
753
754A constraint like this
755
756 [s1 + 2*s2 + 3*s3] * [ s2 + 5*s4] - [s0 ] = 0
757 [ 5*s2 + 6*s3] * [ s2 + ] - [s0 + 2* s2] = 0
758 [s1 + s3] * [ s2 + 5*s3] - [s4 ] = 0
759
760is converted to
761
762[
763 [{"1":"1","2":"2","3":"3"} , {"2":"1","4":"5"} , {"0":"1" }],
764 [{ "2":"5","3":"6"} , {"2":"1" } , {"0":"1", "2":"2"}],
765 [{"1":"1", "3":"1"} , {"2":"1","3":"5"} , {"4":"1" }]
766]
767 ^ ^ ^
768 | | |
769 A B C
770
771*/
772/*
773function buildConstraints(ctx) {
774 const res = [];
775
776 function fillLC(dst, src) {
777 if (src.t != "LC") throw new Error("Constraint is not a LINEARCOMBINATION");
778 for (let s in src.coefs) {
779 const v = src.coefs[s].toString();
780 const id = ctx.signalName2Idx[s];
781 dst[id] = v;
782 }
783 }
784
785 for (let i=0; i<ctx.constraints.length; i++) {
786 const A = {};
787 const B = {};
788 const C = {};
789
790 fillLC(A, ctx.constraints[i].a);
791 fillLC(B, ctx.constraints[i].b);
792 fillLC(C, ctx.lc.negate(ctx.constraints[i].c));
793
794 res.push([A,B,C]);
795 }
796
797 return res;
798}
799*/
800
801/*
802function buildSyms(ctx, strm) {
803
804 let nSyms;
805
806 addSymbolsComponent(ctx.mainComponent + ".", ctx.getComponentIdx(ctx.mainComponent));
807
808
809 function addSymbolsComponent(prefix, idComponet) {
810 for (let n in ctx.components[idComponet].names.o) {
811 const entrie = ctx.components[idComponet].names.o[n];
812 addSymbolArray(prefix+n, entrie.type, entrie.sizes, entrie.offset);
813 }
814 }
815
816 function addSymbolArray(prefix, type, sizes, offset) {
817 if (sizes.length==0) {
818 if (type == "S") {
819 let s=offset;
820 while (ctx.signals[s].e >= 0) s = ctx.signals[s].e;
821 let wId = ctx.signals[s].id;
822 if (typeof(wId) == "undefined") wId=-1;
823 strm.write(`${offset},${wId},${prefix}\n`);
824 nSyms ++;
825 if ((ctx.verbose)&&(nSyms%10000 == 0)) console.log("Symbols saved: "+nSyms);
826 } else {
827 addSymbolsComponent(prefix+".", offset);
828 }
829 return 1;
830 } else {
831 let acc = 0;
832 for (let i=0; i<sizes[0]; i++) {
833 acc += addSymbolArray(`${prefix}[${i}]`, type, sizes.slice(1), offset + acc );
834 }
835 return acc;
836 }
837 }
838
839}
840
841*/
842