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        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
258function reduceConstrains(ctx) {
259    const sig2constraint = {};
260    let removedSignals = {};
261    let nRemoved;
262    let lIdx;
263
264
265    let possibleConstraints = new Array(ctx.constraints.length);
266    let nextPossibleConstraints;
267    for (let i=0; i<ctx.constraints.length; i++) {
268        const insertedSig = {};
269        const c = ctx.constraints[i];
270        for (let s in c.a.coefs) {
271            if (!insertedSig[s]) {
272                if (!sig2constraint[s]) sig2constraint[s] = [];
273                sig2constraint[s].push(i);
274                insertedSig[s] = true;
275            }
276        }
277        for (let s in c.b.coefs) {
278            if (!insertedSig[s]) {
279                if (!sig2constraint[s]) sig2constraint[s] = [];
280                sig2constraint[s].push(i);
281                insertedSig[s] = true;
282            }
283        }
284        for (let s in c.c.coefs) {
285            if (!insertedSig[s]) {
286                if (!sig2constraint[s]) sig2constraint[s] = [];
287                sig2constraint[s].push(i);
288                insertedSig[s] = true;
289            }
290        }
291        possibleConstraints[i] = i;
292    }
293
294    while (possibleConstraints.length >0) {
295        nextPossibleConstraints = {};
296        removedSignals = {};
297        nRemoved = 0;
298        lIdx = {};
299        for (let i=0;i<possibleConstraints.length;i++) {
300            if ((ctx.verbose)&&(i%10000 == 0)) {
301                console.log(`reducing constraints: ${i}/${possibleConstraints.length}   reduced: ${nRemoved}`);
302            }
303            const c = ctx.constraints[possibleConstraints[i]];
304            if (!c) continue;
305
306            // Swap a and b if b has more variables.
307            if (Object.keys(c.b).length > Object.keys(c.a).length) {
308                const aux = c.a;
309                c.a=c.b;
310                c.b=aux;
311            }
312
313            // Mov to C if possible.
314            if (isConstant(c.a)) {
315                const ct = {t: "N", v: c.a.coefs[sONE]};
316                c.c = ctx.lc.add(ctx.lc.mul(c.b, ct), c.c);
317                c.a = { t: "LC", coefs: {} };
318                c.b = { t: "LC", coefs: {} };
319            }
320            if (isConstant(c.b)) {
321                const ct = {t: "N", v: c.b.coefs[sONE]};
322                c.c = ctx.lc.add(ctx.lc.mul(c.a, ct), c.c);
323                c.a = { t: "LC", coefs: {} };
324                c.b = { t: "LC", coefs: {} };
325            }
326
327            if (ctx.lc.isZero(c.a) || ctx.lc.isZero(c.b)) {
328                const freeC = substituteRemoved(c.c);
329                const isolatedSignal = getFirstInternalSignal(ctx, freeC);
330                if (isolatedSignal) {
331    //                console.log(isolatedSignal);
332    //                console.log(freeC);
333                    removedSignals[isolatedSignal] = isolateSignal(freeC, isolatedSignal);
334                    if (lIdx[isolatedSignal]) {
335                        lIdx[isolatedSignal].forEach( (s) => {
336                            removedSignals[s] = substitute(removedSignals[s], isolatedSignal, removedSignals[isolatedSignal]);
337                        });
338                    }
339
340                    addTolIdx(removedSignals[isolatedSignal], isolatedSignal);
341                    ctx.constraints[possibleConstraints[i]] = null;
342                    nRemoved ++;
343
344                    sig2constraint[isolatedSignal].forEach( (s) => {
345                        nextPossibleConstraints[s] = true;
346                    });
347                }
348            }
349        }
350
351        nextPossibleConstraints = Object.keys(nextPossibleConstraints);
352
353        for (let i=0; i<nextPossibleConstraints.length;i++) {
354            const c = ctx.constraints[nextPossibleConstraints[i]];
355            if (c) {
356                const nc = {
357                    a: substituteRemoved(c.a),
358                    b: substituteRemoved(c.b),
359                    c: substituteRemoved(c.c)
360                };
361                if (ctx.lc.isZero(nc)) {
362                    delete ctx.constraints[nextPossibleConstraints[i]];
363                } else {
364                    ctx.constraints[nextPossibleConstraints[i]] = nc;
365                }
366            }
367        }
368
369        for (let s in removedSignals) {
370
371            let lSignal = ctx.signals[s];
372            while (lSignal.e>=0) {
373                lSignal = ctx.signals[lSignal.e];
374            }
375
376            lSignal.c = ctx.stDISCARDED;
377        }
378
379        possibleConstraints = nextPossibleConstraints;
380
381    }
382
383    let o=0;
384    for (let i=0; i<ctx.constraints.length;i++) {
385        if (ctx.constraints[i]) {
386            if (!ctx.lc.isZero(ctx.constraints[i])) {
387                ctx.constraints[o] = ctx.constraints[i];
388                o++;
389            }
390        }
391    }
392
393    ctx.constraints.length = o;
394
395    function getFirstInternalSignal(ctx, l) {
396        for (let k in l.coefs) {
397            k = Number(k);
398            const signal = ctx.signals[k];
399            if ((signal.c == ctx.stINTERNAL)&&(!ctx.F.isZero(l.coefs[k])) &&(!removedSignals[k])) return k;
400        }
401        return null;
402    }
403
404    function isolateSignal(lc, s) {
405        const eq = {
406            t: "LC",
407            coefs: {}
408        };
409        const invCoef = ctx.F.inv(lc.coefs[s]);
410        for (const k in lc.coefs) {
411            if (k != s) {
412                const v = ctx.F.mul( ctx.F.neg(lc.coefs[k]), invCoef);
413                if (!ctx.F.isZero(v)) {
414                    eq.coefs[k] = v;
415                }
416            }
417        }
418        return eq;
419    }
420
421    function substituteRemoved(lc) {
422        const newLc = ctx.lc._clone(lc);
423        for (let k in lc.coefs) {
424            if (removedSignals[k]) {
425                delete newLc.coefs[k];
426                for (let k2 in removedSignals[k].coefs) {
427                    const newP = ctx.F.mul(removedSignals[k].coefs[k2], lc.coefs[k]);
428                    if (!ctx.F.isZero(newP)) {
429                        if (newLc.coefs[k2]) {
430                            newLc.coefs[k2] = ctx.F.add(newLc.coefs[k2], newP);
431                            if (ctx.F.isZero(newLc.coefs[k2])) delete newLc.coefs[k2];
432                        } else {
433                            newLc.coefs[k2] = newP;
434                        }
435                    }
436                }
437            }
438        }
439        return newLc;
440    }
441
442    function substitute(lc, s, eq) {
443        if (!lc.coefs[s]) return lc;
444        const newLc = ctx.lc._clone(lc);
445        delete newLc.coefs[s];
446        for (let k2 in eq.coefs) {
447            const newP = ctx.F.mul(eq.coefs[k2], lc.coefs[s]);
448            if (!ctx.F.isZero(newP)) {
449                if (newLc.coefs[k2]) {
450                    newLc.coefs[k2] = ctx.F.add(newLc.coefs[k2], newP);
451                    if (ctx.F.isZero(newLc.coefs[k2])) delete newLc.coefs[k2];
452                } else {
453                    newLc.coefs[k2] = newP;
454                }
455            }
456        }
457        return newLc;
458    }
459
460    function isConstant(l) {
461        for (let k in l.coefs) {
462            if ((k != sONE) && (!ctx.F.isZero(l.coefs[k]))) return false;
463        }
464        if (!l.coefs[sONE] || ctx.F.isZero(l.coefs[sONE])) return false;
465        return true;
466    }
467
468    function addTolIdx(lc, newS) {
469        for (let s in lc.coefs) {
470            if (!lIdx[s]) lIdx[s] = [];
471            lIdx[s].push(newS);
472        }
473    }
474
475
476}
477
478
479function reduceConstrains_old(ctx) {
480    indexVariables();
481    let possibleConstraints = ctx.constraints;
482    let ii=0;
483    while (possibleConstraints.length>0) {
484        let nextPossibleConstraints = new BigArray();
485        for (let i=0; i<possibleConstraints.length; i++) {
486            ii++;
487            if ((ctx.verbose)&&(ii%10000 == 0)) console.log("reducing constraints: ", i);
488            if (!ctx.constraints[i]) continue;
489            const c = ctx.constraints[i];
490
491            // Swap a and b if b has more variables.
492            if (Object.keys(c.b).length > Object.keys(c.a).length) {
493                const aux = c.a;
494                c.a=c.b;
495                c.b=aux;
496            }
497
498            // Mov to C if possible.
499            if (isConstant(c.a)) {
500                const ct = {t: "N", v: c.a.coefs[sONE]};
501                c.c = ctx.lc.add(ctx.lc.mul(c.b, ct), c.c);
502                c.a = { t: "LC", coefs: {} };
503                c.b = { t: "LC", coefs: {} };
504            }
505            if (isConstant(c.b)) {
506                const ct = {t: "N", v: c.b.coefs[sONE]};
507                c.c = ctx.lc.add(ctx.lc.mul(c.a, ct), c.c);
508                c.a = { t: "LC", coefs: {} };
509                c.b = { t: "LC", coefs: {} };
510            }
511
512            if (ctx.lc.isZero(c.a) || ctx.lc.isZero(c.b)) {
513                const isolatedSignal = getFirstInternalSignal(ctx, c.c);
514                if (isolatedSignal) {
515
516                    let lSignal = ctx.signals[isolatedSignal];
517                    while (lSignal.e>=0) {
518                        lSignal = ctx.signals[lSignal.e];
519                    }
520
521
522                    const isolatedSignalEquivalence = {
523                        t: "LC",
524                        coefs: {}
525                    };
526                    const invCoef = ctx.F.inv(c.c.coefs[isolatedSignal]);
527                    for (const s in c.c.coefs) {
528                        if (s != isolatedSignal) {
529                            const v = ctx.F.mul( ctx.F.neg(c.c.coefs[s]), invCoef);
530                            if (!ctx.F.isZero(v)) {
531                                isolatedSignalEquivalence.coefs[s] = v;
532                            }
533                        }
534                    }
535
536                    for (let j in lSignal.inConstraints) {
537                        if ((j!=i)&&(ctx.constraints[j])) {
538                            ctx.constraints[j] = ctx.lc.substitute(ctx.constraints[j], isolatedSignal, isolatedSignalEquivalence);
539                            linkSignalsConstraint(j);
540                            if (j<i) {
541                                nextPossibleConstraints.push(j);
542                            }
543                        }
544                    }
545
546                    ctx.constraints[i] = null;
547
548                    lSignal.c = ctx.stDISCARDED;
549                } else {
550                    if (ctx.lc.isZero(c.c)) ctx.constraints[i] = null;
551                }
552            }
553        }
554        possibleConstraints = nextPossibleConstraints;
555    }
556    unindexVariables();
557
558    // Pack the constraints
559    let o = 0;
560    for (let i=0; i<ctx.constraints.length; i++) {
561        if (ctx.constraints[i]) {
562            if (o != i) {
563                ctx.constraints[o] = ctx.constraints[i];
564            }
565            o++;
566        }
567    }
568    ctx.constraints.length = o;
569
570    function indexVariables() {
571        for (let i=0; i<ctx.constraints.length; i++) linkSignalsConstraint(i);
572    }
573
574    function linkSignalsConstraint(cidx) {
575        const ct = ctx.constraints[cidx];
576        for (let k in ct.a.coefs) linkSignal(k, cidx);
577        for (let k in ct.b.coefs) linkSignal(k, cidx);
578        for (let k in ct.c.coefs) linkSignal(k, cidx);
579    }
580
581    function unindexVariables() {
582        for (let s=0; s<ctx.signals.length; s++) {
583            let lSignal = ctx.signals[s];
584            while (lSignal.e>=0) {
585                lSignal = ctx.signals[lSignal.e];
586            }
587            if (lSignal.inConstraints) delete lSignal.inConstraints;
588        }
589    }
590
591/*
592    function unlinkSignal(signalName, cidx) {
593        let lSignal = ctx.signals[signalName];
594        while (lSignal.e>=0) {
595            lSignal = ctx.signals[lSignal.e];
596        }
597        if ((lSignal.inConstraints)&&(lSignal.inConstraints[cidx])) {
598            delete lSignal.inConstraints[cidx];
599        }
600    }
601*/
602
603    function linkSignal(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 = {};
609        lSignal.inConstraints[cidx] = true;
610    }
611
612    function getFirstInternalSignal(ctx, l) {
613        for (let k in l.coefs) {
614            const signal = ctx.signals[k];
615            if (signal.c == ctx.stINTERNAL) return k;
616        }
617        return null;
618    }
619
620    function isConstant(l) {
621        for (let k in l.coefs) {
622            if ((k != sONE) && (!ctx.F.isZero(l.coefs[k]))) return false;
623        }
624        if (!l.coefs[sONE] || ctx.F.isZero(l.coefs[sONE])) return false;
625        return true;
626    }
627
628}
629
630/*
631
632function buildCircuitDef(ctx, mainCode) {
633    const res = {
634        mainCode: mainCode
635    };
636    res.signalName2Idx = ctx.signalName2Idx;
637
638    res.components = [];
639    res.componentName2Idx = {};
640    for (let c in ctx.components) {
641        const idCoponent = res.components.length;
642        res.components.push({
643            name: c,
644            params: ctx.components[c].params,
645            template: ctx.components[c].template,
646            inputSignals: 0
647        });
648        res.componentName2Idx[c] = idCoponent;
649    }
650
651    res.signals = new Array(ctx.signalNames.length);
652    for (let i=0; i<ctx.signalNames.length; i++) {
653        res.signals[i] = {
654            names: ctx.signalNames[i],
655            triggerComponents: []
656        };
657        ctx.signalNames[i].map( (fullName) => {
658            const idComponet = res.componentName2Idx[ctx.signals[fullName].component];
659            if (ctx.signals[fullName].direction == "IN") {
660                res.signals[i].triggerComponents.push(idComponet);
661                res.components[idComponet].inputSignals++;
662            }
663        });
664    }
665
666    res.constraints = buildConstraints(ctx);
667
668    res.templates = ctx.templates;
669
670    res.functions = {};
671    for (let f in ctx.functions) {
672        res.functions[f] = {
673            params: ctx.functionParams[f],
674            func: ctx.functions[f]
675        };
676    }
677
678    res.nPrvInputs = ctx.totals.prvInput;
679    res.nPubInputs = ctx.totals.pubInput;
680    res.nInputs = res.nPrvInputs + res.nPubInputs;
681    res.nOutputs = ctx.totals.output;
682    res.nVars = res.nInputs + res.nOutputs + ctx.totals.one + ctx.totals.internal;
683    res.nConstants = ctx.totals.constant;
684    res.nSignals = res.nVars + res.nConstants;
685
686    return res;
687}
688
689*/
690
691
692/*
693    Build constraints
694
695A constraint like this
696
697      [s1 + 2*s2 + 3*s3] * [ s2 + 5*s4] - [s0        ] = 0
698      [     5*s2 + 6*s3] * [ s2 +     ] - [s0 + 2* s2] = 0
699      [s1 +          s3] * [ s2 + 5*s3] - [s4        ] = 0
700
701is converted to
702
703[
704    [{"1":"1","2":"2","3":"3"} , {"2":"1","4":"5"} , {"0":"1"         }],
705    [{        "2":"5","3":"6"} , {"2":"1"        } , {"0":"1", "2":"2"}],
706    [{"1":"1",        "3":"1"} , {"2":"1","3":"5"} , {"4":"1"         }]
707]
708           ^                            ^                  ^
709           |                            |                  |
710           A                            B                  C
711
712*/
713/*
714function buildConstraints(ctx) {
715    const res = [];
716
717    function fillLC(dst, src) {
718        if (src.t != "LC") throw new Error("Constraint is not a LINEARCOMBINATION");
719        for (let s in src.coefs) {
720            const v = src.coefs[s].toString();
721            const id = ctx.signalName2Idx[s];
722            dst[id] = v;
723        }
724    }
725
726    for (let i=0; i<ctx.constraints.length; i++) {
727        const A = {};
728        const B = {};
729        const C = {};
730
731        fillLC(A, ctx.constraints[i].a);
732        fillLC(B, ctx.constraints[i].b);
733        fillLC(C, ctx.lc.negate(ctx.constraints[i].c));
734
735        res.push([A,B,C]);
736    }
737
738    return res;
739}
740*/
741
742/*
743function buildSyms(ctx, strm) {
744
745    let nSyms;
746
747    addSymbolsComponent(ctx.mainComponent + ".", ctx.getComponentIdx(ctx.mainComponent));
748
749
750    function addSymbolsComponent(prefix, idComponet) {
751        for (let n in  ctx.components[idComponet].names.o) {
752            const entrie = ctx.components[idComponet].names.o[n];
753            addSymbolArray(prefix+n, entrie.type, entrie.sizes, entrie.offset);
754        }
755    }
756
757    function addSymbolArray(prefix, type, sizes, offset) {
758        if (sizes.length==0) {
759            if (type == "S") {
760                let s=offset;
761                while (ctx.signals[s].e >= 0) s = ctx.signals[s].e;
762                let wId = ctx.signals[s].id;
763                if (typeof(wId) == "undefined") wId=-1;
764                strm.write(`${offset},${wId},${prefix}\n`);
765                nSyms ++;
766                if ((ctx.verbose)&&(nSyms%10000 == 0)) console.log("Symbols saved: "+nSyms);
767            } else {
768                addSymbolsComponent(prefix+".", offset);
769            }
770            return 1;
771        } else {
772            let acc = 0;
773            for (let i=0; i<sizes[0]; i++) {
774                acc += addSymbolArray(`${prefix}[${i}]`, type, sizes.slice(1), offset + acc );
775            }
776            return acc;
777        }
778    }
779
780}
781
782*/
783