@ -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.
|
|
||||
} |
|
||||
} |
|