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