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        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