arnaucube
arnaucube/circomPublic Self-hosted repository
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};