arnaucube
arnaucube/snarkjsPublic Self-hosted repository
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