snarkjs/src/gcurve.js
src/gcurve.jsRaw
1
2class GCurve {
3
4 constructor(F, g) {
5 this.F = F;
6 this.g = F.copy(g);
7 if (this.g.length == 2) this.g[2] = this.F.one;
8 this.zero = [this.F.zero, this.F.one, this.F.zero];
9 }
10
11 isZero(p) {
12 return this.F.isZero(p[2]);
13 }
14
15 add(p1, p2) {
16
17 if (this.isZero(p1)) return p2;
18 if (this.isZero(p2)) return p1;
19
20 const res = new Array(3);
21
22 const Z1Z1 = this.F.square( p1[2] );
23 const Z2Z2 = this.F.square( p2[2] );
24
25 const U1 = this.F.mul( p1[0] , Z2Z2 ); // U1 = X1 * Z2Z2
26 const U2 = this.F.mul( p2[0] , Z1Z1 ); // U2 = X2 * Z1Z1
27
28 const Z1_cubed = this.F.mul( p1[2] , Z1Z1);
29 const Z2_cubed = this.F.mul( p2[2] , Z2Z2);
30
31 const S1 = this.F.mul( p1[1] , Z2_cubed); // S1 = Y1 * Z2 * Z2Z2
32 const S2 = this.F.mul( p2[1] , Z1_cubed); // S2 = Y2 * Z1 * Z1Z1
33
34 if (this.F.equals(U1,U2) && this.F.equals(S1,S2)) {
35 return this.double(p1);
36 }
37
38 const H = this.F.sub( U2 , U1 ); // H = U2-U1
39
40 const S2_minus_S1 = this.F.sub( S2 , S1 );
41
42 const I = this.F.square( this.F.add(H,H) ); // I = (2 * H)^2
43 const J = this.F.mul( H , I ); // J = H * I
44
45 const r = this.F.add( S2_minus_S1 , S2_minus_S1 ); // r = 2 * (S2-S1)
46 const V = this.F.mul( U1 , I ); // V = U1 * I
47
48 res[0] =
49 this.F.sub(
50 this.F.sub( this.F.square(r) , J ),
51 this.F.add( V , V )); // X3 = r^2 - J - 2 * V
52
53 const S1_J = this.F.mul( S1 , J );
54
55 res[1] =
56 this.F.sub(
57 this.F.mul( r , this.F.sub(V,res[0])),
58 this.F.add( S1_J,S1_J )); // Y3 = r * (V-X3)-2 S1 J
59
60 res[2] =
61 this.F.mul(
62 H,
63 this.F.sub(
64 this.F.square( this.F.add(p1[2],p2[2]) ),
65 this.F.add( Z1Z1 , Z2Z2 ))); // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H
66
67 return res;
68 }
69
70 double(p) {
71 const res = new Array(3);
72
73 if (this.isZero(p)) return p;
74
75 const A = this.F.square( p[0] ); // A = X1^2
76 const B = this.F.square( p[1] ); // B = Y1^2
77 const C = this.F.square( B ); // C = B^2
78
79 let D =
80 this.F.sub(
81 this.F.square( this.F.add(p[0] , B )),
82 this.F.add( A , C));
83 D = this.F.add(D,D); // D = 2 * ((X1 + B)^2 - A - C)
84
85 const E = this.F.add( this.F.add(A,A), A); // E = 3 * A
86 const F = this.F.square( E ); // F = E^2
87
88 res[0] = this.F.sub( F , this.F.add(D,D) ); // X3 = F - 2 D
89
90 let eightC = this.F.add( C , C );
91 eightC = this.F.add( eightC , eightC );
92 eightC = this.F.add( eightC , eightC );
93
94 res[1] =
95 this.F.sub(
96 this.F.mul(
97 E,
98 this.F.sub( D, res[0] )),
99 eightC); // Y3 = E * (D - X3) - 8 * C
100
101 const Y1Z1 = this.F.mul( p[1] , p[2] );
102 res[2] = this.F.add( Y1Z1 , Y1Z1 ); // Z3 = 2 * Y1 * Z1
103
104 return res;
105 }
106
107 mulEscalar(base, e) {
108 let res = this.zero;
109 let rem = e;
110 let exp = base;
111
112 while (! rem.isZero()) {
113 if (rem.isOdd()) {
114 res = this.add(res, exp);
115 }
116 exp = this.double(exp);
117 rem = rem.shiftRight(1);
118 }
119
120 return res;
121 }
122
123 affine(p) {
124 if (this.isZero(p)) {
125 return this.zero;
126 } else {
127 const Z_inv = this.F.inverse(p[2]);
128 const Z2_inv = this.F.square(Z_inv);
129 const Z3_inv = this.F.mul(Z2_inv, Z_inv);
130
131 const res = new Array(3);
132 res[0] = this.F.affine( this.F.mul(p[0],Z2_inv));
133 res[1] = this.F.affine( this.F.mul(p[1],Z3_inv));
134 res[2] = this.F.one;
135
136 return res;
137 }
138 }
139
140 equals(p1, p2) {
141 if (this.isZero(p1)) return this.isZero(p2);
142 if (this.isZero(p2)) return this.isZero(p1);
143
144 const Z1Z1 = this.F.square( p1[2] );
145 const Z2Z2 = this.F.square( p2[2] );
146
147 const U1 = this.F.mul( p1[0] , Z2Z2 );
148 const U2 = this.F.mul( p2[0] , Z1Z1 );
149
150 const Z1_cubed = this.F.mul( p1[2] , Z1Z1);
151 const Z2_cubed = this.F.mul( p2[2] , Z2Z2);
152
153 const S1 = this.F.mul( p1[1] , Z2_cubed);
154 const S2 = this.F.mul( p2[1] , Z1_cubed);
155
156 return (this.F.equals(U1,U2) && this.F.equals(S1,S2));
157 }
158
159 toString(p) {
160 const cp = this.affine(p);
161 return `[ ${this.F.toString(cp[0])} , ${this.F.toString(cp[1])} ]`;
162 }
163
164}
165
166module.exports = GCurve;
167