arnaucube
arnaucube/snarkjsPublic Self-hosted repository
Pairing working
Jordi Baylina jordi@baylina.cat
Tue, 14 Aug 2018 09:06:00 +0200
commit

a878d8ff5958ff133c2de57a6c6ae2276dc013e7

parent

143654c8d615f6df00851d61b8237cb9d18a3c85

A src/bn128.js

@@ -0,0 +1,325 @@

+const bigInt = require("big-integer"); +const assert = require("assert"); + +const F1Field = require("./f1field.js"); +const F2Field = require("./f2field.js"); +const F3Field = require("./f3field.js"); +const GCurve = require("./gcurve.js"); + +class BN128 { + + constructor() { + + this.q = bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583"); + this.r = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); + this.g1 = [ bigInt(1), bigInt(2) ]; + this.g2 = [ + [ + bigInt("10857046999023057135944570762232829481370756359578518086990519993285655852781"), + bigInt("11559732032986387107991004021392285783925812861821192530917403151452391805634") + ], + [ + bigInt("8495653923123431417604973247489272438418190587263600148770280649306958101930"), + bigInt("4082367875863433681332203403145435568316851327593401208105741076214120093531") + ] + ]; + + this.F1 = new F1Field(this.q); + this.F2 = new F2Field(this.F1, bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208582")); + 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") ]); + const self = this; + this.F12._mulByNonResidue = function(a) { + return [self.F2.mul(this.nonResidue, a[2]), a[0], a[1]]; + }; + + this._preparePairing(); + + } + + _preparePairing() { + 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.two_inv = this.F1.inverse(bigInt(2)); + + this.coef_b = bigInt(3); + this.twist = [bigInt(9) , bigInt(1)]; + this.twist_coeff_b = this.F2.mulEscalar( this.F2.inverse(this.twist), this.coef_b ); + + this.frobenius_coeffs_c1_1 = bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + this.twist_mul_by_q_X = + [ + bigInt("21575463638280843010398324269430826099269044274347216827212613867836435027261"), + bigInt("10307601595873709700152284273816112264069230130616436755625194854815875713954") + ]; + this.twist_mul_by_q_Y = + [ + bigInt("2821565182194536844548159561693502659359617185244120367078079554186484126554"), + bigInt("3505843767911556378687030309984248845540243509899259641013678093033130930403") + ]; + + this.final_exponent = bigInt("552484233613224096312617126783173147097382103762957654188882734314196910839907541213974502761540629817009608548654680343627701153829446747810907373256841551006201639677726139946029199968412598804882391702273019083653272047566316584365559776493027495458238373902875937659943504873220554161550525926302303331747463515644711876653177129578303191095900909191624817826566688241804408081892785725967931714097716709526092261278071952560171111444072049229123565057483750161460024353346284167282452756217662335528813519139808291170539072125381230815729071544861602750936964829313608137325426383735122175229541155376346436093930287402089517426973178917569713384748081827255472576937471496195752727188261435633271238710131736096299798168852925540549342330775279877006784354801422249722573783561685179618816480037695005515426162362431072245638324744480"); + + } + + + pairing(p1, p2) { + + const pre1 = this.precomputeG1(p1); + const pre2 = this.precomputeG2(p2); + + const r1 = this.millerLoop(pre1, pre2); + + const res = this.finalExponentiation(r1); + + 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.affine(this._g2MulByQ(Qcopy)); + assert(this.F2.equals(Q1[2], this.F2.one)); + const Q2 = this.G2.affine(this._g2MulByQ(Q1)); + assert(this.F2.equals(Q2[2], this.F2.one)); + + if (this.loopCountNef) + { + R.Y = this.F2.neg(R.Y); + } + Q2[1] = this.F2.neg(Q2[1]); + + 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.mulEscalar(c.ell_VW , pre1.PY), + this.F2.mulEscalar(c.ell_VV , pre1.PX, )); + + if (bit) + { + c = pre2.coeffs[idx++]; + f = this._mul_by_024( + f, + c.ell_0, + this.F2.mulEscalar(c.ell_VW, pre1.PY, ), + this.F2.mulEscalar(c.ell_VV, pre1.PX, )); + } + + } + + if (this.loopCountNef) + { + f = this.F12.inverse(f); + } + + c = pre2.coeffs[idx++]; + f = this._mul_by_024( + f, + c.ell_0, + this.F2.mulEscalar(c.ell_VW, pre1.PY), + this.F2.mulEscalar(c.ell_VV, pre1.PX)); + + c = pre2.coeffs[idx++]; + f = this._mul_by_024( + f, + c.ell_0, + this.F2.mulEscalar(c.ell_VW, pre1.PY, ), + this.F2.mulEscalar(c.ell_VV, pre1.PX)); + + return f; + } + + finalExponentiation(elt) { + // TODO: There is an optimization in FF + + const res = this.F12.exp(elt,this.final_exponent); + + return res; + } + + _doubleStep(current) { + const X = current.X; + const Y = current.Y; + const Z = current.Z; + + const A = this.F2.mulEscalar(this.F2.mul(X,Y), this.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.F2.add(C,C)); // D = 3 * C + const E = this.F2.mul(this.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.add( B , F ), + this.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, this.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[0]; + const y2 = base[1]; + + 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( + this.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. + } + + _g2MulByQ(p) { + const fmx = [p[0][0], this.F1.mul(p[0][1], this.frobenius_coeffs_c1_1 )]; + const fmy = [p[1][0], this.F1.mul(p[1][1], this.frobenius_coeffs_c1_1 )]; + const fmz = [p[2][0], this.F1.mul(p[2][1], this.frobenius_coeffs_c1_1 )]; + return [ + this.F2.mul(this.twist_mul_by_q_X , fmx), + this.F2.mul(this.twist_mul_by_q_Y , fmy), + fmz + ]; + } +} + +module.exports = BN128;
M src/constants.js → src/constants.js

