refactor curve and add tests
This commit is contained in:
parent
91fbc8ea2d
commit
89173c3e63
46
package-lock.json
generated
46
package-lock.json
generated
@ -74,6 +74,11 @@
|
||||
"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 @@
|
||||
"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",
|
||||
@ -171,6 +189,11 @@
|
||||
"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",
|
||||
"resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
|
||||
@ -227,6 +250,14 @@
|
||||
"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 @@
|
||||
"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 @@
|
||||
"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",
|
||||
@ -1033,6 +1074,11 @@
|
||||
"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",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
|
||||
|
@ -19,6 +19,7 @@
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"big-integer": "^1.6.34",
|
||||
"chai": "^4.1.2",
|
||||
"eslint": "^5.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
39
src/constants.js
Normal file
39
src/constants.js
Normal file
@ -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
src/f12field.js
Normal file
55
src/f12field.js
Normal file
@ -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
src/f1field.js
Normal file
78
src/f1field.js
Normal file
@ -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;
|
@ -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 @@ class ZnField {
|
||||
|
||||
}
|
||||
|
||||
module.exports = ZnField;
|
||||
module.exports = F2Field;
|
0
src/f6field.js
Normal file
0
src/f6field.js
Normal file
147
src/g1curve.js
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());
|
||||
|
||||
|
@ -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
src/gcurve.js
Normal file
167
src/gcurve.js
Normal file
@ -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;
|
||||
|
249
src/pairing.js
249
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 = 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
test/algebra.js
Normal file
35
test/algebra.js
Normal file
@ -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…
Reference in New Issue
Block a user