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