@@ -24,8 +24,10 @@ bigInt("4082367875863433681332203403145435568316851327593401208105741076214120093531")

] ], - f2nonResidue: bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208582") - + f2nonResidue: bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208582"), + f6nonResidue: [ bigInt("9"), bigInt("1") ], + f12nonResidue: [ + ] }; const F1 = new F1Field(C.q);

@@ -35,7 +37,8 @@ C.two_inv= F1.inverse(bigInt(2));

C.coef_b = bigInt(3); C.twist = [bigInt(9) , bigInt(1)]; -// C.twist_coeff_b = F2.mulEscalar( F2.inverse(C.twist), C.coef_b ); +C.twist_coeff_b = F2.mulEscalar( F2.inverse(C.twist), C.coef_b ); module.exports = C; +
D src/f12field.js

@@ -1,55 +0,0 @@

- - - -class F12Field { - constructor(p) { - this.p = n; - } - - add(a, b) { - const maxGrade = Math.max(a.length, b.length); - const res = new Array(maxGrade); - for (let i=0; i<maxGrade; i++) { - res[i] = this.F.add(a[i], b[i]); - } - return this._reduce(res); - } - - sub(a, b) { - // TODO - throw new Error("Not Implementted"); - } - - neg(a) { - // TODO - throw new Error("Not Implementted"); - } - - mul(a, b) { - // TODO - throw new Error("Not Implementted"); - } - - inverse(a, b) { - // TODO - throw new Error("Not Implementted"); - } - - div(a, b) { - // TODO - throw new Error("Not Implementted"); - } - - isZero(a) { - // TODO - throw new Error("Not Implementted"); - } - - mul_by_024(a, ell0, ellVW, ellVV) { - // TODO - throw new Error("Not Implementted"); - } - -} - -module.exports = F2Field;
M src/f1field.js → src/f1field.js

@@ -1,4 +1,5 @@

const bigInt = require("big-integer"); +const fUtils = require("./futils.js"); class F1Field { constructor(q) {

@@ -6,10 +7,6 @@ this.q = q;

this.nq = bigInt.zero.minus(q); this.zero = bigInt.zero; this.one = bigInt.one; - } - - e(a) { - return bigInt(a); } copy(a) {

@@ -18,6 +15,10 @@ }

add(a, b) { return a.add(b); + } + + double(a) { + return this.add(a,a); } sub(a, b) {

@@ -67,6 +68,14 @@ aux = aux.mod(this.q);

} } return aux; + } + + mulEscalar(base, e) { + return fUtils.mulEscalar(this, base, e); + } + + exp(base, e) { + return fUtils.exp(this, base, e); } toString(a) {
M src/f2field.js → src/f2field.js

@@ -1,4 +1,4 @@

-const bigInt = require("big-integer"); +const fUtils = require("./futils.js"); class F2Field { constructor(F, nonResidue) {

@@ -8,8 +8,8 @@ this.one = [this.F.one, this.F.zero];

this.nonResidue = nonResidue; } - e(c0, c1) { - return [bigInt(c0), bigInt(c1)]; + _mulByNonResidue(a) { + return this.F.mul(this.nonResidue, a); } copy(a) {

@@ -23,6 +23,10 @@ this.F.add(a[1], b[1])

]; } + double(a) { + return this.add(a,a); + } + sub(a, b) { return [ this.F.sub(a[0], b[0]),

@@ -39,7 +43,7 @@ const aA = this.F.mul(a[0] , b[0]);

const bB = this.F.mul(a[1] , b[1]); return [ - this.F.add( aA , this.F.mul(this.nonResidue , bB)), + this.F.add( aA , this._mulByNonResidue(bB)), this.F.sub( this.F.mul( this.F.add(a[0], a[1]),

@@ -50,7 +54,7 @@

inverse(a) { const t0 = this.F.square(a[0]); const t1 = this.F.square(a[1]); - const t2 = this.F.sub(t0, this.F.mul(this.nonResidue, t1)); + const t2 = this.F.sub(t0, this._mulByNonResidue(t1)); const t3 = this.F.inverse(t2); return [ this.F.mul(a[0], t3),

@@ -77,10 +81,10 @@ this.F.mul(

this.F.add(a[0], a[1]) , this.F.add( a[0] , - this.F.mul(this.nonResidue , a[1]))), + this._mulByNonResidue(a[1]))), this.F.add( ab, - this.F.mul(this.nonResidue, ab))), + this._mulByNonResidue(ab))), this.F.add(ab, ab) ]; }

@@ -95,6 +99,14 @@ }

affine(a) { return [this.F.affine(a[0]), this.F.affine(a[1])]; + } + + mulEscalar(base, e) { + return fUtils.mulEscalar(this, base, e); + } + + exp(base, e) { + return fUtils.exp(this, base, e); } toString(a) {
A src/f3field.js

@@ -0,0 +1,158 @@

+const fUtils = require("./futils.js"); + +class F3Field { + constructor(F, nonResidue) { + this.F = F; + this.zero = [this.F.zero, this.F.zero, this.F.zero]; + this.one = [this.F.one, this.F.zero, this.F.zero]; + this.nonResidue = nonResidue; + } + + _mulByNonResidue(a) { + return this.F.mul(this.nonResidue, a); + } + + copy(a) { + return [this.F.copy(a[0]), this.F.copy(a[1]), this.F.copy(a[2])]; + } + + add(a, b) { + return [ + this.F.add(a[0], b[0]), + this.F.add(a[1], b[1]), + this.F.add(a[2], b[2]) + ]; + } + + double(a) { + return this.add(a,a); + } + + sub(a, b) { + return [ + this.F.sub(a[0], b[0]), + this.F.sub(a[1], b[1]), + this.F.sub(a[2], b[2]) + ]; + } + + neg(a) { + return this.sub(this.zero, a); + } + + mul(a, b) { + + const aA = this.F.mul(a[0] , b[0]); + const bB = this.F.mul(a[1] , b[1]); + const cC = this.F.mul(a[2] , b[2]); + + return [ + this.F.add( + aA, + this._mulByNonResidue( + this.F.sub( + this.F.mul( + this.F.add(a[1], a[2]), + this.F.add(b[1], b[2])), + this.F.add(bB, cC)))), // aA + non_residue*((b+c)*(B+C)-bB-cC), + + this.F.add( + this.F.sub( + this.F.mul( + this.F.add(a[0], a[1]), + this.F.add(b[0], b[1])), + this.F.add(aA, bB)), + this._mulByNonResidue( cC)), // (a+b)*(A+B)-aA-bB+non_residue*cC + + this.F.add( + this.F.sub( + this.F.mul( + this.F.add(a[0], a[2]), + this.F.add(b[0], b[2])), + this.F.add(aA, cC)), + bB)]; // (a+c)*(A+C)-aA+bB-cC) + } + + inverse(a) { + const t0 = this.F.square(a[0]); // t0 = a^2 ; + const t1 = this.F.square(a[1]); // t1 = b^2 ; + const t2 = this.F.square(a[2]); // t2 = c^2; + const t3 = this.F.mul(a[0],a[1]); // t3 = ab + const t4 = this.F.mul(a[0],a[2]); // t4 = ac + const t5 = this.F.mul(a[1],a[2]); // t5 = bc; + // c0 = t0 - non_residue * t5; + const c0 = this.F.sub(t0, this._mulByNonResidue(t5)); + // c1 = non_residue * t2 - t3; + const c1 = this.F.sub(this._mulByNonResidue(t2), t3); + const c2 = this.F.sub(t1, t4); // c2 = t1-t4 + + // t6 = (a * c0 + non_residue * (c * c1 + b * c2)).inverse(); + const t6 = + this.F.inverse( + this.F.add( + this.F.mul(a[0], c0), + this._mulByNonResidue( + this.F.add( + this.F.mul(a[2], c1), + this.F.mul(a[1], c2))))); + + return [ + this.F.mul(t6, c0), // t6*c0 + this.F.mul(t6, c1), // t6*c1 + this.F.mul(t6, c2)]; // t6*c2 + } + + div(a, b) { + return this.mul(a, this.inverse(b)); + } + + square(a) { + const s0 = this.F.square(a[0]); // s0 = a^2 + const ab = this.F.mul(a[0], a[1]); // ab = a*b + const s1 = this.F.add(ab, ab); // s1 = 2ab; + const s2 = this.F.square( + this.F.add(this.F.sub(a[0],a[1]), a[2])); // s2 = (a - b + c)^2; + const bc = this.F.mul(a[1],a[2]); // bc = b*c + const s3 = this.F.add(bc, bc); // s3 = 2*bc + const s4 = this.F.square(a[2]); // s4 = c^2 + + + return [ + this.F.add( + s0, + this._mulByNonResidue(s3)), // s0 + non_residue * s3, + this.F.add( + s1, + this._mulByNonResidue(s4)), // s1 + non_residue * s4, + this.F.sub( + this.F.add( this.F.add(s1, s2) , s3 ), + this.F.add(s0, s4))]; // s1 + s2 + s3 - s0 - s4 + } + + isZero(a) { + return this.F.isZero(a[0]) && this.F.isZero(a[1]) && this.F.isZero(a[2]); + } + + equals(a, b) { + return this.F.equals(a[0], b[0]) && this.F.equals(a[1], b[1]) && this.F.equals(a[2], b[2]); + } + + affine(a) { + return [this.F.affine(a[0]), this.F.affine(a[1]), this.F.affine(a[2])]; + } + + mulEscalar(base, e) { + return fUtils.mulEscalar(this, base, e); + } + + exp(base, e) { + return fUtils.exp(this, base, e); + } + + toString(a) { + const cp = this.affine(a); + return `[ ${this.F.toString(cp[0])} , ${this.F.toString(cp[1])}, ${this.F.toString(cp[2])} ]`; + } +} + +module.exports = F3Field;
A src/futils.js

@@ -0,0 +1,34 @@

+const bigInt = require("big-integer"); + +exports.mulEscalar = (F, base, e) =>{ + let res = F.zero; + let rem = bigInt(e); + let exp = base; + + while (! rem.isZero()) { + if (rem.isOdd()) { + res = F.add(res, exp); + } + exp = F.double(exp); + rem = rem.shiftRight(1); + } + + return res; +}; + + +exports.exp = (F, base, e) =>{ + let res = F.one; + let rem = bigInt(e); + let exp = base; + + while (! rem.isZero()) { + if (rem.isOdd()) { + res = F.mul(res, exp); + } + exp = F.square(exp); + rem = rem.shiftRight(1); + } + + return res; +};
M src/gcurve.js → src/gcurve.js

@@ -1,3 +1,4 @@

+const fUtils = require("./futils.js"); class GCurve {

@@ -105,19 +106,7 @@ return res;

} mulEscalar(base, e) { - let res = this.zero; - let rem = e; - let exp = base; - - while (! rem.isZero()) { - if (rem.isOdd()) { - res = this.add(res, exp); - } - exp = this.double(exp); - rem = rem.shiftRight(1); - } - - return res; + return fUtils.mulEscalar(this, base, e); } affine(p) {
D src/gt.js

@@ -1,20 +0,0 @@

-const bigInt = require("big-integer"); -const ZnField = require("./znfield.js"); - -module.eports = class Gt { - - constructor() { - // TODO - throw new Error("Not Implementted"); - } - - mul(p1, p2) { - // TODO - throw new Error("Not Implementted"); - } - - equal(p1, p2) { - // TODO - throw new Error("Not Implementted"); - } -};
M src/pairing.js → src/pairing.js

@@ -4,11 +4,10 @@ */

const assert = require("assert"); const bigInt = require("big-integer"); -const F1Field = require("f1field"); -const F2Field = require("f2field"); -const F12Field = require("f12field"); -const G1Curve = require("g1curve"); -const G2Curve = require("g2curve"); +const F1Field = require("./f1field"); +const F2Field = require("./f2field"); +const F3Field = require("./f3field"); +const GCurve = require("./gcurve"); const constants = require("constants"); module.exports = new Pairing();

@@ -16,8 +15,8 @@

class Pairing { - constructor() { - this.loopCount = bigInt(11);// CONSTANT + constructor(curve) { + this.loopCount = bigInt("29793968203157093288");// CONSTANT // Set loopCountNeg if (this.loopCount.isNegative()) {

@@ -30,18 +29,17 @@

// Set loop_count_bits let lc = this.loopCount; this.loop_count_bits = []; // Constant - while (lc) { + while (!lc.isZero()) { this.loop_count_bits.push( lc.isOdd() ); lc = lc.shiftRight(1); } - this.F12 = new F12Field(constants.q); - this.F2 = new F2Field(constants.q); - this.F1 = new F1Field(constants.q); - this.G1 = new GCurve(F1, constants.g1); - this.G2 = new GCurve(F2, constants.g2); - - this.twoInv = this.F1.inverse(bigInt(2)); + 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) {

@@ -134,7 +132,7 @@ order */

c = pre2.coeffs[idx++]; f = this.F12.square(f); - f = this.F12.mul_by_024( + f = this._mul_by_024( f, c.ell_0, this.F2.mul(pre1.PY, c.ell_VW),

@@ -143,7 +141,7 @@

if (bit) { c = pre2.coeffs[idx++]; - f = this.F12.mul_by_024( + f = this._mul_by_024( f, c.ell_0, this.F2.mul(pre1.PY, c.ell_VW),

@@ -158,14 +156,14 @@ f = this.F12.inverse(f);

} c = pre2.coeffs[idx++]; - f = this.F12.mul_by_024( + 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.F12.mul_by_024( + f = this._mul_by_024( f, c.ell_0, this.F2.mul(pre1.PY, c.ell_VW),

@@ -249,5 +247,17 @@ 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. } }
M test/algebra.js → test/algebra.js

@@ -1,72 +1,151 @@

+const chai = require("chai"); + const bigInt = require("big-integer"); -const F1Field = require("../src/f1field.js"); -const F2Field = require("../src/f2field.js"); -const GCurve = require("../src/gcurve.js"); -const constants = require("../src/constants.js"); -const chai = require("chai"); +const BN128 = require("../src/BN128.js"); const assert = chai.assert; describe("Curve G1 Test", () => { - it ("r*one == 0", () => { - const F1 = new F1Field(constants.q); - const G1 = new GCurve(F1, constants.g1); + it("r*one == 0", () => { + const bn128 = new BN128(); - const res = G1.mulEscalar(G1.g, constants.r); + const res = bn128.G1.mulEscalar(bn128.G1.g, bn128.r); - assert(G1.equals(res, G1.zero), "G1 does not have range r"); + assert(bn128.G1.equals(res, bn128.G1.zero), "G1 does not have range r"); }); it("Should add match in various in G1", () => { - const F1 = new F1Field(constants.q); - const G1 = new GCurve(F1, constants.g1); + + const bn128 = new BN128(); const r1 = bigInt(33); const r2 = bigInt(44); - const gr1 = G1.mulEscalar(G1.g, r1); - const gr2 = G1.mulEscalar(G1.g, r2); + const gr1 = bn128.G1.mulEscalar(bn128.G1.g, r1); + const gr2 = bn128.G1.mulEscalar(bn128.G1.g, r2); - const grsum1 = G1.add(gr1, gr2); + const grsum1 = bn128.G1.add(gr1, gr2); - const grsum2 = G1.mulEscalar(G1.g, r1.add(r2)); + const grsum2 = bn128.G1.mulEscalar(bn128.G1.g, r1.add(r2)); - assert(G1.equals(grsum1, grsum2)); + assert(bn128.G1.equals(grsum1, grsum2)); }); }); describe("Curve G2 Test", () => { it ("r*one == 0", () => { - const F1 = new F1Field(constants.q); - const F2 = new F2Field(F1, constants.f2nonResidue); - const G2 = new GCurve(F2, constants.g2); + const bn128 = new BN128(); - const res = G2.mulEscalar(G2.g, constants.r); + const res = bn128.G2.mulEscalar(bn128.G2.g, bn128.r); - assert(G2.equals(res, G2.zero), "G2 does not have range r"); + assert(bn128.G2.equals(res, bn128.G2.zero), "G2 does not have range r"); }); it("Should add match in various in G2", () => { - const F1 = new F1Field(constants.q); - const F2 = new F2Field(F1, constants.f2nonResidue); - const G2 = new GCurve(F2, constants.g2); + const bn128 = new BN128(); const r1 = bigInt(33); const r2 = bigInt(44); - const gr1 = G2.mulEscalar(G2.g, r1); - const gr2 = G2.mulEscalar(G2.g, r2); + const gr1 = bn128.G2.mulEscalar(bn128.G2.g, r1); + const gr2 = bn128.G2.mulEscalar(bn128.G2.g, r2); - const grsum1 = G2.add(gr1, gr2); + const grsum1 = bn128.G2.add(gr1, gr2); - const grsum2 = G2.mulEscalar(G2.g, r1.add(r2)); + const grsum2 = bn128.G2.mulEscalar(bn128.G2.g, r1.add(r2)); /* console.log(G2.toString(grsum1)); console.log(G2.toString(grsum2)); */ - assert(G2.equals(grsum1, grsum2)); + assert(bn128.G2.equals(grsum1, grsum2)); + }); +}); + +describe("F6 testing", () => { + it("Should multiply and divide in F6", () => { + const bn128 = new BN128(); + const a = + [ + [bigInt("1"), bigInt("2")], + [bigInt("3"), bigInt("4")], + [bigInt("5"), bigInt("6")] + ]; + const b = + [ + [bigInt("12"), bigInt("11")], + [bigInt("10"), bigInt("9")], + [bigInt("8"), bigInt("7")] + ]; + const c = bn128.F6.mul(a,b); + const d = bn128.F6.div(c,b); + + assert(bn128.F6.equals(a, d)); + }); +}); + +describe("F12 testing", () => { + it("Should multiply and divide in F12", () => { + const bn128 = new BN128(); + const a = + [ + [ + [bigInt("1"), bigInt("2")], + [bigInt("3"), bigInt("4")], + [bigInt("5"), bigInt("6")] + ], + [ + [bigInt("7"), bigInt("8")], + [bigInt("9"), bigInt("10")], + [bigInt("11"), bigInt("12")] + ] + ]; + const b = + [ + [ + [bigInt("12"), bigInt("11")], + [bigInt("10"), bigInt("9")], + [bigInt("8"), bigInt("7")] + ], + [ + [bigInt("6"), bigInt("5")], + [bigInt("4"), bigInt("3")], + [bigInt("2"), bigInt("1")] + ] + ]; + const c = bn128.F12.mul(a,b); + const d = bn128.F12.div(c,b); + + assert(bn128.F12.equals(a, d)); }); +}); + +describe("Pairing", () => { + it("Should match pairing", () => { + const bn128 = new BN128(); + + + const g1a = bn128.G1.mulEscalar(bn128.G1.g, 25); + const g2a = bn128.G2.mulEscalar(bn128.G2.g, 30); + + const g1b = bn128.G1.mulEscalar(bn128.G1.g, 30); + const g2b = bn128.G2.mulEscalar(bn128.G2.g, 25); + + + const pre1a = bn128.precomputeG1(g1a); + const pre2a = bn128.precomputeG2(g2a); + const pre1b = bn128.precomputeG1(g1b); + const pre2b = bn128.precomputeG2(g2b); + + const r1 = bn128.millerLoop(pre1a, pre2a); + const r2 = bn128.millerLoop(pre1b, pre2b); + + const rbe = bn128.F12.mul(r1, bn128.F12.inverse(r2)); + + const res = bn128.finalExponentiation(rbe); + + assert(bn128.F12.equals(res, bn128.F12.one)); + }).timeout(10000); });