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