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