snarkjs/src/gcurve.js
src/gcurve.jsRaw
1/*
2 Copyright 2018 0kims association.
3
4 This file is part of zksnark JavaScript library.
5
6 zksnark JavaScript library is a free software: you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as published by the
8 Free Software Foundation, either version 3 of the License, or (at your option)
9 any later version.
10
11 zksnark JavaScript library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 more details.
15
16 You should have received a copy of the GNU General Public License along with
17 zksnark JavaScript library. If not, see <https://www.gnu.org/licenses/>.
18*/
19
20const fUtils = require("./futils.js");
21
22class GCurve {
23
24 constructor(F, g) {
25 this.F = F;
26 this.g = [F.copy(g[0]), F.copy(g[1])];
27 if (this.g.length == 2) this.g[2] = this.F.one;
28 this.zero = [this.F.zero, this.F.one, this.F.zero];
29 }
30
31 isZero(p) {
32 return this.F.isZero(p[2]);
33 }
34
35 add(p1, p2) {
36
37 const F = this.F;
38
39 if (this.isZero(p1)) return p2;
40 if (this.isZero(p2)) return p1;
41
42 const res = new Array(3);
43
44 const Z1Z1 = F.square( p1[2] );
45 const Z2Z2 = F.square( p2[2] );
46
47 const U1 = F.mul( p1[0] , Z2Z2 ); // U1 = X1 * Z2Z2
48 const U2 = F.mul( p2[0] , Z1Z1 ); // U2 = X2 * Z1Z1
49
50 const Z1_cubed = F.mul( p1[2] , Z1Z1);
51 const Z2_cubed = F.mul( p2[2] , Z2Z2);
52
53 const S1 = F.mul( p1[1] , Z2_cubed); // S1 = Y1 * Z2 * Z2Z2
54 const S2 = F.mul( p2[1] , Z1_cubed); // S2 = Y2 * Z1 * Z1Z1
55
56 if (F.equals(U1,U2) && F.equals(S1,S2)) {
57 return this.double(p1);
58 }
59
60 const H = F.sub( U2 , U1 ); // H = U2-U1
61
62 const S2_minus_S1 = F.sub( S2 , S1 );
63
64 const I = F.square( F.add(H,H) ); // I = (2 * H)^2
65 const J = F.mul( H , I ); // J = H * I
66
67 const r = F.add( S2_minus_S1 , S2_minus_S1 ); // r = 2 * (S2-S1)
68 const V = F.mul( U1 , I ); // V = U1 * I
69
70 res[0] =
71 F.sub(
72 F.sub( F.square(r) , J ),
73 F.add( V , V )); // X3 = r^2 - J - 2 * V
74
75 const S1_J = F.mul( S1 , J );
76
77 res[1] =
78 F.sub(
79 F.mul( r , F.sub(V,res[0])),
80 F.add( S1_J,S1_J )); // Y3 = r * (V-X3)-2 S1 J
81
82 res[2] =
83 F.mul(
84 H,
85 F.sub(
86 F.square( F.add(p1[2],p2[2]) ),
87 F.add( Z1Z1 , Z2Z2 ))); // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H
88
89 return res;
90 }
91
92 neg(p) {
93 return [p[0], this.F.neg(p[1]), p[2]];
94 }
95
96 sub(a, b) {
97 return this.add(a, this.neg(b));
98 }
99
100 double(p) {
101 const F = this.F;
102
103 const res = new Array(3);
104
105 if (this.isZero(p)) return p;
106
107 const A = F.square( p[0] ); // A = X1^2
108 const B = F.square( p[1] ); // B = Y1^2
109 const C = F.square( B ); // C = B^2
110
111 let D =
112 F.sub(
113 F.square( F.add(p[0] , B )),
114 F.add( A , C));
115 D = F.add(D,D); // D = 2 * ((X1 + B)^2 - A - C)
116
117 const E = F.add( F.add(A,A), A); // E = 3 * A
118 const FF =F.square( E ); // F = E^2
119
120 res[0] = F.sub( FF , F.add(D,D) ); // X3 = F - 2 D
121
122 let eightC = F.add( C , C );
123 eightC = F.add( eightC , eightC );
124 eightC = F.add( eightC , eightC );
125
126 res[1] =
127 F.sub(
128 F.mul(
129 E,
130 F.sub( D, res[0] )),
131 eightC); // Y3 = E * (D - X3) - 8 * C
132
133 const Y1Z1 = F.mul( p[1] , p[2] );
134 res[2] = F.add( Y1Z1 , Y1Z1 ); // Z3 = 2 * Y1 * Z1
135
136 return res;
137 }
138
139 mulScalar(base, e) {
140 return fUtils.mulScalar(this, base, e);
141 }
142
143 affine(p) {
144 const F = this.F;
145 if (this.isZero(p)) {
146 return this.zero;
147 } else {
148 const Z_inv = F.inverse(p[2]);
149 const Z2_inv = F.square(Z_inv);
150 const Z3_inv = F.mul(Z2_inv, Z_inv);
151
152 const res = new Array(3);
153 res[0] = F.affine( F.mul(p[0],Z2_inv));
154 res[1] = F.affine( F.mul(p[1],Z3_inv));
155 res[2] = F.one;
156
157 return res;
158 }
159 }
160
161 equals(p1, p2) {
162 const F = this.F;
163
164 if (this.isZero(p1)) return this.isZero(p2);
165 if (this.isZero(p2)) return this.isZero(p1);
166
167 const Z1Z1 = F.square( p1[2] );
168 const Z2Z2 = F.square( p2[2] );
169
170 const U1 = F.mul( p1[0] , Z2Z2 );
171 const U2 = F.mul( p2[0] , Z1Z1 );
172
173 const Z1_cubed = F.mul( p1[2] , Z1Z1);
174 const Z2_cubed = F.mul( p2[2] , Z2Z2);
175
176 const S1 = F.mul( p1[1] , Z2_cubed);
177 const S2 = F.mul( p2[1] , Z1_cubed);
178
179 return (F.equals(U1,U2) && F.equals(S1,S2));
180 }
181
182 toString(p) {
183 const cp = this.affine(p);
184 return `[ ${this.F.toString(cp[0])} , ${this.F.toString(cp[1])} ]`;
185 }
186
187}
188
189module.exports = GCurve;
190