Browse Source

refactor curve and add tests

master
Jordi Baylina 5 years ago
parent
commit
89173c3e63
No known key found for this signature in database GPG Key ID: 7480C80C1BE43112
12 changed files with 670 additions and 183 deletions
  1. +46
    -0
      package-lock.json
  2. +1
    -0
      package.json
  3. +39
    -0
      src/constants.js
  4. +55
    -0
      src/f12field.js
  5. +78
    -0
      src/f1field.js
  6. +4
    -4
      src/f2field.js
  7. +0
    -0
      src/f6field.js
  8. +0
    -147
      src/g1curve.js
  9. +0
    -28
      src/g2curve.js
  10. +167
    -0
      src/gcurve.js
  11. +245
    -4
      src/pairing.js
  12. +35
    -0
      test/algebra.js

+ 46
- 0
package-lock.json

@ -74,6 +74,11 @@
"resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
"integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" "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": { "babel-code-frame": {
"version": "6.26.0", "version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
@ -138,6 +143,19 @@
"resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz",
"integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=" "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": { "chalk": {
"version": "2.4.1", "version": "2.4.1",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
@ -171,6 +189,11 @@
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=" "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": { "circular-json": {
"version": "0.3.3", "version": "0.3.3",
"resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
@ -227,6 +250,14 @@
"ms": "2.0.0" "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": { "deep-is": {
"version": "0.1.3", "version": "0.1.3",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
@ -477,6 +508,11 @@
"resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" "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": { "glob": {
"version": "7.1.2", "version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
@ -798,6 +834,11 @@
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
}, },
"pathval": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
"integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA="
},
"pify": { "pify": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
@ -1033,6 +1074,11 @@
"prelude-ls": "~1.1.2" "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": { "uri-js": {
"version": "4.2.2", "version": "4.2.2",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",

+ 1
- 0
package.json

@ -19,6 +19,7 @@
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"big-integer": "^1.6.34", "big-integer": "^1.6.34",
"chai": "^4.1.2",
"eslint": "^5.3.0" "eslint": "^5.3.0"
}, },
"devDependencies": { "devDependencies": {

+ 39
- 0
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;

+ 55
- 0
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;

+ 78
- 0
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;

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) { add(a, b) {
@ -51,4 +51,4 @@ class ZnField {
} }
module.exports = ZnField;
module.exports = F2Field;

+ 0
- 0
src/f6field.js


+ 0
- 147
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());

+ 0
- 28
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");
}
};

+ 167
- 0
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;

+ 245
- 4
src/pairing.js

@ -2,11 +2,252 @@
This module calculate the pairing of p1 and p2 where p1 in G1 and p2 in G2 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 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 = function pairing(p1, p2) {
module.exports = new Pairing();
// TODO
throw new Error("Not Implementted");
};
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) {
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));
}
}
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;
}
}

+ 35
- 0
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));
});
});

Loading…
Cancel
Save