arnaucube
arnaucube/circomPublic Self-hosted repository
circom/ports/c/builder.js
ports/c/builder.jsRaw
  1const utils = require("../../src/utils");
  2const assert = require("assert");
  3const Scalar = require("ffjavascript").Scalar;
  4const F1Field = require("ffjavascript").F1Field;
  5const BigArray = require("../../src/bigarray");
  6
  7function ref2src(c) {
  8    if ((c[0] == "R")||(c[0] == "RI")) {
  9        return c[1];
 10    } else if (c[0] == "V") {
 11        return c[1].toString();
 12    } else if (c[0] == "C") {
 13        return `(ctx->circuit->constants + ${c[1]})`;
 14    } else if (c[0] == "CC") {
 15        return "__cIdx";
 16    } else {
 17        assert(false);
 18    }
 19}
 20
 21class CodeBuilderC {
 22    constructor() {
 23        this.ops = [];
 24    }
 25
 26    addComment(comment) {
 27        this.ops.push({op: "COMMENT", comment});
 28    }
 29
 30    addBlock(block) {
 31        this.ops.push({op: "BLOCK", block});
 32    }
 33
 34    calcOffset(dLabel, offsets) {
 35        this.ops.push({op: "CALCOFFSETS", dLabel, offsets});
 36    }
 37
 38    assign(dLabel, src, sOffset) {
 39        this.ops.push({op: "ASSIGN", dLabel, src, sOffset});
 40    }
 41
 42    getSubComponentOffset(dLabel, component, hash, hashLabel) {
 43        this.ops.push({op: "GETSUBCOMPONENTOFFSET", dLabel, component, hash, hashLabel});
 44    }
 45
 46    getSubComponentSizes(dLabel, component, hash, hashLabel) {
 47        this.ops.push({op: "GETSUBCOMPONENTSIZES", dLabel, component, hash, hashLabel});
 48    }
 49
 50    getSignalOffset(dLabel, component, hash, hashLabel) {
 51        this.ops.push({op: "GETSIGNALOFFSET", dLabel, component, hash, hashLabel});
 52    }
 53
 54    getSignalSizes(dLabel, component, hash, hashLabel) {
 55        this.ops.push({op: "GETSIGNALSIZES", dLabel, component, hash, hashLabel});
 56    }
 57
 58    setSignal(component, signal, value) {
 59        this.ops.push({op: "SETSIGNAL", component, signal, value});
 60    }
 61
 62    getSignal(dLabel, component, signal, n) {
 63        if (typeof(n) == "undefined") n=1;
 64        this.ops.push({op: "GETSIGNAL", dLabel, component, signal, n});
 65    }
 66
 67    copyN(dLabel, offset, src, n) {
 68        this.ops.push({op: "COPYN", dLabel, offset, src, n});
 69    }
 70
 71    copyNRet(src, n) {
 72        this.ops.push({op: "COPYNRET", src, n});
 73    }
 74
 75    fieldOp(dLabel, fOp, params) {
 76        this.ops.push({op: "FOP", dLabel, fOp, params});
 77    }
 78
 79    ret() {
 80        this.ops.push({op: "RET"});
 81    }
 82
 83    addLoop(condLabel, body) {
 84        this.ops.push({op: "LOOP", condLabel, body});
 85    }
 86
 87    addIf(condLabel, thenCode, elseCode) {
 88        this.ops.push({op: "IF", condLabel, thenCode, elseCode});
 89    }
 90
 91    fnCall(fnName, retLabel, params) {
 92        this.ops.push({op: "FNCALL", fnName, retLabel, params});
 93    }
 94
 95    checkConstraint(a, b, strErr) {
 96        this.ops.push({op: "CHECKCONSTRAINT", a, b, strErr});
 97    }
 98
 99    checkAssert(a, strErr) {
100        this.ops.push({op: "CHECKASSERT", a, strErr});
101    }
102
103    log(val) {
104        this.ops.push({op: "LOG", val});
105    }
106
107    concat(cb) {
108        this.ops.push(...cb.ops);
109    }
110
111    hasCode() {
112        for (let i=0; i<this.ops.length; i++) {
113            if (this.ops[i].op != "COMMENT") return true;
114        }
115        return false;
116    }
117
118    _buildOffset(offsets) {
119        let rN=0;
120        let S = "";
121        offsets.forEach((o) => {
122            if ((o[0][0] == "V") && (o[1][0]== "V")) {
123                rN += o[0][1]*o[1][1];
124                return;
125            }
126            let f="";
127            if (o[0][0] == "V") {
128                if (o[0][1]==0) return;
129                f += o[0][1];
130            } else if (o[0][0] == "RI") {
131                if (o[0][1]==0) return;
132                f += o[0][1];
133            } else if (o[0][0] == "R") {
134                f += `Fr_toInt(${o[0][1]})`;
135            } else {
136                assert(false);
137            }
138            if (o[1][0] == "V") {
139                if (o[1][1]==0) return;
140                if (o[1][1]>1) {
141                    f += "*" + o[1][1];
142                }
143            } else if (o[1][0] == "RS") {
144                f += `*${o[1][1]}[${o[1][2]}]`;
145            } else {
146                assert(false);
147            }
148            if (S!="") S+= " + ";
149            S += f;
150        });
151        if (rN>0) {
152            S = `${rN} + ${S}`;
153        }
154        return S;
155    }
156
157    build(code) {
158        this.ops.forEach( (o) => {
159            if (o.op == "COMMENT") {
160                code.push(`/* ${o.comment} */`);
161            } else if (o.op == "BLOCK") {
162                const codeBlock=[];
163                o.block.build(codeBlock);
164                code.push(utils.ident(codeBlock));
165            } else if (o.op == "CALCOFFSETS") {
166                code.push(`${o.dLabel} = ${this._buildOffset(o.offsets)};`);
167            } else if (o.op == "ASSIGN") {
168                const oS = ref2src(o.sOffset);
169                if (oS != "0") {
170                    code.push(`${o.dLabel} = ${ref2src(o.src)} + ${oS};`);
171                } else {
172                    code.push(`${o.dLabel} = ${ref2src(o.src)};`);
173                }
174            } else if (o.op == "GETSUBCOMPONENTOFFSET") {
175                code.push(`${o.dLabel} = ctx->getSubComponentOffset(${ref2src(o.component)}, 0x${o.hash}LL /* ${o.hashLabel} */);`);
176            } else if (o.op == "GETSUBCOMPONENTSIZES") {
177                code.push(`${o.dLabel} = ctx->getSubComponentSizes(${ref2src(o.component)}, 0x${o.hash}LL /* ${o.hashLabel} */);`);
178            } else if (o.op == "GETSIGNALOFFSET") {
179                code.push(`${o.dLabel} = ctx->getSignalOffset(${ref2src(o.component)}, 0x${o.hash}LL /* ${o.hashLabel} */);`);
180            } else if (o.op == "GETSIGNALSIZES") {
181                code.push(`${o.dLabel} = ctx->getSignalSizes(${ref2src(o.component)}, 0x${o.hash}LL /* ${o.hashLabel} */);`);
182            } else if (o.op == "SETSIGNAL") {
183                code.push(`ctx->setSignal(__cIdx, ${ref2src(o.component)}, ${ref2src(o.signal)}, ${ref2src(o.value)});`);
184            } else if (o.op == "GETSIGNAL") {
185                code.push(`ctx->multiGetSignal(__cIdx, ${ref2src(o.component)}, ${ref2src(o.signal)}, ${o.dLabel}, ${o.n});`);
186            } else if (o.op == "COPYN") {
187                const oS = ref2src(o.offset);
188                const dLabel = (oS != "0") ? (o.dLabel + "+" + oS) : o.dLabel;
189                code.push(`Fr_copyn(${dLabel}, ${ref2src(o.src)}, ${o.n});`);
190            } else if (o.op == "COPYNRET") {
191                code.push(`Fr_copyn(__retValue, ${ref2src(o.src)}, ${o.n});`);
192            } else if (o.op == "RET") {
193                code.push("goto returnFunc;");
194            } else if (o.op == "FOP") {
195                let paramsS = "";
196                for (let i=0; i<o.params.length; i++) {
197                    if (i>0) paramsS += ", ";
198                    paramsS += ref2src(o.params[i]);
199                }
200                code.push(`Fr_${o.fOp}(${o.dLabel}, ${paramsS});`);
201            } else if (o.op == "LOOP") {
202                code.push(`while (Fr_isTrue(${o.condLabel})) {`);
203                const body = [];
204                o.body.build(body);
205                code.push(utils.ident(body));
206                code.push("}");
207            } else if (o.op == "IF") {
208                code.push(`if (Fr_isTrue(${o.condLabel})) {`);
209                const thenCode = [];
210                o.thenCode.build(thenCode);
211                code.push(utils.ident(thenCode));
212                if (o.elseCode) {
213                    code.push("} else {");
214                    const elseCode = [];
215                    o.elseCode.build(elseCode);
216                    code.push(utils.ident(elseCode));
217                }
218                code.push("}");
219            } else if (o.op == "FNCALL") {
220                code.push(`${o.fnName}(ctx, ${o.retLabel}, ${o.params.join(",")});`);
221            } else if (o.op == "CHECKCONSTRAINT") {
222                code.push(`ctx->checkConstraint(__cIdx, ${ref2src(o.a)}, ${ref2src(o.b)}, "${o.strErr}");`);
223            } else if (o.op == "CHECKASSERT") {
224                code.push(`ctx->checkAssert(__cIdx, ${ref2src(o.a)}, "${o.strErr}");`);
225            } else if (o.op == "LOG") {
226                code.push(`ctx->log(${ref2src(o.val)});`);
227            }
228        });
229    }
230}
231
232class FunctionBuilderC {
233
234    constructor(name, instanceDef, type) {
235        this.name = name;
236        this.instanceDef = instanceDef;
237        this.type = type; // "COMPONENT" or "FUNCTIOM"
238        this.definedFrElements = [];
239        this.definedIntElements = [];
240        this.definedSizeElements = [];
241        this.definedPFrElements = [];
242        this.initializedElements = [];
243        this.initializedSignalOffset = [];
244        this.initializedSignalSizes = [];
245
246    }
247
248    defineFrElements(dLabel, size) {
249        this.definedFrElements.push({dLabel, size});
250    }
251
252    defineIntElement(dLabel) {
253        this.definedIntElements.push({dLabel});
254    }
255
256    defineSizesElement(dLabel) {
257        this.definedSizeElements.push({dLabel});
258    }
259
260    definePFrElement(dLabel) {
261        this.definedPFrElements.push({dLabel});
262    }
263
264    initializeFrElement(dLabel, offset, idConstant) {
265        this.initializedElements.push({dLabel, offset, idConstant});
266    }
267
268    initializeSignalOffset(dLabel, component, hash, hashLabel) {
269        this.initializedSignalOffset.push({dLabel, component, hash, hashLabel});
270    }
271
272    initializeSignalSizes(dLabel, component, hash, hashLabel) {
273        this.initializedSignalSizes.push({dLabel, component, hash, hashLabel});
274    }
275
276    setParams(params) {
277        this.params = params;
278    }
279
280    _buildHeader(code) {
281        this.definedFrElements.forEach( (o) => {
282            code.push(`FrElement ${o.dLabel}[${o.size}];`);
283        });
284        this.definedIntElements.forEach( (o) => {
285            code.push(`int ${o.dLabel};`);
286        });
287        this.definedSizeElements.forEach( (o) => {
288            code.push(`Circom_Sizes ${o.dLabel};`);
289        });
290        this.definedPFrElements.forEach( (o) => {
291            code.push(`PFrElement ${o.dLabel};`);
292        });
293        this.initializedElements.forEach( (o) => {
294            code.push(`Fr_copy(&(${o.dLabel}[${o.offset}]), ctx->circuit->constants +${o.idConstant});`);
295        });
296        this.initializedSignalOffset.forEach( (o) => {
297            code.push(`${o.dLabel} = ctx->getSignalOffset(${ref2src(o.component)}, 0x${o.hash}LL /* ${o.hashLabel} */);`);
298        });
299        this.initializedSignalSizes.forEach( (o) => {
300            code.push(`${o.dLabel} = ctx->getSignalSizes(${ref2src(o.component)}, 0x${o.hash}LL /* ${o.hashLabel} */);`);
301        });
302    }
303
304    _buildFooter(code) {
305    }
306
307    newCodeBuilder() {
308        return new CodeBuilderC();
309    }
310
311    setBody(body) {
312        this.body = body;
313    }
314
315    build(code) {
316        code.push(
317            "/*",
318            this.instanceDef,
319            "*/"
320        );
321
322        if (this.type=="COMPONENT") {
323            code.push(`void ${this.name}(Circom_CalcWit *ctx, int __cIdx) {`);
324        } else if (this.type=="FUNCTION") {
325            let sParams = "";
326            for (let i=0;i<this.params.length;i++ ) sParams += `, PFrElement ${this.params[i]}`;
327            code.push(`void ${this.name}(Circom_CalcWit *ctx, PFrElement __retValue ${sParams}) {`);
328        } else {
329            assert(false);
330        }
331
332        const fnCode = [];
333        this._buildHeader(fnCode);
334        this.body.build(fnCode);
335        if (this.type=="COMPONENT") {
336            fnCode.push("ctx->finished(__cIdx);");
337        } else if (this.type=="FUNCTION") {
338            fnCode.push("returnFunc: ;");
339        } else {
340            assert(false);
341        }
342        this._buildFooter(fnCode);
343
344        code.push(utils.ident(fnCode));
345        code.push("}");
346    }
347
348}
349
350class BuilderC {
351    constructor(p, verbose) {
352        this.F = new F1Field(p);
353
354        this.hashMaps={};
355        this.componentEntriesTables=new BigArray();
356        this.sizes ={};
357        this.constants = [];
358        this.functions = [];
359        this.components = new BigArray();
360        this.usedConstants = {};
361        this.verbose = verbose;
362
363
364        this.sizePointers = {};
365        this.hashMapPointers = {};
366        this.functionIdx = {};
367        this.nCets = 0;
368    }
369
370    setHeader(header) {
371        this.header=header;
372    }
373
374    // ht is an array of 256 element that can be undefined or [Hash, Idx, KeyName] elements.
375    addHashMap(name, hm) {
376        this.hashMaps[name] = hm;
377    }
378
379    addComponentEntriesTable(name, cet, idComponent) {
380        this.componentEntriesTables[idComponent] = {
381            name: name,
382            cet: cet
383        };
384    }
385
386    addSizes(name, accSizes) {
387        this.sizes[name] = accSizes;
388    }
389
390    addConstant(c) {
391        c = this.F.e(c);
392        const cS = c.toString();
393        if (typeof this.usedConstants[cS] != "undefined") return this.usedConstants[cS];
394        this.constants.push(c);
395        this.usedConstants[cS] = this.constants.length - 1;
396        return this.constants.length - 1;
397    }
398
399    addFunction(fnBuilder) {
400        this.functions.push(fnBuilder);
401    }
402
403    addComponent(component) {
404        this.components.push(component);
405    }
406
407    setMapIsInput(map) {
408        this.mapIsInput = map;
409    }
410
411    setWit2Sig(wit2sig) {
412        this.wit2sig = wit2sig;
413    }
414
415
416    newComponentFunctionBuilder(name, instanceDef) {
417        return new FunctionBuilderC(name, instanceDef, "COMPONENT");
418    }
419
420    newFunctionBuilder(name, instanceDef) {
421        return new FunctionBuilderC(name, instanceDef, "FUNCTION");
422    }
423
424
425    // Body functions
426
427    _buildHeader(code) {
428        code.push(
429            "#include \"circom.hpp\"",
430            "#include \"calcwit.hpp\"",
431            `#define NSignals ${this.header.NSignals}`,
432            `#define NComponents ${this.header.NComponents}`,
433            `#define NOutputs ${this.header.NOutputs}`,
434            `#define NInputs ${this.header.NInputs}`,
435            `#define NVars ${this.header.NVars}`,
436            `#define NPublic ${this.header.NPublic}`,
437            `#define __P__ "${this.header.P.toString()}"`,
438            ""
439        );
440    }
441
442    async _buildHashMaps(fdData) {
443
444        while (fdData.pos % 8) fdData.pos++;
445        this.pHashMaps = fdData.pos;
446
447        const buff = new Uint8Array(256*12);
448        const buffV = new DataView(buff.buffer);
449        for (let hmName in this.hashMaps ) {
450
451            while (fdData.pos % 8) fdData.pos++;
452            this.hashMapPointers[hmName] = fdData.pos;
453            const hm = this.hashMaps[hmName];
454
455            for (let i=0; i<256; i++) {
456                buffV.setUint32(i*12, hm[i] ? parseInt( hm[i][0].slice(8), 16 ) : 0, true);
457                buffV.setUint32(i*12+4, hm[i] ? parseInt( hm[i][0].slice(0,8), 16 ) : 0, true);
458                buffV.setUint32(i*12+8, hm[i] ? hm[i][1] : 0, true);
459            }
460
461            await fdData.write(buff);
462        }
463
464    }
465
466    async _buildComponentEntriesTables(fdData) {
467
468        while (fdData.pos % 8) fdData.pos++;
469        this.pCets = fdData.pos;
470        for (let i=0; i< this.componentEntriesTables.length; i++) {
471            if ((this.verbose)&&(i%100000 ==0)) console.log(`_buildComponentEntriesTables ${i}/${this.componentEntriesTables.length}`);
472            const cet = this.componentEntriesTables[i].cet;
473
474            this.components[i].entryTablePointer = fdData.pos;
475            const buff = new Uint8Array(16*cet.length);
476            const buffV = new DataView(buff.buffer);
477
478            for (let j=0; j<cet.length; j++) {
479                utils.setUint64(buffV, 16*j+0, this.sizePointers[ cet[j].sizeName]);
480                buffV.setUint32(16*j+8, cet[j].offset, true);
481                buffV.setUint32(16*j+12, cet[j].type == "S" ? 0 : 1, true);  // Size type 0-> Signal, 1->Component
482                this.nCets ++;
483            }
484
485            await fdData.write(buff);
486
487        }
488    }
489
490    async _buildSizes(fdData) {
491        for (let sName in this.sizes) {
492            const accSizes = this.sizes[sName];
493
494            while (fdData.pos % 8) fdData.pos++;
495            this.sizePointers[sName] = fdData.pos;
496
497            const buff = new Uint8Array(4*accSizes.length);
498            const buffV = new DataView(buff.buffer);
499            for (let i=0; i<accSizes.length; i++) {
500                buffV.setUint32(i*4, accSizes[i], true);
501            }
502            await fdData.write(buff);
503        }
504    }
505
506
507    async _buildConstants(fdData) {
508        const self = this;
509
510        const frSize = (8 + self.F.n64*8);
511        const buff = new Uint8Array(self.constants.length* frSize);
512        const buffV = new DataView(buff.buffer);
513
514
515        while (fdData.pos % 8) fdData.pos++;
516        this.pConstants = fdData.pos;
517
518        let o = 0;
519        for (let i=0; i<self.constants.length; i++) {
520            Fr2Bytes(buffV, o, self.constants[i]);
521            o += frSize;
522        }
523        await fdData.write(buff);
524
525
526        function Fr2Bytes(buffV, offset, n) {
527            const minShort = self.F.neg(self.F.e("80000000"));
528            const maxShort = self.F.e("7FFFFFFF", 16);
529
530            if (  (self.F.geq(n, minShort))
531                &&(self.F.leq(n, maxShort)))
532            {
533                if (self.F.geq(n, self.F.zero)) {
534                    return shortMontgomeryPositive(n);
535                } else {
536                    return shortMontgomeryNegative(n);
537                }
538            }
539
540            return longMontgomery(n);
541
542
543            function shortMontgomeryPositive(a) {
544                buffV.setUint32(offset, Scalar.toNumber(a) , true );
545                buffV.setUint32(offset + 4, 0x40000000 , true );
546                long(buffV, offset + 8, toMontgomery(a));
547            }
548
549
550            function shortMontgomeryNegative(a) {
551                const b = -Scalar.toNumber(self.F.neg(a));
552                buffV.setUint32(offset, b , true );
553                buffV.setUint32(offset + 4, 0x40000000 , true );
554                long(buffV, offset + 8, toMontgomery(a));
555            }
556
557            function longMontgomery(a) {
558                buffV.setUint32(offset, 0 , true );
559                buffV.setUint32(offset + 4, 0xC0000000 , true );
560                long(buffV, offset + 8, toMontgomery(a));
561            }
562
563            function long(buffV, offset, a) {
564
565                let p = offset;
566                const arr = Scalar.toArray(a, 0x100000000);
567                for (let i=0; i<self.F.n64*2; i++) {
568                    const idx = arr.length-1-i;
569
570                    if ( idx >=0) {
571                        buffV.setUint32(p, arr[idx], true);
572                    } else {
573                        buffV.setUint32(p, 0, true);
574                    }
575                    p+= 4;
576                }
577            }
578
579            function toMontgomery(a) {
580                return self.F.mul(a, self.F.R);
581            }
582
583        }
584
585    }
586
587    _buildFunctions(code) {
588        const listedFunctions = [];
589        for (let i=0; i<this.functions.length; i++) {
590            const cfb = this.functions[i];
591            cfb.build(code);
592            if (this.functions[i].type == "COMPONENT") {
593                this.functionIdx[this.functions[i].name] = listedFunctions.length;
594                listedFunctions.push(i);
595            }
596        }
597
598        code.push("// Function Table");
599        code.push(`Circom_ComponentFunction _functionTable[${listedFunctions.length}] = {`);
600        for (let i=0; i<listedFunctions.length; i++) {
601            const sep = i>0 ? "    ," : "     ";
602            code.push(`${sep}${this.functions[listedFunctions[i]].name}`);
603        }
604        code.push("};");
605    }
606
607
608    async _buildComponents(fdData) {
609
610        const buff = new Uint8Array(32);
611        const buffV = new DataView(buff.buffer);
612
613        while (fdData.pos % 8) fdData.pos++;
614        this.pComponents = fdData.pos;
615
616        for (let i=0; i<this.components.length; i++) {
617            if ((this.verbose)&&(i%1000000 ==0)) console.log(`_buildComponents ${i}/${this.components.length}`);
618            const c = this.components[i];
619
620            utils.setUint64(buffV, 0, this.hashMapPointers[c.hashMapName], true);
621            utils.setUint64(buffV, 8, c.entryTablePointer, true);
622            utils.setUint64(buffV, 16, this.functionIdx[c.functionName], true);
623            buffV.setUint32(24, c.nInSignals, true);
624            buffV.setUint32(28, c.newThread ? 1 : 0, true);
625
626            await fdData.write(buff);
627        }
628    }
629
630    async _buildMapIsInput(fdData) {
631
632        const buff = new Uint8Array(this.mapIsInput.length * 4);
633        const buffV = new DataView(buff.buffer);
634
635        while (fdData.pos % 8) fdData.pos++;
636        this.pMapIsInput = fdData.pos;
637
638        for (let i=0; i<this.mapIsInput.length; i++) {
639            if ((this.verbose)&&(i%1000000 ==0)) console.log(`_buildMapIsInput ${i}/${this.mapIsInput.length}`);
640
641            buffV.setUint32(4*i, this.mapIsInput[i], true);
642        }
643
644        await fdData.write(buff);
645    }
646
647    async _buildWit2Sig(fdData) {
648
649        const buff = new Uint8Array(this.wit2sig.length * 4);
650        const buffV = new DataView(buff.buffer);
651
652        while (fdData.pos % 8) fdData.pos++;
653        this.pWit2Sig = fdData.pos;
654
655        for (let i=0; i<this.wit2sig.length; i++) {
656            if ((this.verbose)&&(i%1000000 ==0)) console.log(`_buildWit2Sig ${i}/${this.wit2sig.length}`);
657
658            buffV.setUint32(4*i, this.wit2sig[i], true);
659        }
660
661        await fdData.write(buff);
662    }
663
664    async _buildCircuitVar(fdData) {
665
666        const buff = new Uint8Array(76);
667        const buffV = new DataView(buff.buffer);
668
669        utils.setUint64(buffV, 0, this.pWit2Sig, true);
670        utils.setUint64(buffV, 8, this.pComponents, true);
671        utils.setUint64(buffV, 16, this.pMapIsInput, true);
672        utils.setUint64(buffV, 24, this.pConstants, true);
673        utils.setUint64(buffV, 32, this.pPriemStr, true);
674        utils.setUint64(buffV, 40, this.pCets, true);
675
676        buffV.setUint32(48, this.header.NSignals, true);
677        buffV.setUint32(52, this.header.NComponents, true);
678        buffV.setUint32(56, this.header.NOutputs, true);
679        buffV.setUint32(60, this.header.NInputs, true);
680        buffV.setUint32(64, this.header.NVars, true);
681        buffV.setUint32(68, this.nCets, true);
682        buffV.setUint32(72, this.header.NPublic, true);
683
684        fdData.pos = 0;
685
686        await fdData.write(buff);
687    }
688
689    async _buildPrimeStr(fdData) {
690        this.pPriemStr = fdData.pos;
691        const strBuff = new TextEncoder("utf-8").encode(this.header.P.toString());
692        await fdData.write(strBuff);
693
694        const zB = new Uint8Array(1);
695        zB[0] =0;
696        await fdData.write(zB);
697    }
698
699
700    async build(fdCode, fdData) {
701        const encoder = new TextEncoder("utf-8");
702        fdData.pos = 76;
703        while (fdData.pos % 8) fdData.pos++;
704
705        const code=new BigArray();
706        this._buildHeader(code);
707        await this._buildPrimeStr(fdData);
708        await this._buildSizes(fdData);
709        await this._buildConstants(fdData);
710        await this._buildHashMaps(fdData);
711        await this._buildComponentEntriesTables(fdData);
712        this._buildFunctions(code);
713        await this._buildComponents(fdData);
714        await this._buildMapIsInput(fdData);
715        await this._buildWit2Sig(fdData);
716        await this._buildCircuitVar(fdData);
717        await writeCode(code);
718
719        async function writeCode(c) {
720            if (c.push) {
721                for (let i=0; i<c.length; i++) {
722                    await writeCode(c[i]);
723                }
724            } else if (typeof c === "string") {
725                await fdCode.write(encoder.encode(c + "\n"));
726            }
727        }
728    }
729}
730
731
732module.exports = BuilderC;