@ -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; |
@ -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; |
@ -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,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"); |
|
||||
} |
|
||||
|
|
||||
}; |
|
@ -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; |
||||
|
|
@ -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)); |
||||
|
}); |
||||
|
}); |