diff --git a/src/bn128.js b/src/bn128.js index 03f7e29..9142d0b 100644 --- a/src/bn128.js +++ b/src/bn128.js @@ -24,12 +24,15 @@ class BN128 { ] ]; + this.nonResidueF2 = bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + this.nonResidueF6 = [ bigInt("9"), bigInt("1") ]; + this.F1 = new F1Field(this.q); - this.F2 = new F2Field(this.F1, bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208582")); + this.F2 = new F2Field(this.F1, this.nonResidueF2); this.G1 = new GCurve(this.F1, this.g1); this.G2 = new GCurve(this.F2, this.g2); - this.F6 = new F3Field(this.F2, [ bigInt("9"), bigInt("1") ]); - this.F12 = new F2Field(this.F6, [ bigInt("9"), bigInt("1") ]); + this.F6 = new F3Field(this.F2, this.nonResidueF6); + this.F12 = new F2Field(this.F6, this.nonResidueF6); const self = this; this.F12._mulByNonResidue = function(a) { return [self.F2.mul(this.nonResidue, a[2]), a[0], a[1]]; @@ -300,6 +303,8 @@ class BN128 { _mul_by_024(a, ell_0, ell_VW, ell_VV) { + // Old implementation + const b = [ [ell_0, this.F2.zero, ell_VV], [this.F2.zero, ell_VW, this.F2.zero] @@ -307,7 +312,91 @@ class BN128 { return this.F12.mul(a,b); - // TODO There is a better version on libff. It should be ported. + /* + // This is a new implementation, + // But it does not look worthy + // at least in javascript. + + let z0 = a[0][0]; + let z1 = a[0][1]; + let z2 = a[0][2]; + let z3 = a[1][0]; + let z4 = a[1][1]; + let z5 = a[1][2]; + + const x0 = ell_0; + const x2 = ell_VV; + const x4 = ell_VW; + + const D0 = this.F2.mul(z0, x0); + const D2 = this.F2.mul(z2, x2); + const D4 = this.F2.mul(z4, x4); + const t2 = this.F2.add(z0, z4); + let t1 = this.F2.add(z0, z2); + const s0 = this.F2.add(this.F2.add(z1,z3),z5); + + // For z.a_.a_ = z0. + let S1 = this.F2.mul(z1, x2); + let T3 = this.F2.add(S1, D4); + let T4 = this.F2.add( this.F2.mul(this.nonResidueF6, T3),D0); + z0 = T4; + + // For z.a_.b_ = z1 + T3 = this.F2.mul(z5, x4); + S1 = this.F2.add(S1, T3); + T3 = this.F2.add(T3, D2); + T4 = this.F2.mul(this.nonResidueF6, T3); + T3 = this.F2.mul(z1, x0); + S1 = this.F2.add(S1, T3); + T4 = this.F2.add(T4, T3); + z1 = T4; + + // For z.a_.c_ = z2 + let t0 = this.F2.add(x0, x2); + T3 = this.F2.sub( + this.F2.mul(t1, t0), + this.F2.add(D0, D2)); + T4 = this.F2.mul(z3, x4); + S1 = this.F2.add(S1, T4); + T3 = this.F2.add(T3, T4); + + // For z.b_.a_ = z3 (z3 needs z2) + t0 = this.F2.add(z2, z4); + z2 = T3; + t1 = this.F2.add(x2, x4); + T3 = this.F2.sub( + this.F2.mul(t0,t1), + this.F2.add(D2, D4)); + + T4 = this.F2.mul(this.nonResidueF6, T3); + T3 = this.F2.mul(z3, x0); + S1 = this.F2.add(S1, T3); + T4 = this.F2.add(T4, T3); + z3 = T4; + + // For z.b_.b_ = z4 + T3 = this.F2.mul(z5, x2); + S1 = this.F2.add(S1, T3); + T4 = this.F2.mul(this.nonResidueF6, T3); + t0 = this.F2.add(x0, x4); + T3 = this.F2.sub( + this.F2.mul(t2,t0), + this.F2.add(D0, D4)); + T4 = this.F2.add(T4, T3); + z4 = T4; + + // For z.b_.c_ = z5. + t0 = this.F2.add(this.F2.add(x0, x2), x4); + T3 = this.F2.sub(this.F2.mul(s0, t0), S1); + z5 = T3; + + return [ + [z0, z1, z2], + [z3, z4, z5] + ]; + + */ + } _g2MulByQ(p) { diff --git a/src/pairing.js b/src/pairing.js deleted file mode 100644 index ae69216..0000000 --- a/src/pairing.js +++ /dev/null @@ -1,263 +0,0 @@ -/* -This module calculate the pairing of p1 and p2 where p1 in G1 and p2 in G2 - */ - -const assert = require("assert"); -const bigInt = require("big-integer"); -const F1Field = require("./f1field"); -const F2Field = require("./f2field"); -const F3Field = require("./f3field"); -const GCurve = require("./gcurve"); -const constants = require("constants"); - -module.exports = new Pairing(); - - -class Pairing { - - constructor(curve) { - this.loopCount = bigInt("29793968203157093288");// CONSTANT - - // Set loopCountNeg - if (this.loopCount.isNegative()) { - this.loopCount = this.neg(); - this.loopCountNeg = true; - } else { - this.loopCountNeg = false; - } - - // Set loop_count_bits - let lc = this.loopCount; - this.loop_count_bits = []; // Constant - while (!lc.isZero()) { - this.loop_count_bits.push( lc.isOdd() ); - lc = lc.shiftRight(1); - } - - this.F1 = curve.F1; - this.F2 = curve.F2; - this.G1 = curve.G1; - this.G2 = curve.G2; - this.F6 = curve.F6; - this.F12 = curve.F12; - } - - pairing(p1, p2) { - - const pre1 = this._precomputeG1(p1); - const pre2 = this._precomputeG2(p2); - - const res = this._millerLoop(pre1, pre2); - - return res; - } - - - _precomputeG1(p) { - const Pcopy = this.G1.affine(p); - - const res = {}; - res.PX = Pcopy[0]; - res.PY = Pcopy[1]; - - return res; - } - - _precomputeG2(p) { - - const Qcopy = this.G2.affine(p); - - const res = { - QX: Qcopy[0], - QY: Qcopy[1], - coeffs: [] - }; - - const R = { - X: Qcopy[0], - Y: Qcopy[1], - Z: this.F2.one - }; - - let c; - - for (let i = this.loop_count_bits.length-2; i >= 0; --i) - { - const bit = this.loop_count_bits[i]; - - c = this._doubleStep(R); - res.coeffs.push(c); - - if (bit) - { - c = this._addStep(Qcopy, R); - res.coeffs.push(c); - } - } - - const Q1 = this.G2.mul_by_q(Qcopy); // TODO mul_by_q - assert(this.F2.equal(Q1[2], this.F2.one)); - const Q2 = this.G2.mul_by_q(Q1); - assert(this.F2.equal(Q2[2], this.F2.one)); - - if (this.loopCountNef) - { - R.Y = this.F2.neg(R.Y); - } - Q2.Y = this.F2.neg(Q2.Y); - - c = this._addStep(Q1, R); - res.coeffs.push(c); - - c = this._addStep(Q2, R); - res.coeffs.push(c); - - return res; - } - - _millerLoop(pre1, pre2) { - let f = this.F12.one; - - let idx = 0; - - let c; - - for (let i = this.loop_count_bits.length-2; i >= 0; --i) - { - const bit = this.loop_count_bits[i]; - - /* code below gets executed for all bits (EXCEPT the MSB itself) of - alt_bn128_param_p (skipping leading zeros) in MSB to LSB - order */ - - c = pre2.coeffs[idx++]; - f = this.F12.square(f); - f = this._mul_by_024( - f, - c.ell_0, - this.F2.mul(pre1.PY, c.ell_VW), - this.F2.mul(pre1.PX, c.ell_VV)); - - if (bit) - { - c = pre2.coeffs[idx++]; - f = this._mul_by_024( - f, - c.ell_0, - this.F2.mul(pre1.PY, c.ell_VW), - this.F2.mul(pre1.PX, c.ell_VV)); - } - - } - - if (this.loopCountNef) - { - f = this.F12.inverse(f); - } - - c = pre2.coeffs[idx++]; - f = this._mul_by_024( - f, - c.ell_0, - this.F2.mul(pre1.PY, c.ell_VW), - this.F2.mul(pre1.PX, c.ell_VV)); - - c = pre2.coeffs[idx++]; - f = this._mul_by_024( - f, - c.ell_0, - this.F2.mul(pre1.PY, c.ell_VW), - this.F2.mul(pre1.PX, c.ell_VV)); - - return f; - } - - _doubleStep(current) { - const X = current.X; - const Y = current.Y; - const Z = current.Z; - - const A = this.F2.mulEscalar(this.F1.mul(X,Y), constants.two_inv); // A = X1 * Y1 / 2 - const B = this.F2.square(Y); // B = Y1^2 - const C = this.F2.square(Z); // C = Z1^2 - const D = this.F2.add(C, this.F1.add(C,C)); // D = 3 * C - const E = this.F2.mul(constants.twist_coeff_b, D); // E = twist_b * D - const F = this.F2.add(E, this.F2.add(E,E)); // F = 3 * E - const G = - this.F2.mulEscalar( - this.F2.sum( B , F ), - constants.two_inv); // G = (B+F)/2 - const H = - this.F2.sub( - this.F2.square( this.F2.add(Y,Z) ), - this.F2.add( B , C)); // H = (Y1+Z1)^2-(B+C) - const I = this.F2.sub(E, B); // I = E-B - const J = this.F2.square(X); // J = X1^2 - const E_squared = this.F2.square(E); // E_squared = E^2 - - current.X = this.F2.mul( A, this.F2.sub(B,F) ); // X3 = A * (B-F) - current.Y = - this.F2.sub( - this.F2.sub( this.F2.square(G) , E_squared ), - this.F2.add( E_squared , E_squared )); // Y3 = G^2 - 3*E^2 - current.Z = this.F2.mul( B, H ); // Z3 = B * H - const c = { - ell_0 : this.F2.mul( I, constants.twist), // ell_0 = xi * I - ell_VW: this.F2.neg( H ), // ell_VW = - H (later: * yP) - ell_VV: this.F2.add( J , this.F2.add(J,J) ) // ell_VV = 3*J (later: * xP) - }; - - return c; - } - - _addStep(base, current) { - - const X1 = current.X; - const Y1 = current.Y; - const Z1 = current.Z; - const x2 = base.X; - const y2 = base.Y; - - const D = this.F2.sub( X1, this.F2.mul(x2,Z1) ); // D = X1 - X2*Z1 - const E = this.F2.sub( Y1, this.F2.mul(y2,Z1) ); // E = Y1 - Y2*Z1 - const F = this.F2.square(D); // F = D^2 - const G = this.F2.square(E); // G = E^2 - const H = this.F2.mul(D,F); // H = D*F - const I = this.F2.mul(X1,F); // I = X1 * F - const J = - this.F2.sub( - this.F2.add( H, this.F2.mul(Z1,G) ), - this.F2.add( I, I )); // J = H + Z1*G - (I+I) - - current.X = this.F2.mul( D , J ); // X3 = D*J - current.Y = - this.F2.sub( - this.F2.mul( E , this.F2.sub(I,J) ), - this.F2.mul( H , Y1)); // Y3 = E*(I-J)-(H*Y1) - current.Z = this.F2.mul(Z1,H); - const c = { - ell_0 : - this.F2.mul( - constants.twist, - this.F2.sub( - this.F2.mul(E , x2), - this.F2.mul(D , y2))), // ell_0 = xi * (E * X2 - D * Y2) - ell_VV : this.F2.neg(E), // ell_VV = - E (later: * xP) - ell_VW : D // ell_VW = D (later: * yP ) - }; - - return c; - } - - _mul_by_024(a, ell_0, ell_VW, ell_VV) { - - const b = [ - [ell_0, this.F2.zero, ell_VV], - [this.F2.zero, ell_VW, this.F2.zero] - ]; - - return this.F12.mul(a,b); - - // TODO There is a better version on libff. It should be ported. - } -}