arnaucube
arnaucube/circomPublic Self-hosted repository
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