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 buildCheckAssert() {
623 const f = module.addFunction("checkAssert");
624 f.addParam("cIdx", "i32");
625 f.addParam("pA", "i32");
626 f.addParam("pStr", "i32");
627
628 const c = f.getCodeBuilder();
629
630 f.addCode(ifSanityCheck(c,
631 c.if (
632 c.i32_eqz(
633 c.call(
634 "Fr_isTrue",
635 c.getLocal("pA"),
636 )
637 ),
638 c.call(
639 "error",
640 c.i32_const(errs.ASSERT_DOES_NOT_MATCH.code),
641 c.i32_const(errs.ASSERT_DOES_NOT_MATCH.pointer),
642 c.getLocal("cIdx"),
643 c.getLocal("pA"),
644 c.getLocal("pStr"),
645 c.i32_const(0)
646 )
647 )
648 ));
649 }
650
651 function buildGetNVars() {
652 const f = module.addFunction("getNVars");
653 f.setReturnType("i32");
654
655 const c = f.getCodeBuilder();
656
657 f.addCode(c.i32_const(builder.header.NVars));
658 }
659
660 function buildGetFrLen() {
661 const f = module.addFunction("getFrLen");
662 f.setReturnType("i32");
663
664 const c = f.getCodeBuilder();
665
666 f.addCode(
667 c.i32_const(builder.sizeFr));
668 }
669
670 function buildGetPRawPrime() {
671 const f = module.addFunction("getPRawPrime");
672 f.setReturnType("i32");
673
674 const c = f.getCodeBuilder();
675
676 f.addCode(
677 c.i32_const(module.modules["Fr_F1m"].pq));
678 }
679
680 function buildGetPWitness() {
681 const f = module.addFunction("getPWitness");
682 f.addParam("w", "i32");
683 f.addLocal("signal", "i32");
684 f.setReturnType("i32");
685
686 const c = f.getCodeBuilder();
687
688
689 f.addCode(
690 c.setLocal(
691 "signal",
692 c.i32_load( // wit2sig[w]
693 c.i32_add(
694 c.i32_load( c.i32_const(builder.ppWit2sig)),
695 c.i32_mul(
696 c.getLocal("w"),
697 c.i32_const(4)
698 )
699 )
700 )
701 )
702 );
703
704 if (builder.sanityCheck) {
705 f.addCode(
706 c.if(
707 c.i32_eqz(
708 c.i32_load(
709 c.i32_add(
710 c.i32_const(builder.pSignalsAssigned),
711 c.i32_mul(
712 c.getLocal("signal"),
713 c.i32_const(4)
714 )
715 ),
716 )
717 ),
718 c.call(
719 "error",
720 c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.code),
721 c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.pointer),
722 c.i32_const(0),
723 c.i32_const(0),
724 c.i32_const(0),
725 c.i32_const(0)
726 )
727 )
728 );
729 }
730
731 f.addCode(
732 c.i32_add(
733 c.i32_const(builder.pSignals),
734
735 c.i32_mul(
736 c.getLocal("signal"),
737 c.i32_const(builder.sizeFr)
738 )
739 )
740 );
741 }
742
743 function buildGetWitnessBuffer() {
744 const f = module.addFunction("getWitnessBuffer");
745 f.setReturnType("i32");
746 f.addLocal("i", "i32");
747 f.addLocal("pSrc", "i32");
748 f.addLocal("pDst", "i32");
749
750 const c = f.getCodeBuilder();
751
752 f.addCode(
753 c.setLocal("i", c.i32_const(0)),
754 c.block(c.loop(
755 // if (i==NComponents) break
756 c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NVars))),
757
758 c.setLocal(
759 "pSrc",
760 c.call(
761 "getPWitness",
762 c.getLocal("i"),
763 )
764 ),
765
766 c.call(
767 "Fr_toLongNormal",
768 c.getLocal("pSrc")
769 ),
770
771 c.setLocal(
772 "pDst",
773 c.i32_add(
774 c.i32_const(builder.pOutput),
775 c.i32_mul(
776 c.getLocal("i"),
777 c.i32_const(builder.sizeFr-8)
778 )
779 )
780 ),
781
782 c.call(
783 "Fr_F1m_copy",
784 c.i32_add(c.getLocal("pSrc"), c.i32_const(8)),
785 c.getLocal("pDst")
786 ),
787
788 // i=i+1
789 c.setLocal(
790 "i",
791 c.i32_add(
792 c.getLocal("i"),
793 c.i32_const(1)
794 )
795 ),
796 c.br(0)
797 )),
798
799 c.i32_const(builder.pOutput)
800 );
801
802 }
803
804
805 const fError = module.addIimportFunction("error", "runtime");
806 fError.addParam("code", "i32");
807 fError.addParam("pStr", "i32");
808 fError.addParam("param1", "i32");
809 fError.addParam("param2", "i32");
810 fError.addParam("param3", "i32");
811 fError.addParam("param4", "i32");
812
813 const fLogSetSignal = module.addIimportFunction("logSetSignal", "runtime");
814 fLogSetSignal.addParam("signal", "i32");
815 fLogSetSignal.addParam("val", "i32");
816
817 const fLogGetSignal = module.addIimportFunction("logGetSignal", "runtime");
818 fLogGetSignal.addParam("signal", "i32");
819 fLogGetSignal.addParam("val", "i32");
820
821 const fLogFinishComponent = module.addIimportFunction("logFinishComponent", "runtime");
822 fLogFinishComponent.addParam("cIdx", "i32");
823
824 const fLogStartComponent = module.addIimportFunction("logStartComponent", "runtime");
825 fLogStartComponent.addParam("cIdx", "i32");
826
827 const fLog = module.addIimportFunction("log", "runtime");
828 fLog.addParam("code", "i32");
829
830 buildWasmFf(module, "Fr", builder.header.P);
831
832 builder.pSignals=module.alloc(builder.header.NSignals*builder.sizeFr);
833 builder.pOutput=module.alloc(builder.header.NVars*(builder.sizeFr-8));
834 builder.pInputSignalsToTrigger=module.alloc(builder.header.NComponents*4);
835 builder.pSignalsAssigned=module.alloc(builder.header.NSignals*4);
836
837 buildHash2ComponentEntry();
838
839 buildTriggerComponent();
840 buildInit();
841
842 buildGetFromComponentEntry("getSubComponentOffset", 0 /* offset */, builder.TYPE_COMPONENT);
843 buildGetFromComponentEntry("getSubComponentSizes", 4 /* offset */, builder.TYPE_COMPONENT);
844
845 buildGetFromComponentEntry("getSignalOffset", 0 /* offset */, builder.TYPE_SIGNAL);
846 buildGetFromComponentEntry("getSignalSizes", 4 /* offset */, builder.TYPE_SIGNAL);
847
848 buildGetSignal();
849 buildSetSignal();
850
851 buildComponentStarted();
852 buildComponentFinished();
853
854 buildCheckConstraint();
855 buildCheckAssert();
856
857 buildGetNVars();
858 buildGetFrLen();
859 buildGetPWitness();
860 buildGetPRawPrime();
861 buildGetWitnessBuffer();
862
863// buildFrToInt();
864
865 module.exportFunction("init");
866 module.exportFunction("getNVars");
867 module.exportFunction("getFrLen");
868 module.exportFunction("getSignalOffset32");
869 module.exportFunction("setSignal");
870 module.exportFunction("getPWitness");
871 module.exportFunction("Fr_toInt");
872 module.exportFunction("getPRawPrime");
873 module.exportFunction("getWitnessBuffer");
874
875};