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