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("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};