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