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