arnaucube
arnaucube/circomlibPublic Self-hosted repository
circomlib/src/g2_gencontract.js
src/g2_gencontract.jsRaw
  1// Copyright (c) 2018 Jordi Baylina
  2// License: LGPL-3.0+
  3//
  4
  5const Contract = require("./evmasm");
  6const G2 = require("snarkjs").bn128.G2;
  7
  8
  9function toHex256(a) {
 10    let S = a.toString(16);
 11    while (S.length < 64) S="0"+S;
 12    return "0x" + S;
 13}
 14
 15function createCode(P, w) {
 16
 17    const C = new Contract();
 18
 19    const NPOINTS = 1 << (w-1);
 20
 21    const VAR_POS = C.allocMem(32);
 22    const VAR_POINTS = C.allocMem( (NPOINTS)*4*32);
 23    const savedP = C.allocMem(32);
 24    const savedZ3 = C.allocMem(32);
 25
 26    // Check selector
 27    C.push("0x0100000000000000000000000000000000000000000000000000000000");
 28    C.push(0);
 29    C.calldataload();
 30    C.div();
 31    C.push("b65c7c74"); // mulexp(uint256)
 32    C.eq();
 33    C.jmpi("start");
 34    C.invalid();
 35
 36    C.label("start");
 37
 38    storeVals();
 39
 40    C.push( Math.floor(255/w)*w  );                // pos := 255
 41    C.push(VAR_POS);
 42    C.mstore();
 43
 44    C.push("21888242871839275222246405745257275088696311157297823662689037894645226208583");
 45    C.push(0);
 46    C.push(0);
 47    C.push(0);
 48    C.push(0);
 49    C.push(0);
 50    C.push(0);
 51
 52    C.label("begin_loop");      // ACC_X ACC_Y ACC_Z q
 53
 54    C.internalCall("double");
 55
 56    // g = (e>>pos)&MASK
 57    C.push(4);
 58    C.calldataload();           // e ACC_X ACC_Y ACC_Z q
 59
 60    C.push(VAR_POS);
 61    C.mload();                  // pos e ACC_X ACC_Y ACC_Z q
 62    C.shr();
 63
 64    C.push(NPOINTS-1);
 65    C.and();                    // g ACC_X ACC_Y ACC_Z q
 66
 67    C.internalCall("add");      // acc_x acc_y acc_z
 68
 69    C.push(VAR_POS);
 70    C.mload();                  // pos acc_x acc_y acc_z
 71    C.dup(0);                   // pos pos acc_x acc_y acc_z
 72    C.push(0);                  // 0 pos pos acc_x acc_y acc_z
 73    C.eq();                     // eq pos acc_x acc_y acc_z
 74    C.jmpi("after_loop");       // pos acc_x acc_y acc_z
 75    C.push(w);                  // 5 pos acc_x acc_y acc_z
 76    C.sub();                    // pos acc_x acc_y acc_z
 77    C.push(VAR_POS);
 78    C.mstore();                 // acc_x acc_y acc_z
 79    C.jmp("begin_loop");
 80    C.label("after_loop");      // pos acc_x acc_y acc_z
 81    C.pop();                    // acc_x acc_y acc_z
 82
 83    C.internalCall("affine");   // acc_x acc_y
 84
 85    C.push(0);
 86    C.mstore();
 87    C.push(20);
 88    C.mstore();
 89    C.push(40);
 90    C.mstore();
 91    C.push(60);
 92    C.mstore();
 93
 94    C.push("0x80");
 95    C.push("0x00");
 96    C.return();
 97
 98
 99    double();
100    addPoint();
101    affine();
102
103    return C.createTxData();
104
105    function add(a,b,q) {
106        C.dup(q);
107        C.dup(a+1 + 1);
108        C.dup(b+1 + 2);
109        C.addmod();
110        C.dup(q + 1);
111        C.dup(a + 2);
112        C.dup(b + 3);
113        C.addmod();
114    }
115
116    function sub(a,b,q) {
117        C.dup(q);           // q
118        C.dup(a+1 + 1);     // ai q
119        C.dub(q + 2);       // q ai q
120        C.dup(b+1 + 3);     // bi q ai q
121        C.sub();            // -bi ai q
122        C.addmod();         // ci
123        C.dup(q + 1);       // q ci
124        C.dup(a + 2);       // ar q ci
125        C.dup(q + 3);       // q ar q ci
126        C.dup(b + 4);       // br q ar q ci
127        C.sub();            // -br ar q ci
128        C.addmod();         // cr ci
129    }
130
131    function mul(a, b, q) {
132        C.dup(q);           //  q
133        C.dup(q + 1);       //  q q
134        C.dup(a + 2);       //  ar q q
135        C.dup(b+1 + 3);     //  bi ar q q
136        C.mulmod();         //  ci1 q
137        C.dup(q + 2);       //  q ci1 q
138        C.dup(a+1 + 3);     //  ai q ci1 q
139        C.dup(b + 4);       //  ar ai q ci1 q
140        C.mulmod();         //  ci2 ci1 q
141        C.addmod();         //  ci
142        C.dup(q + 1);       //  q ci
143        C.dup(q + 2);       //  q q ci
144        C.dup(q + 3);       //  q q q ci
145        C.dup(a+1 + 4);     //  ai q q ci
146        C.dup(b+1 + 5);     //  bi ai q q ci
147        C.mulmod();         //  cr2 q q ci
148        C.sub();            //  -cr2 q ci
149        C.dup(q + 3);       //  q -cr2 q ci
150        C.dup(a + 4);       //  ar q -cr2 q ci
151        C.dup(b + 5);       //  br ar q -cr2 q ci
152        C.mulmod();         //  cr1 -cr2 q ci
153        C.addmod();         //  cr ci
154    }
155
156    function square(a, q) {
157        C.dup(q);           //  q
158        C.dup(q + 1);       //  q q
159        C.dup(a + 2);       //  ar q q
160        C.dup(a+1 + 3);     //  ai ar q q
161        C.mulmod();         //  arai q
162        C.dup(0);           //  arai arai q
163        C.addmod();         //  ci
164        C.dup(q + 1);       //  q ci
165        C.dup(q + 2);       //  q q ci
166        C.dup(q + 3);       //  q q q ci
167        C.dup(a+1 + 4);     //  ai q q ci
168        C.dup(a+1 + 5);     //  ai ai q q ci
169        C.mulmod();         //  cr2 q q ci
170        C.sub();            //  -cr2 q ci
171        C.dup(q + 3);       //  q -cr2 q ci
172        C.dup(a + 4);       //  ar q -cr2 q ci
173        C.dup(a + 5);       //  br ar q -cr2 q ci
174        C.mulmod();         //  cr1 -cr2 q ci
175        C.addmod();         //  cr ci
176    }
177
178    function add1(a, q) {
179        C.dup(a+1);         // im
180        C.dup(1 + q);       //  q
181        C.dup(2 + a);       //  re q im
182        C.push(1);          // 1 re q im
183        C.addmod();
184    }
185
186    function cmp(a, b) {
187        C.dup(a);
188        C.dup(b);
189        C.eq();
190        C.dup(a+1);
191        C.dup(a+1);
192        C.and();
193    }
194
195    function rm(a) {
196        if (a>0) C.swap(a);
197        C.pop();
198        if (a>0) C.swap(a);
199        C.pop();
200    }
201
202    function double() {
203        C.label("double");       // xR, xI,    yR, yI,   zR zI, q
204
205        C.dup(4);
206        C.iszero();
207        C.dup(6);
208        C.iszero();
209        C.and();
210        C.jumpi("enddouble");   // X Y Z q
211
212
213        // Z3 = 2*Y*Z // Remove Z
214        mul(2, 4, 6);           // yz X Y Z q
215        rm(6);                  // X Y yz q
216
217        add(4, 4, 6);           // 2yz X Y yz q
218        rm(6);                  // X Y Z3 q
219
220        // A = X^2
221        square(0,6);               // A X Y Z3 q
222
223        // B = Y^2  // Remove Y
224        square(4,8);              // B A X Y Z3 q
225        rm(6);                  // A X B Z3 q
226
227        // C = B^2
228        square(4,8);               // C A X B Z3 q
229
230        // D = (X+B)^2-A-C // Remove X, Remove B
231        add(4,6, 10);           // X+B C A X B Z3 q
232        rm(6);                  // C A X+B B Z3 q
233        rm(6);                  // A X+B C Z3 q
234        square(2,8);            // (X+B)^2 A X+B C Z3 q
235        rm(4);                  // A (X+B)^2 C Z3 q
236        sub(2, 0, 8);           // (X+B)^2-A A (X+B)^2 C Z3 q
237        rm(4);                  // A (X+B)^2-A C Z3 q
238        sub(2, 4, 8);           // (X+B)^2-A-C A (X+B)^2-A C Z3 q
239        rm(4);                  // A D C Z3 q
240
241        // D = D+D
242        add(2,2, 8);            // D+D A D C Z3 q
243        rm(4);                  // A D C Z3 q
244
245        // E=A+A+A
246        add(0, 0, 8);           // 2A A D C Z3 q
247        add(0, 2, 10);          // 3A 2A A D C Z3 q
248        rm(4);                  // 2A 3A D C Z3 q
249        rm(0);                  // E D C Z3 q
250
251        // F=E^2
252        square(0, 8);           // F E D C Z3 q
253
254        // X3= F - 2*D  // Remove F
255        add(4, 4, 10);          // 2D F E D C Z3 q
256        sub(2, 0, 12);          // F-2D 2D F E D C Z3 q
257        rm(4);                  // 2D X3 E D C Z3 q
258        rm(0);                  // X3 E D C Z3 q
259
260        // Y3 = E * (D - X3) - 8 * C  // Remove D C  E
261
262        sub(4, 0, 10);          // D-X3 X3 E D C Z3 q
263        rm(6);                  // X3 E D-X3 C Z3 q
264        mul(2, 4, 10);          // E*(D-X3) X3 E D-X3 C Z3 q
265        rm(6);                  // X3 E E*(D-X3) C Z3 q
266        rm(2);                  // X3 E*(D-X3) C Z3 q
267        add(4, 4, 8);           // 2C X3 E*(D-X3) C Z3 q
268        rm(6);                  // X3 E*(D-X3) 2C Z3 q
269        add(4, 4, 8);           // 4C X3 E*(D-X3) 2C Z3 q
270        rm(6);                  // X3 E*(D-X3) 4C Z3 q
271        add(4, 4, 8);           // 8C X3 E*(D-X3) 4C Z3 q
272        rm(6);                  // X3 E*(D-X3) 8C Z3 q
273        sub(2, 4, 8);           // E*(D-X3)-8C X3 E*(D-X3) 8C Z3 q
274        rm(6);                  // X3 E*(D-X3) Y3 Z3 q
275        rm(2);                  // X3 Y3 Z3 q
276
277        C.label("enddouble");
278        C.returnCall();
279    }
280
281    function addPoint() {     // p, xR, xI,    yR, yI,   zR zI, q
282
283
284        C.dup(0);           // p p X2 Y2 Z2 q
285
286        C.push(savedP);
287        C.mstore();
288
289        C.iszero();         // X2 Y2 Z2 q
290        C.jumpi("endpadd");
291
292
293        C.dup(4);
294        C.iszero();
295        C.dup(6);
296        C.iszero();
297        C.and();
298        C.jumpi("returnP");   // X2 Y2 Z2 q
299
300
301
302        // lastZ3 = (Z2+1)^2 - Z2^2
303        add1(4, 6);         // Z2+1 X2 Y2 Z2 q
304        square(0, 8);       // (Z2+1)^2 Z2+1 X2 Y2 Z2 q
305        rm(2);              // (Z2+1)^2 X2 Y2 Z2 q
306        square(6, 8);       // Z2^2 (Z2+1)^2 X2 Y2 Z2 q
307
308
309        sub(2, 0, 10);      // (Z2+1)^2-Z2^2 Z2^2 (Z2+1)^2 X2 Y2 Z2 q
310
311        saveZ3();           // Z2^2 (Z2+1)^2 X2 Y2 Z2 q
312        rm(2);              // Z2^2 X2 Y2 Z2 q
313
314        // U2 = X2
315        // S2 = Y2          // Z2^2 U2 S2 Z2 q
316
317
318        // U1 = X1 * Z2^2
319        loadX();            // X1 Z2^2 U2 S2 Z2 q
320        mul(0, 2, 10);      // X1*Z2^2 X1 Z2^2 U2 S2 Z2 q
321        rm(2);              // X1*Z2^2 Z2^2 U2 S2 Z2 q
322
323
324        mul(2, 8, 10);      // Z2^3 U1 Z2^2 U2 S2 Z2 q
325        rm(4);              // U1 Z2^3 U2 S2 Z2 q
326        rm(8);              // Z2^3 U2 S2 U1 q
327
328        // S1 = Y1 * Z1^3
329        loadY();            // Y1 Z2^3 U2 S2 U1 q
330        mul(0, 2, 10);      // S1 Y1 Z2^3 U2 S2 U1 q
331        rm(4);              // Y1 S1 U2 S2 U1 q
332        rm(0);              // S1 U2 S2 U1 q
333
334        cmp(0, 4);          // c1 S1 U2 S2 U1 q
335        cmp(3, 7);          // c2 c1 S1 U2 S2 U1 q
336        C.and();            // c2&c1 S1 U2 S2 U1 q
337        C.jumpi("double1"); // S1 U2 S2 U1 q
338
339
340        // Returns the double
341
342        // H = U2-U1  // Remove U2
343        C.sub(4, 8, 10);    // H S1 U2 S2 U1 q
344        rm(4);              // S1 H S2 U1 q
345
346        // // r = 2 * (S2-S1)  // Remove S2
347        C.sub(4, 4, 8);     // S1-S2 S1 H S2 U1 q
348        rm(6);              // S1 H S1-S2 U1 q
349        C.add(4, 4, 8);     // 2*(S1-S2) S1 H S1-S2 U1 q
350        rm(6);              // S1 H r U1 q
351
352        // I = (2 * H)^2
353        C.add(2, 2, 8);     // 2*H S1 H r U1 q
354        C.square(0, 10);    // (2*H)^2 2*H S1 H r U1 q
355        rm(2);              // I S1 H r U1 q
356
357        // V = U1 * I
358        mul(8, 0, 10);      // V I S1 H r U1 q
359        rm(10);             // I S1 H r V q
360
361        // J = H * I // Remove I
362        mul(4, 0, 10);      // J I S1 H r V q
363        rm(2);              // J S1 H r V q
364
365        // X3 = r^2 - J - 2 * V
366
367        // S1J2 = (S1*J)*2  // Remove S1
368        mul(2, 0, 10);      // S1*J J S1 H r V q
369        rm(4);              // J S1*J H r V q
370        add(2,2, 10);       // (S1*J)*2 J S1*J H r V q
371        rm(4);              // J S1J2 H r V q
372
373        // X3 = r^2 - J - 2 * V
374        square(6, 10);      // r^2 J S1J2 H r V q
375        sub(0, 2, 12);      // r^2-J r^2 J S1J2 H r V q
376        rm(2);              // r^2-J J S1J2 H r V q
377        rm(2);              // r^2-J S1J2 H r V q
378        add(8, 8, 10);      // 2*V r^2-J S1J2 H r V q
379        sub(2, 0, 12);      // r^2-J-2*V 2*V r^2-J S1J2 H r V q
380        rm(4);              // 2*V  X3 S1J2 H r V q
381        rm(0);              // X3 S1J2 H r V q
382
383        // Y3 = r * (V-X3)-S1J2
384
385        sub(8, 0, 10);      // V-X3 X3 S1J2 H r V q
386        rm(10);             // X3 S1J2 H r V-X3 q
387        mul(6, 8, 10);      // r*(V-X3) X3 S1J2 H r V-X3 q
388        rm(8);              // X3 S1J2 H r*(V-X3) V-X3 q
389        rm(8);              // S1J2 H r*(V-X3) X3 q
390        sub(4, 0, 8);       // Y3 S1J2 H r*(V-X3) X3 q
391        rm(6);              // S1J2 H Y3 X3 q
392        rm(0);              // H Y3 X3 q
393
394        // Z3 = lastZ * H
395        loadZ3();           // lastZ3 H Y3 X3 q
396        mul(0, 2, 8);       // Z3 lastZ3 H Y3 X3 q
397        rm(4);              // lastZ3 Z3 Y3 X3 q
398        rm(0);              // Z3 Y3 X3 q
399
400        C.swap(1);
401        C.swap(5);
402        C.swap(1);
403        C.swap(4);          // X3 Y3 Z3 q
404
405        // returns the point in memory
406        C.label("returnP"); // X Y Z q
407        rm(0);
408        rm(0);
409        rm(0);
410        C.push(0);
411        C.push(1);
412        loadX();
413        loadY();
414        C.jump("endpadd");
415
416        C.label("double1"); // S1 U2 S2 U1 q
417        rm(0);
418        rm(0);
419        rm(0);
420        rm(0);
421        C.push(0);
422        C.push(1);
423        loadX();
424        loadY();
425        C.jump("double");
426
427        C.label("endpadd");
428        C.returnCall();
429
430        function loadX() {
431            C.push(savedP);
432            C.mload();                  // p
433            C.push(32);
434            C.mul();                    // P*32
435            C.push(VAR_POINTS+32);
436            C.add();                    // P*32+32
437            C.dup();                    // P*32+32 P*32+32
438            C.mload();                  // im P*32+32
439            C.swap(1);                  // P*32+32 im
440            C.push(0x20);               // 32 P*32+32 im
441            C.sub();                    // P*32 im
442            C.mload();                  // re im
443        }
444
445        function loadY() {
446            C.push(savedP);
447            C.mload();                  // p
448            C.push(32);
449            C.mul();                    // P*32
450            C.push(VAR_POINTS+32*3);
451            C.add();                    // P*32+32
452            C.dup();                    // P*32+32 P*32+32
453            C.mload();                  // im P*32+32
454            C.swap(1);                  // P*32+32 im
455            C.push(0x20);               // 32 P*32+32 im
456            C.sub();                    // P*32 im
457            C.mload();                  // re im
458        }
459
460        function loadZ3() {
461            C.push(savedZ3+32);
462            C.mload();                  // p
463            C.push(savedZ3);
464            C.mload();
465        }
466
467        function saveZ3() {
468            C.push(savedZ3);
469            C.mstore();
470            C.push(savedZ3+32);
471            C.mstore();
472        }
473    }
474
475    function affine() { // X Y Z q
476        // If Z2=0 return 0
477        C.label("affine");
478        C.dup(4);
479        C.dup(5 + 1);
480        C.or();
481        C.jumpi("notZero");     // X Y Z q
482        rm(0);
483        rm(0);
484        C.push(0);
485        C.push(0);
486
487        C.jmp("endAffine");
488        C.label("notZero");
489
490        inverse2(4,6);          // Z_inv X Y Z q
491        square(2, 8);           // Z2_inv Z_inv X Y Z q
492        mul(0, 2, 10);          // Z3_inv Z2_inv Z_inv X Y Z q
493        rm(4);                  // Z2_inv Z3_inv X Y Z q
494        C.push(1);
495        C.push(0);              // 1 Z2_inv Z3_inv X Y Z q
496        rm(10);                 // Z2_inv Z3_inv X Y 1 q
497        mul(2, 6, 10);          // YI Z2_inv Z3_inv X Y 1 q
498        rm(8);                  // Z2_inv Z3_inv X YI 1 q
499        mul(0, 4, 10);          // XI Z2_inv Z3_inv X YI 1 q
500        rm(6);                  // Z2_inv Z3_inv XI YI 1 q
501        rm(0);                  // Z3_inv XI YI 1 q
502        rm(0);                  // XI YI 1 q
503        C.label("endAffine");
504        C.returnCall();
505    }
506
507    function inverse2(a, q) {
508        C.dup(q);           // q
509        C.dup(q + 1);       // q q
510        C.push(2);          // 2 q q
511        C.sub();            // q-2 q
512        C.dup(q + 2);       // q q-2 q
513        C.dup(q + 3);       // q q q-2 q
514        C.dup(a + 4);       // ar q q q-2 q
515        C.dup(a + 5);       // ar ar q q q-2 q
516        C.mulmod();         // t0 q q-2 q
517
518        C.dup(q   + 4);     // q t0 q q-2 q
519        C.dup(a+1 + 5);     // ai q t0 q q-2 q
520        C.dup(a+1 + 6);     // ai ai q t0 q q-2 q
521        C.mulmod();         // t1 t0 q q-2 q
522
523        C.addmod();         // t2 q-2 q
524        C.expmod();         // t3
525
526        C.dup(q + 1);       // q t3
527        C.dup(q + 2);       // q q t3
528        C.dup(q + 3);       // q q q t3
529        C.dup(1);           // t3 q q q t3
530        C.sub();            // -t3 q q t3
531        C.dup(a+1 + 3);     // ai -t3 q q t3
532        C.mulmod();         // ii q t3
533        C.swap(2);          // t3 q ii
534        C.dup(a + 3);       // ar t3 q ii
535        C.mulmod();         // ir ii
536    }
537
538    function storeVals() {
539        C.push(VAR_POINTS);                 // p
540        for (let i=0; i<NPOINTS; i++) {
541            const MP = G2.affine(G2.mulScalar(P, i));
542            for (let j=0; j<2; j++) {
543                for (let k=0; k<2; k++) {
544                    C.push(toHex256(MP[j][k]));     // MP[0][0] p
545                    C.dup(1);                       // p MP[0][0] p
546                    C.mstore();                     // p
547                    C.push(32);                     // 32 p
548                    C.add();                        // p+32
549                }
550            }
551        }
552    }
553
554}
555
556module.exports.abi = [
557    {
558        "constant": true,
559        "inputs": [
560            {
561                "name": "escalar",
562                "type": "uint256"
563            }
564        ],
565        "name": "mulexp",
566        "outputs": [
567            {
568                "name": "",
569                "type": "uint256"
570            },
571            {
572                "name": "",
573                "type": "uint256"
574            }
575        ],
576        "payable": false,
577        "stateMutability": "pure",
578        "type": "function"
579    }
580];
581
582module.exports.createCode = createCode;