circom/ports/wasm/build_runtime.js
ports/wasm/build_runtime.jsRaw
1const errs = require("./errs");
2
3
4const buildWasmFf = require("ffwasm").buildWasmFf;
5
6
7module.exports = function buildRuntime(module, builder) {
8
9 const pSanityCheck = module.alloc(4);
10
11 function buildInit() {
12 const f = module.addFunction("init");
13 f.addParam("sanityCheck", "i32");
14 f.addLocal("i", "i32");
15
16 const c = f.getCodeBuilder();
17
18 // Set the stack to current memory
19 f.addCode(
20 c.i32_store(
21 c.i32_const(4),
22 c.i32_shl(
23 c.i32_and(
24 c.current_memory(),
25 c.i32_const(0xFFFFFFF8)
26 ),
27 c.i32_const(16)
28 )
29 )
30 );
31
32 // Save Sanity check flag
33 f.addCode(
34 c.i32_store(
35 c.i32_const(pSanityCheck),
36 c.getLocal("sanityCheck")
37 )
38 );
39
40 f.addCode(
41 // i=0
42 c.setLocal("i", c.i32_const(0)),
43 c.block(c.loop(
44 // if (i==NComponents) break
45 c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NComponents))),
46
47 // inputSignalsToTrigger[i] = components[i].nInputSignals
48 c.i32_store(
49 c.i32_add(
50 c.i32_const(builder.pInputSignalsToTrigger),
51 c.i32_mul(
52 c.getLocal("i"),
53 c.i32_const(4)
54 )
55 ),
56 c.i32_load(
57 c.i32_add(
58 c.i32_load(c.i32_const(builder.ppComponents)),
59 c.i32_mul(
60 c.getLocal("i"),
61 c.i32_const(builder.sizeofComponent) // Sizeof component
62 )
63 ),
64 builder.offsetComponentNInputSignals
65 )
66 ),
67
68 // i=i+1
69 c.setLocal(
70 "i",
71 c.i32_add(
72 c.getLocal("i"),
73 c.i32_const(1)
74 )
75 ),
76 c.br(0)
77 ))
78 );
79
80 f.addCode(ifSanityCheck(c,
81 // i=0
82 c.setLocal("i", c.i32_const(0)),
83 c.block(c.loop(
84 // if (i==NSignals) break
85 c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NSignals))),
86
87 // signalsAssigned[i] = false
88 c.i32_store(
89 c.i32_add(
90 c.i32_const(builder.pSignalsAssigned),
91 c.i32_mul(
92 c.getLocal("i"),
93 c.i32_const(4)
94 )
95 ),
96 c.i32_const(0)
97 ),
98
99 // i=i+1
100 c.setLocal(
101 "i",
102 c.i32_add(
103 c.getLocal("i"),
104 c.i32_const(1)
105 )
106 ),
107 c.br(0)
108 ))
109 ));
110
111 f.addCode(
112 c.call(
113 "Fr_copy",
114 c.i32_const(builder.pSignals),
115 c.i32_add(
116 c.i32_load(c.i32_const(builder.ppConstants)),
117 c.i32_const(builder.addConstant(1) * builder.sizeFr)
118 )
119 )
120 );
121 f.addCode(ifSanityCheck(c,
122 c.i32_store(
123 c.i32_const(builder.pSignalsAssigned),
124 c.i32_const(1)
125 )
126 ));
127
128 f.addCode(
129 // i=0
130 c.setLocal("i", c.i32_const(0)),
131 c.block(c.loop(
132 // if (i==NComponents) break
133 c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NComponents))),
134
135 // if (inputSignalsToTrigger[i] == 0) triggerComponent(i)
136 c.if(
137 c.i32_eqz(
138 c.i32_load(
139 c.i32_add(
140 c.i32_const(builder.pInputSignalsToTrigger),
141 c.i32_mul(
142 c.getLocal("i"),
143 c.i32_const(4)
144 )
145 )
146 )
147 ),
148 c.call(
149 "triggerComponent",
150 c.getLocal("i")
151 )
152 ),
153
154 // i=i+1
155 c.setLocal(
156 "i",
157 c.i32_add(
158 c.getLocal("i"),
159 c.i32_const(1)
160 )
161 ),
162 c.br(0)
163 ))
164 );
165
166 }
167
168 function ifSanityCheck(c, ...args) {
169 return c.if(
170 c.i32_load(c.i32_const(pSanityCheck)),
171 [].concat(...[...args])
172 );
173 }
174
175
176 function buildTriggerComponent() {
177 const f = module.addFunction("triggerComponent");
178 f.addParam("component", "i32");
179
180 const c = f.getCodeBuilder();
181
182 f.addCode(
183 c.call_indirect(
184 c.getLocal("component"), // Idx in table
185 c.getLocal("component") // Parameter
186 )
187 );
188
189 }
190
191
192 function buildHash2ComponentEntry() {
193 const f = module.addFunction("hash2ComponentEntry");
194 f.addParam("component", "i32");
195 f.addParam("hash", "i64");
196 f.setReturnType("i32");
197
198 f.addLocal("pComponent", "i32");
199 f.addLocal("pHashTable", "i32");
200 f.addLocal("hIdx", "i32");
201 f.addLocal("h", "i64");
202
203 const c = f.getCodeBuilder();
204
205 f.addCode(
206 c.setLocal(
207 "pComponent",
208 c.i32_add(
209 c.i32_load(c.i32_const(builder.ppComponents)), // pComponents
210 c.i32_mul(
211 c.getLocal("component"),
212 c.i32_const(20) // sizeof(Component)
213 )
214 )
215 ),
216 c.setLocal(
217 "pHashTable",
218 c.i32_load(c.getLocal("pComponent"))
219 ),
220 c.setLocal(
221 "hIdx",
222 c.i32_and(
223 c.i32_wrap_i64(c.getLocal("hash")),
224 c.i32_const(0xFF)
225 )
226 ),
227 c.block(c.loop(
228 c.setLocal(
229 "h",
230 c.i64_load(
231 c.i32_add(
232 c.getLocal("pHashTable"),
233 c.i32_mul(
234 c.getLocal("hIdx"),
235 c.i32_const(12)
236 )
237 )
238 )
239 ),
240 c.br_if(1, c.i64_eq(c.getLocal("h"), c.getLocal("hash"))),
241 c.if(
242 c.i64_eqz(c.getLocal("h")),
243 c.call(
244 "error",
245 c.i32_const(errs.HASH_NOT_FOUND.code),
246 c.i32_const(errs.HASH_NOT_FOUND.pointer),
247 c.i32_const(0),
248 c.i32_const(0),
249 c.i32_const(0),
250 c.i32_const(0)
251 )
252 ),
253 c.setLocal(
254 "hIdx",
255 c.i32_and(
256 c.i32_add(
257 c.getLocal("hIdx"),
258 c.i32_const(1)
259 ),
260 c.i32_const(0xFF)
261 )
262 ),
263 c.br(0)
264 )),
265
266 c.i32_add( // pComponentEntry
267 c.i32_load( // pComponentEntryTable
268 c.i32_add(
269 c.getLocal("pComponent"),
270 c.i32_const(4)
271 )
272 ),
273 c.i32_mul(
274 c.i32_load( // idx to the componentEntry
275 c.i32_add(
276 c.getLocal("pHashTable"),
277 c.i32_mul(
278 c.getLocal("hIdx"),
279 c.i32_const(12)
280 )
281 ),
282 8
283 ),
284 c.i32_const(12)
285 )
286 )
287 );
288 }
289
290 function buildGetFromComponentEntry(fnName, offset, type) {
291 const f = module.addFunction(fnName);
292 f.addParam("pR", "i32");
293 f.addParam("component", "i32");
294 f.addParam("hash", "i64");
295 f.addLocal("pComponentEntry", "i32");
296
297 const c = f.getCodeBuilder();
298
299 f.addCode(
300 c.setLocal(
301 "pComponentEntry",
302 c.call(
303 "hash2ComponentEntry",
304 c.getLocal("component"),
305 c.getLocal("hash")
306 )
307 ),
308 c.if( // If type is not signal
309 c.i32_ne(
310 c.i32_load(
311 c.getLocal("pComponentEntry"),
312 8 // type offset
313 ),
314 c.i32_const(type)
315 ),
316 c.call(
317 "error",
318 c.i32_const(errs.INVALID_TYPE.code),
319 c.i32_const(errs.INVALID_TYPE.pointer),
320 c.i32_const(0),
321 c.i32_const(0),
322 c.i32_const(0),
323 c.i32_const(0)
324 )
325 ),
326 c.i32_store(
327 c.getLocal("pR"),
328 c.i32_load(
329 c.getLocal("pComponentEntry"),
330 offset
331 )
332 )
333 );
334
335 const f2 = module.addFunction(fnName + "32");
336 f2.addParam("pR", "i32");
337 f2.addParam("component", "i32");
338 f2.addParam("hashMSB", "i32");
339 f2.addParam("hashLSB", "i32");
340
341 const c2 = f2.getCodeBuilder();
342
343 f2.addCode(
344 c2.call(
345 fnName,
346 c2.getLocal("pR"),
347 c2.getLocal("component"),
348 c2.i64_or(
349 c2.i64_shl(
350 c2.i64_extend_i32_u(c2.getLocal("hashMSB")),
351 c2.i64_const(32)
352 ),
353 c2.i64_extend_i32_u(c2.getLocal("hashLSB"))
354 )
355 )
356 );
357
358 }
359
360
361 function buildGetSignal() {
362 const f = module.addFunction("getSignal");
363 f.addParam("cIdx", "i32");
364 f.addParam("pR", "i32");
365 f.addParam("component", "i32");
366 f.addParam("signal", "i32");
367
368 const c = f.getCodeBuilder();
369
370 f.addCode(ifSanityCheck(c,
371 c.if(
372 c.i32_eqz(
373 c.i32_load(
374 c.i32_add(
375 c.i32_const(builder.pSignalsAssigned),
376 c.i32_mul(
377 c.getLocal("signal"),
378 c.i32_const(4)
379 )
380 ),
381 )
382 ),
383 c.call(
384 "error",
385 c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.code),
386 c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.pointer),
387 c.i32_const(0),
388 c.i32_const(0),
389 c.i32_const(0),
390 c.i32_const(0)
391 )
392 )
393 ));
394
395 f.addCode(
396 c.call(
397 "Fr_copy",
398 c.getLocal("pR"),
399 c.i32_add(
400 c.i32_const(builder.pSignals),
401 c.i32_mul(
402 c.getLocal("signal"),
403 c.i32_const(builder.sizeFr)
404 )
405 )
406 )
407 );
408
409 f.addCode(ifSanityCheck(c,
410 c.call("logGetSignal", c.getLocal("signal"), c.getLocal("pR") )
411 ));
412
413 }
414
415
416 function buildSetSignal() {
417 const f = module.addFunction("setSignal");
418 f.addParam("cIdx", "i32");
419 f.addParam("component", "i32");
420 f.addParam("signal", "i32");
421 f.addParam("pVal", "i32");
422 f.addLocal("signalsToTrigger", "i32");
423
424 const c = f.getCodeBuilder();
425
426
427 f.addCode(ifSanityCheck(c,
428 c.call("logSetSignal", c.getLocal("signal"), c.getLocal("pVal") ),
429 c.if(
430 c.i32_load(
431 c.i32_add(
432 c.i32_const(builder.pSignalsAssigned),
433 c.i32_mul(
434 c.getLocal("signal"),
435 c.i32_const(4)
436 )
437 ),
438 ),
439 c.call(
440 "error",
441 c.i32_const(errs.SIGNAL_ASSIGNED_TWICE.code),
442 c.i32_const(errs.SIGNAL_ASSIGNED_TWICE.pointer),
443 c.i32_const(0),
444 c.i32_const(0),
445 c.i32_const(0),
446 c.i32_const(0)
447 )
448 ),
449 c.i32_store(
450 c.i32_add(
451 c.i32_const(builder.pSignalsAssigned),
452 c.i32_mul(
453 c.getLocal("signal"),
454 c.i32_const(4)
455 )
456 ),
457 c.i32_const(1)
458 ),
459 ));
460
461 f.addCode(
462 c.call(
463 "Fr_copy",
464 c.i32_add(
465 c.i32_const(builder.pSignals),
466 c.i32_mul(
467 c.getLocal("signal"),
468 c.i32_const(builder.sizeFr)
469 )
470 ),
471 c.getLocal("pVal"),
472 )
473 );
474
475 f.addCode(
476 c.if( // If ( mapIsInput[s >> 5] & 1 << (s & 0x1f) )
477 c.i32_and(
478 c.i32_load(
479 c.i32_add(
480 c.i32_load(c.i32_const(builder.ppMapIsInput)),
481 c.i32_shl(
482 c.i32_shr_u(
483 c.getLocal("signal"),
484 c.i32_const(5)
485 ),
486 c.i32_const(2)
487 )
488 )
489 ),
490 c.i32_shl(
491 c.i32_const(1),
492 c.i32_and(
493 c.getLocal("signal"),
494 c.i32_const(0x1F)
495 )
496 )
497 ),
498 [
499
500 ...c.setLocal(
501 "signalsToTrigger",
502 c.i32_load(
503 c.i32_add(
504 c.i32_const(builder.pInputSignalsToTrigger),
505 c.i32_mul(
506 c.getLocal("component"),
507 c.i32_const(4)
508 )
509 )
510 )
511 ),
512
513 ...c.if( // if (signalsToTrigger > 0)
514 c.i32_gt_u(
515 c.getLocal("signalsToTrigger"),
516 c.i32_const(0)
517 ),
518 [
519 ...c.setLocal( // signalsToTrigger--
520 "signalsToTrigger",
521 c.i32_sub(
522 c.getLocal("signalsToTrigger"),
523 c.i32_const(1)
524 )
525 ),
526 ...c.i32_store(
527 c.i32_add(
528 c.i32_const(builder.pInputSignalsToTrigger),
529 c.i32_mul(
530 c.getLocal("component"),
531 c.i32_const(4)
532 )
533 ),
534 c.getLocal("signalsToTrigger"),
535 ),
536 ...c.if( // if (signalsToTrigger==0) triggerCompomnent(component)
537 c.i32_eqz(c.getLocal("signalsToTrigger")),
538 c.call(
539 "triggerComponent",
540 c.getLocal("component")
541 )
542 )
543 ],
544 c.call(
545 "error",
546 c.i32_const(errs.MAPISINPUT_DONT_MATCH.code),
547 c.i32_const(errs.MAPISINPUT_DONT_MATCH.pointer),
548 c.getLocal("component"),
549 c.getLocal("signal"),
550 c.i32_const(0),
551 c.i32_const(0)
552 )
553 )
554 ]
555 )
556 );
557 }
558
559 function buildComponentFinished() {
560 const f = module.addFunction("componentFinished");
561 f.addParam("cIdx", "i32");
562
563 const c = f.getCodeBuilder();
564
565 f.addCode(ifSanityCheck(c,
566 c.call("logFinishComponent", c.getLocal("cIdx"))
567 ));
568
569 f.addCode(c.ret([]));
570 }
571
572 function buildComponentStarted() {
573 const f = module.addFunction("componentStarted");
574 f.addParam("cIdx", "i32");
575
576 const c = f.getCodeBuilder();
577
578 f.addCode(ifSanityCheck(c,
579 c.call("logStartComponent", c.getLocal("cIdx"))
580 ));
581
582 f.addCode(c.ret([]));
583 }
584
585 function buildCheckConstraint() {
586 const pTmp = module.alloc(builder.sizeFr);
587 const f = module.addFunction("checkConstraint");
588 f.addParam("cIdx", "i32");
589 f.addParam("pA", "i32");
590 f.addParam("pB", "i32");
591 f.addParam("pStr", "i32");
592
593 const c = f.getCodeBuilder();
594
595 f.addCode(ifSanityCheck(c,
596 c.call(
597 "Fr_eq",
598 c.i32_const(pTmp),
599 c.getLocal("pA"),
600 c.getLocal("pB")
601 ),
602 c.if (
603 c.i32_eqz(
604 c.call(
605 "Fr_isTrue",
606 c.i32_const(pTmp),
607 )
608 ),
609 c.call(
610 "error",
611 c.i32_const(errs.CONSTRAIN_DOES_NOT_MATCH.code),
612 c.i32_const(errs.CONSTRAIN_DOES_NOT_MATCH.pointer),
613 c.getLocal("cIdx"),
614 c.getLocal("pA"),
615 c.getLocal("pB"),
616 c.getLocal("pStr"),
617 )
618 )
619 ));
620 }
621
622 function buildGetNVars() {
623 const f = module.addFunction("getNVars");
624 f.setReturnType("i32");
625
626 const c = f.getCodeBuilder();
627
628 f.addCode(c.i32_const(builder.header.NVars));
629 }
630
631 function buildGetFrLen() {
632 const f = module.addFunction("getFrLen");
633 f.setReturnType("i32");
634
635 const c = f.getCodeBuilder();
636
637 f.addCode(
638 c.i32_const(builder.sizeFr));
639 }
640
641 function buildGetPRawPrime() {
642 const f = module.addFunction("getPRawPrime");
643 f.setReturnType("i32");
644
645 const c = f.getCodeBuilder();
646
647 f.addCode(
648 c.i32_const(module.modules["Fr_F1m"].pq));
649 }
650
651 function buildGetPWitness() {
652 const f = module.addFunction("getPWitness");
653 f.addParam("w", "i32");
654 f.addLocal("signal", "i32");
655 f.setReturnType("i32");
656
657 const c = f.getCodeBuilder();
658
659
660 f.addCode(
661 c.setLocal(
662 "signal",
663 c.i32_load( // wit2sig[w]
664 c.i32_add(
665 c.i32_load( c.i32_const(builder.ppWit2sig)),
666 c.i32_mul(
667 c.getLocal("w"),
668 c.i32_const(4)
669 )
670 )
671 )
672 )
673 );
674
675 if (builder.sanityCheck) {
676 f.addCode(
677 c.if(
678 c.i32_eqz(
679 c.i32_load(
680 c.i32_add(
681 c.i32_const(builder.pSignalsAssigned),
682 c.i32_mul(
683 c.getLocal("signal"),
684 c.i32_const(4)
685 )
686 ),
687 )
688 ),
689 c.call(
690 "error",
691 c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.code),
692 c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.pointer),
693 c.i32_const(0),
694 c.i32_const(0),
695 c.i32_const(0),
696 c.i32_const(0)
697 )
698 )
699 );
700 }
701
702 f.addCode(
703 c.i32_add(
704 c.i32_const(builder.pSignals),
705
706 c.i32_mul(
707 c.getLocal("signal"),
708 c.i32_const(builder.sizeFr)
709 )
710 )
711 );
712 }
713
714 function buildGetWitnessBuffer() {
715 const f = module.addFunction("getWitnessBuffer");
716 f.setReturnType("i32");
717 f.addLocal("i", "i32");
718 f.addLocal("pSrc", "i32");
719 f.addLocal("pDst", "i32");
720
721 const c = f.getCodeBuilder();
722
723 f.addCode(
724 c.setLocal("i", c.i32_const(0)),
725 c.block(c.loop(
726 // if (i==NComponents) break
727 c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NVars))),
728
729 c.setLocal(
730 "pSrc",
731 c.i32_add(
732 c.i32_const(builder.pSignals),
733 c.i32_mul(
734 c.getLocal("i"),
735 c.i32_const(builder.sizeFr)
736 )
737 )
738 ),
739
740 c.call(
741 "Fr_toLongNormal",
742 c.getLocal("pSrc")
743 ),
744
745 c.setLocal(
746 "pDst",
747 c.i32_add(
748 c.i32_const(builder.pSignals),
749 c.i32_mul(
750 c.getLocal("i"),
751 c.i32_const(builder.sizeFr-8)
752 )
753 )
754 ),
755
756 c.call(
757 "Fr_F1m_copy",
758 c.i32_add(c.getLocal("pSrc"), c.i32_const(8)),
759 c.getLocal("pDst")
760 ),
761
762 // i=i+1
763 c.setLocal(
764 "i",
765 c.i32_add(
766 c.getLocal("i"),
767 c.i32_const(1)
768 )
769 ),
770 c.br(0)
771 )),
772
773 c.i32_const(builder.pSignals)
774 );
775
776 }
777
778
779 const fError = module.addIimportFunction("error", "runtime");
780 fError.addParam("code", "i32");
781 fError.addParam("pStr", "i32");
782 fError.addParam("param1", "i32");
783 fError.addParam("param2", "i32");
784 fError.addParam("param3", "i32");
785 fError.addParam("param4", "i32");
786
787 const fLogSetSignal = module.addIimportFunction("logSetSignal", "runtime");
788 fLogSetSignal.addParam("signal", "i32");
789 fLogSetSignal.addParam("val", "i32");
790
791 const fLogGetSignal = module.addIimportFunction("logGetSignal", "runtime");
792 fLogGetSignal.addParam("signal", "i32");
793 fLogGetSignal.addParam("val", "i32");
794
795 const fLogFinishComponent = module.addIimportFunction("logFinishComponent", "runtime");
796 fLogFinishComponent.addParam("cIdx", "i32");
797
798 const fLogStartComponent = module.addIimportFunction("logStartComponent", "runtime");
799 fLogStartComponent.addParam("cIdx", "i32");
800
801 const fLog = module.addIimportFunction("log", "runtime");
802 fLog.addParam("code", "i32");
803
804 buildWasmFf(module, "Fr", builder.header.P);
805
806 builder.pSignals=module.alloc(builder.header.NSignals*builder.sizeFr);
807 builder.pInputSignalsToTrigger=module.alloc(builder.header.NComponents*4);
808 builder.pSignalsAssigned=module.alloc(builder.header.NSignals*4);
809
810 buildHash2ComponentEntry();
811
812 buildTriggerComponent();
813 buildInit();
814
815 buildGetFromComponentEntry("getSubComponentOffset", 0 /* offset */, builder.TYPE_COMPONENT);
816 buildGetFromComponentEntry("getSubComponentSizes", 4 /* offset */, builder.TYPE_COMPONENT);
817
818 buildGetFromComponentEntry("getSignalOffset", 0 /* offset */, builder.TYPE_SIGNAL);
819 buildGetFromComponentEntry("getSignalSizes", 4 /* offset */, builder.TYPE_SIGNAL);
820
821 buildGetSignal();
822 buildSetSignal();
823
824 buildComponentStarted();
825 buildComponentFinished();
826
827 buildCheckConstraint();
828
829 buildGetNVars();
830 buildGetFrLen();
831 buildGetPWitness();
832 buildGetPRawPrime();
833 buildGetWitnessBuffer();
834
835// buildFrToInt();
836
837 module.exportFunction("init");
838 module.exportFunction("getNVars");
839 module.exportFunction("getFrLen");
840 module.exportFunction("getSignalOffset32");
841 module.exportFunction("setSignal");
842 module.exportFunction("getPWitness");
843 module.exportFunction("Fr_toInt");
844 module.exportFunction("getPRawPrime");
845 module.exportFunction("getWitnessBuffer");
846
847};