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