refactor curve and add tests
Jordi Baylina jordi@baylina.cat
Sun, 12 Aug 2018 20:37:43 +0200
12 files changed,
670 insertions(+),
183 deletions(-)
M
package-lock.json
→
package-lock.json
@@ -74,6 +74,11 @@ "version": "1.0.1",
"resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" + }, "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",@@ -138,6 +143,19 @@ "version": "0.2.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=" }, + "chai": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz", + "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", + "requires": { + "assertion-error": "^1.0.1", + "check-error": "^1.0.1", + "deep-eql": "^3.0.0", + "get-func-name": "^2.0.0", + "pathval": "^1.0.0", + "type-detect": "^4.0.0" + } + }, "chalk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",@@ -170,6 +188,11 @@ "chardet": {
"version": "0.4.2", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=" + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" }, "circular-json": { "version": "0.3.3",@@ -227,6 +250,14 @@ "requires": {
"ms": "2.0.0" } }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "requires": { + "type-detect": "^4.0.0" + } + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",@@ -477,6 +508,11 @@ "version": "1.0.1",
"resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=" + }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",@@ -798,6 +834,11 @@ "version": "2.0.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=" + }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",@@ -1032,6 +1073,11 @@ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
"requires": { "prelude-ls": "~1.1.2" } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" }, "uri-js": { "version": "4.2.2",
M
package.json
→
package.json
@@ -19,6 +19,7 @@ "author": "Jordi Baylina",
"license": "GPL-3.0", "dependencies": { "big-integer": "^1.6.34", + "chai": "^4.1.2", "eslint": "^5.3.0" }, "devDependencies": {
A
src/constants.js
@@ -0,0 +1,39 @@
+const bigInt = require("big-integer"); + +const F1Field = require("./f1field"); +const F2Field = require("./f1field"); + +const C = { + + // Module of the field + q : bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583"), + + // Order of the group + r : bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"), + + g1 : [ bigInt(1), bigInt(2) ], + g2 : + [ + [ + bigInt("10857046999023057135944570762232829481370756359578518086990519993285655852781"), + bigInt("11559732032986387107991004021392285783925812861821192530917403151452391805634") + ], + [ + bigInt("8495653923123431417604973247489272438418190587263600148770280649306958101930"), + bigInt("4082367875863433681332203403145435568316851327593401208105741076214120093531") + ] + ] + +}; + +const F1 = new F1Field(C.q); +const F2 = new F2Field(C.q); + +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 ); + + +module.exports = C;
A
src/f12field.js
@@ -0,0 +1,55 @@
+ + + +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;
A
src/f1field.js
@@ -0,0 +1,78 @@
+const bigInt = require("big-integer"); + +class F1Field { + constructor(q) { + this.q = q; + this.nq = bigInt.zero.minus(q); + this.zero = bigInt.zero; + this.one = bigInt.one; + } + + e(a) { + return bigInt(a); + } + + copy(a) { + return bigInt(a); + } + + add(a, b) { + return a.add(b); + } + + sub(a, b) { + return a.minus(b); + } + + neg(a) { + return bigInt.zero.minus(a); + } + + mul(a, b) { + return a.times(b).mod(this.q); + } + + inverse(a) { + return this.affine(a).modInv(this.q); + } + + div(a, b) { + return this.mul(a, this.inverse(b)); + } + + square(a) { + return a.square().mod(this.q); + } + + isZero(a) { + return a.isZero(); + } + + equals(a, b) { + return this.affine(a).equals(this.affine(b)); + } + + affine(a) { + let aux = a; + if (aux.isNegative()) { + if (aux.lesserOrEquals(this.nq)) { + aux = a.mod(this.q); + } + if (aux.isNegative()) { + aux = aux.add(this.q); + } + } else { + if (aux.greaterOrEquals(this.q)) { + aux = aux.mod(this.q); + } + } + return aux; + } + + toString(a) { + const ca = this.affine(a); + return `"0x${ca.toString(16)}"`; + } +} + +module.exports = F1Field;
D
src/g1curve.js
@@ -1,147 +0,0 @@
-const bigInt = require("big-integer"); - -const q = new bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583"); - -module.eports = class G1Curve { - - constructor() { - this.g = [ bigInt(1), bigInt(2), bigInt(1) ]; - this.zero = [ bigInt(0), bigInt(1), bigInt(0) ]; - } - - isZero(p) { - return p[2].isZero(); - } - add(p1, p2) { - - if (this.isZero(p1)) return p2; - if (this.isZero(p2)) return p1; - - const res = new Array(3); - - const Z1Z1 = p1[2].square().mod(q); - const Z2Z2 = p2[2].square().mod(q); - - const U1 = p1[0].times(Z2Z2).mod(q); - const U2 = p2[0].times(Z1Z1).mod(q); - - const Z1_cubed = p1[2].times(Z1Z1).mod(q); - const Z2_cubed = p2[2].times(Z2Z2).mod(q); - - const S1 = p1[1].times(Z2_cubed).mod(q); - const S2 = p2[1].times(Z1_cubed).mod(q); - - if (U1.equals(U2) && (S1.equals(S2))) { - return this.double(p1); - } - - let H = U2.minus(U1); - if (H.isNegative()) H = H.add(q); - - let S2_minus_S1 = S2.minus(S1); - if (S2_minus_S1.isNegative()) S2_minus_S1 = S2_minus_S1.add(q); - - const I = H.add(H).square().mod(q); - const J = H.times(I).mod(q); - - const r = S2_minus_S1.add(S2_minus_S1); - const V = U1.times(I).mod(q); - - res[0] = r.square().minus(J).minus(V).minus(V).mod(q); - if (res[0].isNegative()) res[0] = res[0].add(q); - - const S1_J = S1.times(J).mod(q); - - res[1] = r.times(V.minus(res[0])).minus(S1_J).minus(S1_J).mod(q); - if (res[1].isNegative()) res[1] = res[1].add(q); - - res[2] = p1[2].add(p2[2]).square().minus(Z1Z1).minus(Z2Z2).mod(q); - res[2] = res[2].times(H).mod(q); - if (res[2].isNegative()) res[2] = res[2].add(q); - - return res; - } - - double(p) { - const res = new Array(3); - - if (this.isZero(p)) return p; - - const A = p[0].square().mod(q); - const B = p[1].square().mod(q); - const C = B.square().mod(q); - - let D = p[0].add(B).square().minus(A).minus(C); - D = D.add(D); - - const E = A.times(3); - const F = E.square(); - - res[0] = F.minus(D).minus(D).mod(q); - if (res[0].isNegative()) res[0] = res[0].add(q); - - const eightC = C.times(8); - - res[1] = E.times(D.minus(res[0])).minus(eightC).mod(q); - if (res[1].isNegative()) res[1] = res[1].add(q); - - const Y1Z1 = p[1].times(p[2]); - res[2] = Y1Z1.add(Y1Z1).mod(q); - - return res; - } - - toAffineCoordinates(p) { - if (this.isZero(p)) { - return this.zero; - } else { - const Z_inv = p[2].modInv(q); - const Z2_inv = Z_inv.square().mod(q); - const Z3_inv = Z2_inv.times(Z_inv).mod(q); - - const res = new Array(3); - res[0] = p[0].times(Z2_inv).mod(q); - res[1] = p[1].times(Z3_inv).mod(q); - res[2] = bigInt(1); - - 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; - } - -}; - -const G1 = new module.eports(); - - -const r = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); -// const np = G1.mulEscalar(G1.g, bigInt(2)); - -const np = G1.mulEscalar(G1.g, r.add(1)); -const p = G1.toAffineCoordinates(np); - -/* -const np2 = G1.add(G1.g, G1.g); -const np3 = G1.add(G1.g, np2); - -const p = G1.toAffineCoordinates(np3); -*/ - -console.log(p[0].toString() + ", " + p[1].toString() + ", " + p[2].toString()); - -
D
src/g2curve.js
@@ -1,28 +0,0 @@
-const bigInt = require("big-integer"); -const ZnField = require("./znfield.js"); - -module.eports = class G2Curve { - - constructor() { - this.F = new ZnField(bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583")); - this.g = [ - - ]; - } - - add(p1, p2) { - // TODO - throw new Error("Not Implementted"); - } - - double(p1) { - // TODO - throw new Error("Not Implementted"); - } - - mulEscalar(p1, e) { - // TODO - throw new Error("Not Implementted"); - } - -};
A
src/gcurve.js
@@ -0,0 +1,167 @@
+ +class GCurve { + + constructor(F, g) { + this.F = F; + this.g = F.copy(g); + if (this.g.length == 2) this.g[2] = this.F.one; + this.zero = [this.F.zero, this.F.one, this.F.zero]; + } + + isZero(p) { + return this.F.isZero(p[2]); + } + + add(p1, p2) { + + if (this.isZero(p1)) return p2; + if (this.isZero(p2)) return p1; + + const res = new Array(3); + + const Z1Z1 = this.F.square( p1[2] ); + const Z2Z2 = this.F.square( p2[2] ); + + const U1 = this.F.mul( p1[0] , Z2Z2 ); // U1 = X1 * Z2Z2 + const U2 = this.F.mul( p2[0] , Z1Z1 ); // U2 = X2 * Z1Z1 + + const Z1_cubed = this.F.mul( p1[2] , Z1Z1); + const Z2_cubed = this.F.mul( p2[2] , Z2Z2); + + const S1 = this.F.mul( p1[1] , Z2_cubed); // S1 = Y1 * Z2 * Z2Z2 + const S2 = this.F.mul( p2[1] , Z1_cubed); // S2 = Y2 * Z1 * Z1Z1 + + if (this.F.equals(U1,U2) && this.F.equals(S1,S2)) { + return this.double(p1); + } + + const H = this.F.sub( U2 , U1 ); // H = U2-U1 + + const S2_minus_S1 = this.F.sub( S2 , S1 ); + + const I = this.F.square( this.F.add(H,H) ); // I = (2 * H)^2 + const J = this.F.mul( H , I ); // J = H * I + + const r = this.F.add( S2_minus_S1 , S2_minus_S1 ); // r = 2 * (S2-S1) + const V = this.F.mul( U1 , I ); // V = U1 * I + + res[0] = + this.F.sub( + this.F.sub( this.F.square(r) , J ), + this.F.add( V , V )); // X3 = r^2 - J - 2 * V + + const S1_J = this.F.mul( S1 , J ); + + res[1] = + this.F.sub( + this.F.mul( r , this.F.sub(V,res[0])), + this.F.add( S1_J,S1_J )); // Y3 = r * (V-X3)-2 S1 J + + res[2] = + this.F.mul( + H, + this.F.sub( + this.F.square( this.F.add(p1[2],p2[2]) ), + this.F.add( Z1Z1 , Z2Z2 ))); // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H + + return res; + } + + double(p) { + const res = new Array(3); + + if (this.isZero(p)) return p; + + const A = this.F.square( p[0] ); // A = X1^2 + const B = this.F.square( p[1] ); // B = Y1^2 + const C = this.F.square( B ); // C = B^2 + + let D = + this.F.sub( + this.F.square( this.F.add(p[0] , B )), + this.F.add( A , C)); + D = this.F.add(D,D); // D = 2 * ((X1 + B)^2 - A - C) + + const E = this.F.add( this.F.add(A,A), A); // E = 3 * A + const F = this.F.square( E ); // F = E^2 + + res[0] = this.F.sub( F , this.F.add(D,D) ); // X3 = F - 2 D + + let eightC = this.F.add( C , C ); + eightC = this.F.add( eightC , eightC ); + eightC = this.F.add( eightC , eightC ); + + res[1] = + this.F.sub( + this.F.mul( + E, + this.F.sub( D, res[0] )), + eightC); // Y3 = E * (D - X3) - 8 * C + + const Y1Z1 = this.F.mul( p[1] , p[2] ); + res[2] = this.F.add( Y1Z1 , Y1Z1 ); // Z3 = 2 * Y1 * Z1 + + 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; + } + + affine(p) { + if (this.isZero(p)) { + return this.zero; + } else { + const Z_inv = this.F.inverse(p[2]); + const Z2_inv = this.F.square(Z_inv); + const Z3_inv = this.F.mul(Z2_inv, Z_inv); + + const res = new Array(3); + res[0] = this.F.affine( this.F.mul(p[0],Z2_inv)); + res[1] = this.F.affine( this.F.mul(p[1],Z3_inv)); + res[2] = this.F.one; + + return res; + } + } + + equals(p1, p2) { + if (this.isZero(p1)) return this.isZero(p2); + if (this.isZero(p2)) return this.isZero(p1); + + const Z1Z1 = this.F.square( p1[2] ); + const Z2Z2 = this.F.square( p2[2] ); + + const U1 = this.F.mul( p1[0] , Z2Z2 ); + const U2 = this.F.mul( p2[0] , Z1Z1 ); + + const Z1_cubed = this.F.mul( p1[2] , Z1Z1); + const Z2_cubed = this.F.mul( p2[2] , Z2Z2); + + const S1 = this.F.mul( p1[1] , Z2_cubed); + const S2 = this.F.mul( p2[1] , Z1_cubed); + + return (this.F.equals(U1,U2) && this.F.equals(S1,S2)); + } + + toString(p) { + const cp = this.affine(p); + return `[ ${this.F.toString(cp[0])} , ${this.F.toString(cp[1])} ]`; + } + +} + +module.exports = GCurve; +
M
src/pairing.js
→
src/pairing.js
@@ -2,11 +2,252 @@ /*
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 F12Field = require("f12field"); +const G1Curve = require("g1curve"); +const G2Curve = require("g2curve"); +const constants = require("constants"); + +module.exports = new Pairing(); + + +class Pairing { + + constructor() { + this.loopCount = bigInt(11);// 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) { + 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)); + } + + 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) { -module.exports = function pairing(p1, p2) { + 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.F12.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.F12.mul_by_024( + f, + c.ell_0, + this.F2.mul(pre1.PY, c.ell_VW), + this.F2.mul(pre1.PX, c.ell_VV)); + } + } - // TODO - throw new Error("Not Implementted"); -}; + if (this.loopCountNef) + { + f = this.F12.inverse(f); + } + + c = pre2.coeffs[idx++]; + f = this.F12.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, + 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; + } +}
M
src/znfield.js
→
src/f2field.js
@@ -1,8 +1,8 @@
-class ZnField { - constructor(n) { - this.n = n; +class F2Field { + constructor(p) { + this.p = n; } add(a, b) {@@ -51,4 +51,4 @@ }
} -module.exports = ZnField; +module.exports = F2Field;
A
test/algebra.js
@@ -0,0 +1,35 @@
+const F1Field = require("../src/f1field.js"); +const GCurve = require("../src/gcurve.js"); +const constants = require("../src/constants.js"); +const chai = require('chai'); + +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); + + const res = G1.mulEscalar(G1.g, constants.r); + + assert(G1.equals(res, G1.zero), "G1 does not have range r"); + }); + + it("Should add match in various", () => { + const F1 = new F1Field(constants.q); + const G1 = new GCurve(F1, constants.g1); + + const r1 = F1.e(33); + const r2 = F1.e(44); + + const gr1 = G1.mulEscalar(G1.g, r1); + const gr2 = G1.mulEscalar(G1.g, r2); + + const grsum1 = G1.add(gr1, gr2); + + const grsum2 = G1.mulEscalar(G1.g, r1.add(r2)); + + assert(G1.equals(grsum1, grsum2)); + }); +});