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