Socket
Socket
Sign inDemoInstall

@noble/bls12-381

Package Overview
Dependencies
0
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.2.0 to 1.3.0

118

lib/esm/index.js

@@ -1,2 +0,2 @@

/*! noble-bls12-381 - MIT License (c) Paul Miller (paulmillr.com) */
/*! noble-bls12-381 - MIT License (c) 2019 Paul Miller (paulmillr.com) */
import nodeCrypto from 'crypto';

@@ -26,2 +26,11 @@ import { Fp, Fr, Fp2, Fp12, CURVE, ProjectivePoint, map_to_curve_simple_swu_9mod16, isogenyMapG2, millerLoop, psi, psi2, calcPairingPrecomputes, mod } from './math.js';

hashToField: hash_to_field,
hashToPrivateKey: (hash) => {
hash = ensureBytes(hash);
if (hash.length < 40 || hash.length > 1024)
throw new Error('Expected 40-1024 bytes of private key as per FIPS 186');
const num = mod(bytesToNumberBE(hash), CURVE.r);
if (num === 0n || num === 1n)
throw new Error('Invalid private key');
return numberTo32BytesBE(num);
},
bytesToHex,

@@ -41,10 +50,3 @@ randomBytes: (bytesLength = 32) => {

randomPrivateKey: () => {
let i = 8;
while (i--) {
const b32 = utils.randomBytes(32);
const num = bytesToNumberBE(b32);
if (isWithinCurveOrder(num) && num !== 1n)
return b32;
}
throw new Error('Valid private key was not found in 8 iterations. PRNG is broken');
return utils.hashToPrivateKey(utils.randomBytes(40));
},

@@ -74,8 +76,6 @@ sha256: async (message) => {

};
function bytesToNumberBE(bytes) {
let value = 0n;
for (let i = bytes.length - 1, j = 0; i >= 0; i--, j++) {
value += (BigInt(bytes[i]) & 255n) << (8n * BigInt(j));
}
return value;
function bytesToNumberBE(uint8a) {
if (!(uint8a instanceof Uint8Array))
throw new Error('Expected Uint8Array');
return BigInt('0x' + bytesToHex(Uint8Array.from(uint8a)));
}

@@ -103,3 +103,3 @@ const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));

const byte = Number.parseInt(hexByte, 16);
if (Number.isNaN(byte))
if (Number.isNaN(byte) || byte < 0)
throw new Error('Invalid byte sequence');

@@ -110,5 +110,10 @@ array[i] = byte;

}
function numberTo32BytesBE(num) {
const length = 32;
const hex = num.toString(16).padStart(length * 2, '0');
return hexToBytes(hex);
}
function toPaddedHex(num, padding) {
if (num < 0n)
throw new Error('Expected valid number');
if (typeof num !== 'bigint' || num < 0n)
throw new Error('Expected valid bigint');
if (typeof padding !== 'number')

@@ -119,7 +124,3 @@ throw new TypeError('Expected valid padding');

function ensureBytes(hex) {
if (hex instanceof Uint8Array)
return hex;
if (typeof hex === 'string')
return hexToBytes(hex);
throw new TypeError('Expected hex string or Uint8Array');
return hex instanceof Uint8Array ? Uint8Array.from(hex) : hexToBytes(hex);
}

@@ -243,5 +244,5 @@ function concatBytes(...arrays) {

bytes = ensureBytes(bytes);
const { P } = CURVE;
let point;
if (bytes.length === 48) {
const { P } = CURVE;
const compressedValue = bytesToNumberBE(bytes);

@@ -283,4 +284,4 @@ const bflag = mod(compressedValue, POW_2_383) / POW_2_382;

this.assertValidity();
const { P } = CURVE;
if (isCompressed) {
const { P } = CURVE;
let hex;

@@ -383,10 +384,10 @@ if (this.isZero()) {

return this.ZERO;
const x1 = z1 % POW_2_381;
const x2 = z2;
const x = new Fp2([x2, x1]);
const y2 = x.pow(3n).add(new Fp2(CURVE.b2));
const x1 = new Fp(z1 % POW_2_381);
const x2 = new Fp(z2);
const x = new Fp2(x2, x1);
const y2 = x.pow(3n).add(Fp2.fromBigTuple(CURVE.b2));
let y = y2.sqrt();
if (!y)
throw new Error('Failed to find a square root');
const [y0, y1] = y.values;
const { re: y0, im: y1 } = y.reim();
const aflag1 = (z1 % POW_2_382) / POW_2_381;

@@ -403,7 +404,32 @@ const isGreater = y1 > 0n && (y1 * 2n) / P !== aflag1;

bytes = ensureBytes(bytes);
const m_byte = bytes[0] & 0xe0;
if (m_byte === 0x20 || m_byte === 0x60 || m_byte === 0xe0) {
throw new Error('Invalid encoding flag: ' + m_byte);
}
const bitC = m_byte & 0x80;
const bitI = m_byte & 0x40;
const bitS = m_byte & 0x20;
let point;
if (bytes.length === 96) {
throw new Error('Compressed format not supported yet.');
if (bytes.length === 96 && bitC) {
const { P, b2 } = CURVE;
const b = Fp2.fromBigTuple(b2);
bytes[0] = bytes[0] & 0x1f;
if (bitI) {
if (bytes.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
throw new Error('Invalid compressed G2 point');
}
return PointG2.ZERO;
}
const x_1 = bytesToNumberBE(bytes.slice(0, PUBLIC_KEY_LENGTH));
const x_0 = bytesToNumberBE(bytes.slice(PUBLIC_KEY_LENGTH));
const x = new Fp2(new Fp(x_0), new Fp(x_1));
const right = x.pow(3n).add(b);
let y = right.sqrt();
if (!y)
throw new Error('Invalid compressed G2 point');
const Y_bit = y.c1.value === 0n ? (y.c0.value * 2n) / P : (y.c1.value * 2n) / P ? 1n : 0n;
y = bitS > 0 && Y_bit > 0 ? y : y.negate();
return new PointG2(x, y);
}
else if (bytes.length === 192) {
else if (bytes.length === 192 && !bitC) {
if ((bytes[0] & (1 << 6)) !== 0) {

@@ -416,6 +442,6 @@ return PointG2.ZERO;

const y0 = bytesToNumberBE(bytes.slice(3 * PUBLIC_KEY_LENGTH));
point = new PointG2(new Fp2([x0, x1]), new Fp2([y0, y1]));
point = new PointG2(Fp2.fromBigTuple([x0, x1]), Fp2.fromBigTuple([y0, y1]));
}
else {
throw new Error('Invalid uncompressed point G2, expected 192 bytes');
throw new Error('Invalid point G2, expected 96/192 bytes');
}

@@ -434,3 +460,3 @@ point.assertValidity();

}
const [[x0, x1], [y0, y1]] = this.toAffine().map((a) => a.values);
const [{ re: x0, im: x1 }, { re: y0, im: y1 }] = this.toAffine().map((a) => a.reim());
const tmp = y1 > 0n ? y1 * 2n : y0 * 2n;

@@ -448,3 +474,15 @@ const aflag1 = tmp / CURVE.P;

if (isCompressed) {
throw new Error('Point compression has not yet been implemented');
const { P } = CURVE;
let x_1 = 0n;
let x_0 = 0n;
if (this.isZero()) {
x_1 = POW_2_383 + POW_2_382;
}
else {
const [x, y] = this.toAffine();
const flag = y.c1.value === 0n ? (y.c0.value * 2n) / P : (y.c1.value * 2n) / P ? 1n : 0n;
x_1 = x.c1.value + flag * POW_2_381 + POW_2_383;
x_0 = x.c0.value;
}
return toPaddedHex(x_1, PUBLIC_KEY_LENGTH) + toPaddedHex(x_0, PUBLIC_KEY_LENGTH);
}

@@ -455,3 +493,3 @@ else {

}
const [[x0, x1], [y0, y1]] = this.toAffine().map((a) => a.values);
const [{ re: x0, im: x1 }, { re: y0, im: y1 }] = this.toAffine().map((a) => a.reim());
return (toPaddedHex(x1, PUBLIC_KEY_LENGTH) +

@@ -496,3 +534,3 @@ toPaddedHex(x0, PUBLIC_KEY_LENGTH) +

isOnCurve() {
const b = new Fp2(CURVE.b2);
const b = Fp2.fromBigTuple(CURVE.b2);
const { x, y, z } = this;

@@ -520,3 +558,3 @@ const left = y.pow(2n).multiply(z).subtract(x.pow(3n));

}
PointG2.BASE = new PointG2(new Fp2(CURVE.G2x), new Fp2(CURVE.G2y), Fp2.ONE);
PointG2.BASE = new PointG2(Fp2.fromBigTuple(CURVE.G2x), Fp2.fromBigTuple(CURVE.G2y), Fp2.ONE);
PointG2.ZERO = new PointG2(Fp2.ONE, Fp2.ONE, Fp2.ZERO);

@@ -523,0 +561,0 @@ export function pairing(P, Q, withFinalExponent = true) {

@@ -29,8 +29,12 @@ export const CURVE = {

}
export function powMod(a, power, modulo) {
export function powMod(num, power, modulo) {
if (modulo <= 0n || power < 0n)
throw new Error('Expected power/modulo > 0');
if (modulo === 1n)
return 0n;
let res = 1n;
while (power > 0n) {
if (power & 1n)
res = (res * a) % modulo;
a = (a * a) % modulo;
res = (res * num) % modulo;
num = (num * num) % modulo;
power >>= 1n;

@@ -41,20 +45,17 @@ }

function genInvertBatch(cls, nums) {
const len = nums.length;
const scratch = new Array(len);
let acc = cls.ONE;
for (let i = 0; i < len; i++) {
if (nums[i].isZero())
continue;
scratch[i] = acc;
acc = acc.multiply(nums[i]);
}
acc = acc.invert();
for (let i = len - 1; i >= 0; i--) {
if (nums[i].isZero())
continue;
let tmp = acc.multiply(nums[i]);
nums[i] = acc.multiply(scratch[i]);
acc = tmp;
}
return nums;
const tmp = new Array(nums.length);
const lastMultiplied = nums.reduce((acc, num, i) => {
if (num.isZero())
return acc;
tmp[i] = acc;
return acc.multiply(num);
}, cls.ONE);
const inverted = lastMultiplied.invert();
nums.reduceRight((acc, num, i) => {
if (num.isZero())
return acc;
tmp[i] = acc.multiply(tmp[i]);
return acc.multiply(num);
}, inverted);
return tmp;
}

@@ -71,3 +72,5 @@ function bitLen(n) {

function invert(number, modulo = CURVE.P) {
if (number === 0n || modulo <= 0n) {
const _0n = 0n;
const _1n = 1n;
if (number === _0n || modulo <= _0n) {
throw new Error(`invert: expected positive integers, got n=${number} mod=${modulo}`);

@@ -77,4 +80,4 @@ }

let b = modulo;
let [x, y, u, v] = [0n, 1n, 1n, 0n];
while (a !== 0n) {
let x = _0n, y = _1n, u = _1n, v = _0n;
while (a !== _0n) {
const q = b / a;

@@ -84,8 +87,6 @@ const r = b % a;

const n = y - v * q;
[b, a] = [a, r];
[x, y] = [u, v];
[u, v] = [m, n];
b = a, a = r, x = u, y = v, u = m, v = n;
}
const gcd = b;
if (gcd !== 1n)
if (gcd !== _1n)
throw new Error('invert: does not exist');

@@ -229,60 +230,74 @@ return mod(x, modulo);

Fr.ONE = new Fr(1n);
class FQP {
zip(rhs, mapper) {
const c0 = this.c;
const c1 = rhs.c;
const res = [];
for (let i = 0; i < c0.length; i++) {
res.push(mapper(c0[i], c1[i]));
}
return res;
function powMod_FQP(fqp, fqpOne, n) {
const elm = fqp;
if (n === 0n)
return fqpOne;
if (n === 1n)
return elm;
let p = fqpOne;
let d = elm;
while (n > 0n) {
if (n & 1n)
p = p.multiply(d);
n >>= 1n;
d = d.square();
}
map(callbackfn) {
return this.c.map(callbackfn);
return p;
}
export class Fp2 {
constructor(c0, c1) {
this.c0 = c0;
this.c1 = c1;
if (typeof c0 === 'bigint')
throw new Error('c0: Expected Fp');
if (typeof c1 === 'bigint')
throw new Error('c1: Expected Fp');
}
static fromBigTuple(tuple) {
const fps = tuple.map(n => new Fp(n));
return new Fp2(...fps);
}
one() {
return Fp2.ONE;
}
isZero() {
return this.c.every((c) => c.isZero());
return this.c0.isZero() && this.c1.isZero();
}
equals(rhs) {
return this.zip(rhs, (left, right) => left.equals(right)).every((r) => r);
toString() {
return `Fp2(${this.c0} + ${this.c1}×i)`;
}
reim() {
return { re: this.c0.value, im: this.c1.value };
}
negate() {
return this.init(this.map((c) => c.negate()));
const { c0, c1 } = this;
return new Fp2(c0.negate(), c1.negate());
}
equals(rhs) {
const { c0, c1 } = this;
const { c0: r0, c1: r1 } = rhs;
return c0.equals(r0) && c1.equals(r1);
}
add(rhs) {
return this.init(this.zip(rhs, (left, right) => left.add(right)));
const { c0, c1 } = this;
const { c0: r0, c1: r1 } = rhs;
return new Fp2(c0.add(r0), c1.add(r1));
}
subtract(rhs) {
return this.init(this.zip(rhs, (left, right) => left.subtract(right)));
const { c0, c1 } = this;
const { c0: r0, c1: r1 } = rhs;
return new Fp2(c0.subtract(r0), c1.subtract(r1));
}
conjugate() {
return this.init([this.c[0], this.c[1].negate()]);
multiply(rhs) {
const { c0, c1 } = this;
if (typeof rhs === 'bigint') {
return new Fp2(c0.multiply(rhs), c1.multiply(rhs));
}
const { c0: r0, c1: r1 } = rhs;
let t1 = c0.multiply(r0);
let t2 = c1.multiply(r1);
return new Fp2(t1.subtract(t2), c0.add(c1).multiply(r0.add(r1)).subtract(t1.add(t2)));
}
one() {
const el = this;
let one;
if (el instanceof Fp2)
one = Fp2.ONE;
if (el instanceof Fp6)
one = Fp6.ONE;
if (el instanceof Fp12)
one = Fp12.ONE;
return one;
}
pow(n) {
const elm = this;
const one = this.one();
if (n === 0n)
return one;
if (n === 1n)
return elm;
let p = one;
let d = elm;
while (n > 0n) {
if (n & 1n)
p = p.multiply(d);
n >>= 1n;
d = d.square();
}
return p;
return powMod_FQP(this, Fp2.ONE, n);
}

@@ -293,44 +308,14 @@ div(rhs) {

}
}
export class Fp2 extends FQP {
constructor(coeffs) {
super();
if (coeffs.length !== 2)
throw new Error(`Expected array with 2 elements`);
coeffs.forEach((c, i) => {
if (typeof c === 'bigint')
coeffs[i] = new Fp(c);
});
this.c = coeffs;
}
init(tuple) {
return new Fp2(tuple);
}
toString() {
return `Fp2(${this.c[0]} + ${this.c[1]}×i)`;
}
get values() {
return this.c.map((c) => c.value);
}
multiply(rhs) {
if (typeof rhs === 'bigint')
return new Fp2(this.map((c) => c.multiply(rhs)));
const [c0, c1] = this.c;
const [r0, r1] = rhs.c;
let t1 = c0.multiply(r0);
let t2 = c1.multiply(r1);
return new Fp2([t1.subtract(t2), c0.add(c1).multiply(r0.add(r1)).subtract(t1.add(t2))]);
}
mulByNonresidue() {
const c0 = this.c[0];
const c1 = this.c[1];
return new Fp2([c0.subtract(c1), c0.add(c1)]);
const c0 = this.c0;
const c1 = this.c1;
return new Fp2(c0.subtract(c1), c0.add(c1));
}
square() {
const c0 = this.c[0];
const c1 = this.c[1];
const c0 = this.c0;
const c1 = this.c1;
const a = c0.add(c1);
const b = c0.subtract(c1);
const c = c0.add(c0);
return new Fp2([a.multiply(b), c.multiply(c1)]);
return new Fp2(a.multiply(b), c.multiply(c1));
}

@@ -350,4 +335,4 @@ sqrt() {

const x2 = x1.negate();
const [re1, im1] = x1.values;
const [re2, im2] = x2.values;
const { re: re1, im: im1 } = x1.reim();
const { re: re2, im: im2 } = x2.reim();
if (im1 > im2 || (im1 === im2 && re1 > re2))

@@ -358,14 +343,15 @@ return x1;

invert() {
const [a, b] = this.values;
const { re: a, im: b } = this.reim();
const factor = new Fp(a * a + b * b).invert();
return new Fp2([factor.multiply(new Fp(a)), factor.multiply(new Fp(-b))]);
return new Fp2(factor.multiply(new Fp(a)), factor.multiply(new Fp(-b)));
}
frobeniusMap(power) {
return new Fp2([this.c[0], this.c[1].multiply(FP2_FROBENIUS_COEFFICIENTS[power % 2])]);
return new Fp2(this.c0, this.c1.multiply(FP2_FROBENIUS_COEFFICIENTS[power % 2]));
}
multiplyByB() {
let [c0, c1] = this.c;
let c0 = this.c0;
let c1 = this.c1;
let t0 = c0.multiply(4n);
let t1 = c1.multiply(4n);
return new Fp2([t0.subtract(t1), t0.add(t1)]);
return new Fp2(t0.subtract(t1), t0.add(t1));
}

@@ -375,64 +361,83 @@ }

Fp2.MAX_BITS = bitLen(CURVE.P2);
Fp2.ZERO = new Fp2([0n, 0n]);
Fp2.ONE = new Fp2([1n, 0n]);
export class Fp6 extends FQP {
constructor(c) {
super();
this.c = c;
if (c.length !== 3)
throw new Error(`Expected array with 3 elements`);
Fp2.ZERO = new Fp2(Fp.ZERO, Fp.ZERO);
Fp2.ONE = new Fp2(Fp.ONE, Fp.ZERO);
export class Fp6 {
constructor(c0, c1, c2) {
this.c0 = c0;
this.c1 = c1;
this.c2 = c2;
}
static fromTuple(t) {
static fromBigSix(t) {
if (!Array.isArray(t) || t.length !== 6)
throw new Error('Invalid Fp6 usage');
return new Fp6([new Fp2(t.slice(0, 2)), new Fp2(t.slice(2, 4)), new Fp2(t.slice(4, 6))]);
const c = [t.slice(0, 2), t.slice(2, 4), t.slice(4, 6)].map(t => Fp2.fromBigTuple(t));
return new Fp6(...c);
}
init(triple) {
return new Fp6(triple);
fromTriple(triple) {
return new Fp6(...triple);
}
one() {
return Fp6.ONE;
}
isZero() {
return this.c0.isZero() && this.c1.isZero() && this.c2.isZero();
}
negate() {
const { c0, c1, c2 } = this;
return new Fp6(c0.negate(), c1.negate(), c2.negate());
}
toString() {
return `Fp6(${this.c[0]} + ${this.c[1]} * v, ${this.c[2]} * v^2)`;
return `Fp6(${this.c0} + ${this.c1} * v, ${this.c2} * v^2)`;
}
conjugate() {
throw new TypeError('No conjugate on Fp6');
equals(rhs) {
const { c0, c1, c2 } = this;
const { c0: r0, c1: r1, c2: r2 } = rhs;
return c0.equals(r0) && c1.equals(r1) && c2.equals(r2);
}
add(rhs) {
const { c0, c1, c2 } = this;
const { c0: r0, c1: r1, c2: r2 } = rhs;
return new Fp6(c0.add(r0), c1.add(r1), c2.add(r2));
}
subtract(rhs) {
const { c0, c1, c2 } = this;
const { c0: r0, c1: r1, c2: r2 } = rhs;
return new Fp6(c0.subtract(r0), c1.subtract(r1), c2.subtract(r2));
}
multiply(rhs) {
if (typeof rhs === 'bigint')
return new Fp6([this.c[0].multiply(rhs), this.c[1].multiply(rhs), this.c[2].multiply(rhs)]);
let [c0, c1, c2] = this.c;
const [r0, r1, r2] = rhs.c;
if (typeof rhs === 'bigint') {
return new Fp6(this.c0.multiply(rhs), this.c1.multiply(rhs), this.c2.multiply(rhs));
}
let { c0, c1, c2 } = this;
let { c0: r0, c1: r1, c2: r2 } = rhs;
let t0 = c0.multiply(r0);
let t1 = c1.multiply(r1);
let t2 = c2.multiply(r2);
return new Fp6([
t0.add(c1.add(c2).multiply(r1.add(r2)).subtract(t1.add(t2)).mulByNonresidue()),
c0.add(c1).multiply(r0.add(r1)).subtract(t0.add(t1)).add(t2.mulByNonresidue()),
t1.add(c0.add(c2).multiply(r0.add(r2)).subtract(t0.add(t2))),
]);
return new Fp6(t0.add(c1.add(c2).multiply(r1.add(r2)).subtract(t1.add(t2)).mulByNonresidue()), c0.add(c1).multiply(r0.add(r1)).subtract(t0.add(t1)).add(t2.mulByNonresidue()), t1.add(c0.add(c2).multiply(r0.add(r2)).subtract(t0.add(t2))));
}
pow(n) {
return powMod_FQP(this, Fp6.ONE, n);
}
div(rhs) {
const inv = typeof rhs === 'bigint' ? new Fp(rhs).invert().value : rhs.invert();
return this.multiply(inv);
}
mulByNonresidue() {
return new Fp6([this.c[2].mulByNonresidue(), this.c[0], this.c[1]]);
return new Fp6(this.c2.mulByNonresidue(), this.c0, this.c1);
}
multiplyBy1(b1) {
return new Fp6([
this.c[2].multiply(b1).mulByNonresidue(),
this.c[0].multiply(b1),
this.c[1].multiply(b1),
]);
return new Fp6(this.c2.multiply(b1).mulByNonresidue(), this.c0.multiply(b1), this.c1.multiply(b1));
}
multiplyBy01(b0, b1) {
let [c0, c1, c2] = this.c;
let { c0, c1, c2 } = this;
let t0 = c0.multiply(b0);
let t1 = c1.multiply(b1);
return new Fp6([
c1.add(c2).multiply(b1).subtract(t1).mulByNonresidue().add(t0),
b0.add(b1).multiply(c0.add(c1)).subtract(t0).subtract(t1),
c0.add(c2).multiply(b0).subtract(t0).add(t1),
]);
return new Fp6(c1.add(c2).multiply(b1).subtract(t1).mulByNonresidue().add(t0), b0.add(b1).multiply(c0.add(c1)).subtract(t0).subtract(t1), c0.add(c2).multiply(b0).subtract(t0).add(t1));
}
multiplyByFp2(rhs) {
return new Fp6(this.map((c) => c.multiply(rhs)));
let { c0, c1, c2 } = this;
return new Fp6(c0.multiply(rhs), c1.multiply(rhs), c2.multiply(rhs));
}
square() {
let [c0, c1, c2] = this.c;
let { c0, c1, c2 } = this;
let t0 = c0.square();

@@ -442,10 +447,6 @@ let t1 = c0.multiply(c1).multiply(2n);

let t4 = c2.square();
return new Fp6([
t3.mulByNonresidue().add(t0),
t4.mulByNonresidue().add(t1),
t1.add(c0.subtract(c1).add(c2).square()).add(t3).subtract(t0).subtract(t4),
]);
return new Fp6(t3.mulByNonresidue().add(t0), t4.mulByNonresidue().add(t1), t1.add(c0.subtract(c1).add(c2).square()).add(t3).subtract(t0).subtract(t4));
}
invert() {
let [c0, c1, c2] = this.c;
let { c0, c1, c2 } = this;
let t0 = c0.square().subtract(c2.multiply(c1).mulByNonresidue());

@@ -455,106 +456,109 @@ let t1 = c2.square().mulByNonresidue().subtract(c0.multiply(c1));

let t4 = c2.multiply(t1).add(c1.multiply(t2)).mulByNonresidue().add(c0.multiply(t0)).invert();
return new Fp6([t4.multiply(t0), t4.multiply(t1), t4.multiply(t2)]);
return new Fp6(t4.multiply(t0), t4.multiply(t1), t4.multiply(t2));
}
frobeniusMap(power) {
return new Fp6([
this.c[0].frobeniusMap(power),
this.c[1].frobeniusMap(power).multiply(FP6_FROBENIUS_COEFFICIENTS_1[power % 6]),
this.c[2].frobeniusMap(power).multiply(FP6_FROBENIUS_COEFFICIENTS_2[power % 6]),
]);
return new Fp6(this.c0.frobeniusMap(power), this.c1.frobeniusMap(power).multiply(FP6_FROBENIUS_COEFFICIENTS_1[power % 6]), this.c2.frobeniusMap(power).multiply(FP6_FROBENIUS_COEFFICIENTS_2[power % 6]));
}
}
Fp6.ZERO = new Fp6([Fp2.ZERO, Fp2.ZERO, Fp2.ZERO]);
Fp6.ONE = new Fp6([Fp2.ONE, Fp2.ZERO, Fp2.ZERO]);
export class Fp12 extends FQP {
constructor(c) {
super();
this.c = c;
if (c.length !== 2)
throw new Error(`Expected array with 2 elements`);
Fp6.ZERO = new Fp6(Fp2.ZERO, Fp2.ZERO, Fp2.ZERO);
Fp6.ONE = new Fp6(Fp2.ONE, Fp2.ZERO, Fp2.ZERO);
export class Fp12 {
constructor(c0, c1) {
this.c0 = c0;
this.c1 = c1;
}
static fromTuple(t) {
return new Fp12([
Fp6.fromTuple(t.slice(0, 6)),
Fp6.fromTuple(t.slice(6, 12)),
]);
static fromBigTwelve(t) {
return new Fp12(Fp6.fromBigSix(t.slice(0, 6)), Fp6.fromBigSix(t.slice(6, 12)));
}
init(c) {
return new Fp12(c);
fromTuple(c) {
return new Fp12(...c);
}
one() {
return Fp12.ONE;
}
isZero() {
return this.c0.isZero() && this.c1.isZero();
}
toString() {
return `Fp12(${this.c[0]} + ${this.c[1]} * w)`;
return `Fp12(${this.c0} + ${this.c1} * w)`;
}
negate() {
const { c0, c1 } = this;
return new Fp12(c0.negate(), c1.negate());
}
equals(rhs) {
const { c0, c1 } = this;
const { c0: r0, c1: r1 } = rhs;
return c0.equals(r0) && c1.equals(r1);
}
add(rhs) {
const { c0, c1 } = this;
const { c0: r0, c1: r1 } = rhs;
return new Fp12(c0.add(r0), c1.add(r1));
}
subtract(rhs) {
const { c0, c1 } = this;
const { c0: r0, c1: r1 } = rhs;
return new Fp12(c0.subtract(r0), c1.subtract(r1));
}
multiply(rhs) {
if (typeof rhs === 'bigint')
return new Fp12([this.c[0].multiply(rhs), this.c[1].multiply(rhs)]);
let [c0, c1] = this.c;
const [r0, r1] = rhs.c;
return new Fp12(this.c0.multiply(rhs), this.c1.multiply(rhs));
let { c0, c1 } = this;
let { c0: r0, c1: r1 } = rhs;
let t1 = c0.multiply(r0);
let t2 = c1.multiply(r1);
return new Fp12([
t1.add(t2.mulByNonresidue()),
c0.add(c1).multiply(r0.add(r1)).subtract(t1.add(t2)),
]);
return new Fp12(t1.add(t2.mulByNonresidue()), c0.add(c1).multiply(r0.add(r1)).subtract(t1.add(t2)));
}
pow(n) {
return powMod_FQP(this, Fp12.ONE, n);
}
div(rhs) {
const inv = typeof rhs === 'bigint' ? new Fp(rhs).invert().value : rhs.invert();
return this.multiply(inv);
}
multiplyBy014(o0, o1, o4) {
let [c0, c1] = this.c;
let [t0, t1] = [c0.multiplyBy01(o0, o1), c1.multiplyBy1(o4)];
return new Fp12([
t1.mulByNonresidue().add(t0),
c1.add(c0).multiplyBy01(o0, o1.add(o4)).subtract(t0).subtract(t1),
]);
let { c0, c1 } = this;
let t0 = c0.multiplyBy01(o0, o1);
let t1 = c1.multiplyBy1(o4);
return new Fp12(t1.mulByNonresidue().add(t0), c1.add(c0).multiplyBy01(o0, o1.add(o4)).subtract(t0).subtract(t1));
}
multiplyByFp2(rhs) {
return this.init(this.map((c) => c.multiplyByFp2(rhs)));
return new Fp12(this.c0.multiplyByFp2(rhs), this.c1.multiplyByFp2(rhs));
}
square() {
let [c0, c1] = this.c;
let { c0, c1 } = this;
let ab = c0.multiply(c1);
return new Fp12([
c1.mulByNonresidue().add(c0).multiply(c0.add(c1)).subtract(ab).subtract(ab.mulByNonresidue()),
ab.add(ab),
]);
return new Fp12(c1.mulByNonresidue().add(c0).multiply(c0.add(c1)).subtract(ab).subtract(ab.mulByNonresidue()), ab.add(ab));
}
invert() {
let [c0, c1] = this.c;
let { c0, c1 } = this;
let t = c0.square().subtract(c1.square().mulByNonresidue()).invert();
return new Fp12([c0.multiply(t), c1.multiply(t).negate()]);
return new Fp12(c0.multiply(t), c1.multiply(t).negate());
}
conjugate() {
return new Fp12(this.c0, this.c1.negate());
}
frobeniusMap(power) {
const [c0, c1] = this.c;
let r0 = c0.frobeniusMap(power);
let [c1_0, c1_1, c1_2] = c1.frobeniusMap(power).c;
const r0 = this.c0.frobeniusMap(power);
const { c0, c1, c2 } = this.c1.frobeniusMap(power);
const coeff = FP12_FROBENIUS_COEFFICIENTS[power % 12];
return new Fp12([
r0,
new Fp6([c1_0.multiply(coeff), c1_1.multiply(coeff), c1_2.multiply(coeff)]),
]);
return new Fp12(r0, new Fp6(c0.multiply(coeff), c1.multiply(coeff), c2.multiply(coeff)));
}
Fp4Square(a, b) {
const a2 = a.square(), b2 = b.square();
return [
b2.mulByNonresidue().add(a2),
a.add(b).square().subtract(a2).subtract(b2),
];
const a2 = a.square();
const b2 = b.square();
return {
first: b2.mulByNonresidue().add(a2),
second: a.add(b).square().subtract(a2).subtract(b2),
};
}
cyclotomicSquare() {
const [c0, c1] = this.c;
const [c0c0, c0c1, c0c2] = c0.c;
const [c1c0, c1c1, c1c2] = c1.c;
let [t3, t4] = this.Fp4Square(c0c0, c1c1);
let [t5, t6] = this.Fp4Square(c1c0, c0c2);
let [t7, t8] = this.Fp4Square(c0c1, c1c2);
const { c0: c0c0, c1: c0c1, c2: c0c2 } = this.c0;
const { c0: c1c0, c1: c1c1, c2: c1c2 } = this.c1;
const { first: t3, second: t4 } = this.Fp4Square(c0c0, c1c1);
const { first: t5, second: t6 } = this.Fp4Square(c1c0, c0c2);
const { first: t7, second: t8 } = this.Fp4Square(c0c1, c1c2);
let t9 = t8.mulByNonresidue();
return new Fp12([
new Fp6([
t3.subtract(c0c0).multiply(2n).add(t3),
t5.subtract(c0c1).multiply(2n).add(t5),
t7.subtract(c0c2).multiply(2n).add(t7),
]),
new Fp6([
t9.add(c1c0).multiply(2n).add(t9),
t4.add(c1c1).multiply(2n).add(t4),
t6.add(c1c2).multiply(2n).add(t6),
]),
]);
return new Fp12(new Fp6(t3.subtract(c0c0).multiply(2n).add(t3), t5.subtract(c0c1).multiply(2n).add(t5), t7.subtract(c0c2).multiply(2n).add(t7)), new Fp6(t9.add(c1c0).multiply(2n).add(t9), t4.add(c1c1).multiply(2n).add(t4), t6.add(c1c2).multiply(2n).add(t6)));
}

@@ -587,4 +591,4 @@ cyclotomicExp(n) {

}
Fp12.ZERO = new Fp12([Fp6.ZERO, Fp6.ZERO]);
Fp12.ONE = new Fp12([Fp6.ONE, Fp6.ZERO]);
Fp12.ZERO = new Fp12(Fp6.ZERO, Fp6.ZERO);
Fp12.ONE = new Fp12(Fp6.ONE, Fp6.ZERO);
export class ProjectivePoint {

@@ -619,2 +623,5 @@ constructor(x, y, z, C) {

toString(isAffine = true) {
if (this.isZero()) {
return `Point<Zero>`;
}
if (!isAffine) {

@@ -630,2 +637,4 @@ return `Point<x=${this.x}, y=${this.y}, z=${this.z}>`;

toAffine(invZ = this.z.invert()) {
if (invZ.isZero())
throw new Error('Invalid inverted z');
return [this.x.multiply(invZ), this.y.multiply(invZ)];

@@ -769,3 +778,4 @@ }

}
let [p, f] = [this.getZero(), this.getZero()];
let p = this.getZero();
let f = this.getZero();
const windows = Math.ceil(this.maxBits() / W);

@@ -799,3 +809,3 @@ const windowSize = 2 ** (W - 1);

function sgn0(x) {
const [x0, x1] = x.values;
const { re: x0, im: x1 } = x.reim();
const sign_0 = x0 % 2n;

@@ -815,3 +825,3 @@ const zero_0 = x0 === 0n;

const positiveRootsOfUnity = FP2_ROOTS_OF_UNITY.slice(0, 4);
for (const root of positiveRootsOfUnity) {
positiveRootsOfUnity.forEach((root) => {
const candidate = root.multiply(gamma);

@@ -822,11 +832,11 @@ if (candidate.pow(2n).multiply(v).subtract(u).isZero() && !success) {

}
}
return [success, result];
});
return { success, sqrtCandidateOrGamma: result };
}
export function map_to_curve_simple_swu_9mod16(t) {
const iso_3_a = new Fp2([0n, 240n]);
const iso_3_b = new Fp2([1012n, 1012n]);
const iso_3_z = new Fp2([-2n, -1n]);
const iso_3_a = new Fp2(new Fp(0n), new Fp(240n));
const iso_3_b = new Fp2(new Fp(1012n), new Fp(1012n));
const iso_3_z = new Fp2(new Fp(-2n), new Fp(-1n));
if (Array.isArray(t))
t = new Fp2(t);
t = Fp2.fromBigTuple(t);
const t2 = t.pow(2n);

@@ -844,3 +854,3 @@ const iso_3_z_t2 = iso_3_z.multiply(t2);

.add(iso_3_b.multiply(v));
const [success, sqrtCandidateOrGamma] = sqrt_div_fp2(u, v);
const { success, sqrtCandidateOrGamma } = sqrt_div_fp2(u, v);
let y;

@@ -852,3 +862,3 @@ if (success)

let success2 = false;
for (const eta of FP2_ETAs) {
FP2_ETAs.forEach((eta) => {
const etaSqrtCandidate = eta.multiply(sqrtCandidateX1);

@@ -860,3 +870,3 @@ const temp = etaSqrtCandidate.pow(2n).multiply(v).subtract(u);

}
}
});
if (!success && !success2)

@@ -873,3 +883,3 @@ throw new Error('Hash to Curve - Optimized SWU failure');

export function isogenyMapG2(xyz) {
const [x, y, z] = xyz;
const x = xyz[0], y = xyz[1], z = xyz[2];
const zz = z.multiply(z);

@@ -896,4 +906,4 @@ const zzz = zz.multiply(z);

export function calcPairingPrecomputes(x, y) {
const [Qx, Qy, Qz] = [x, y, Fp2.ONE];
let [Rx, Ry, Rz] = [Qx, Qy, Qz];
const Qx = x, Qy = y, Qz = Fp2.ONE;
let Rx = Qx, Ry = Qy, Rz = Qz;
let ell_coeff = [];

@@ -934,10 +944,12 @@ for (let i = BLS_X_LEN - 2; i >= 0; i--) {

export function millerLoop(ell, g1) {
const Px = g1[0].value;
const Py = g1[1].value;
let f12 = Fp12.ONE;
const [x, y] = g1;
const [Px, Py] = [x, y];
for (let j = 0, i = BLS_X_LEN - 2; i >= 0; i--, j++) {
f12 = f12.multiplyBy014(ell[j][0], ell[j][1].multiply(Px.value), ell[j][2].multiply(Py.value));
const E = ell[j];
f12 = f12.multiplyBy014(E[0], E[1].multiply(Px), E[2].multiply(Py));
if (bitGet(CURVE.x, i)) {
j += 1;
f12 = f12.multiplyBy014(ell[j][0], ell[j][1].multiply(Px.value), ell[j][2].multiply(Py.value));
const F = ell[j];
f12 = f12.multiplyBy014(F[0], F[1].multiply(Px), F[2].multiply(Py));
}

@@ -949,10 +961,9 @@ if (i !== 0)

}
const ut_root = new Fp6([Fp2.ZERO, Fp2.ONE, Fp2.ZERO]);
const wsq = new Fp12([ut_root, Fp6.ZERO]);
const wsq_inv = wsq.invert();
const wcu = new Fp12([Fp6.ZERO, ut_root]);
const wcu_inv = wcu.invert();
const ut_root = new Fp6(Fp2.ZERO, Fp2.ONE, Fp2.ZERO);
const wsq = new Fp12(ut_root, Fp6.ZERO);
const wcu = new Fp12(Fp6.ZERO, ut_root);
const [wsq_inv, wcu_inv] = genInvertBatch(Fp12, [wsq, wcu]);
export function psi(x, y) {
const x2 = wsq_inv.multiplyByFp2(x).frobeniusMap(1).multiply(wsq).c[0].c[0];
const y2 = wcu_inv.multiplyByFp2(y).frobeniusMap(1).multiply(wcu).c[0].c[0];
const x2 = wsq_inv.multiplyByFp2(x).frobeniusMap(1).multiply(wsq).c0.c0;
const y2 = wcu_inv.multiplyByFp2(y).frobeniusMap(1).multiply(wcu).c0.c0;
return [x2, y2];

@@ -982,3 +993,3 @@ }

[-rv1, -rv1],
].map((pair) => new Fp2(pair));
].map((pair) => Fp2.fromBigTuple(pair));
const FP2_ETAs = [

@@ -989,3 +1000,3 @@ [ev1, ev2],

[-ev4, ev3],
].map((pair) => new Fp2(pair));
].map((pair) => Fp2.fromBigTuple(pair));
const FP6_FROBENIUS_COEFFICIENTS_1 = [

@@ -1010,3 +1021,3 @@ [0x1n, 0x0n],

],
].map((pair) => new Fp2(pair));
].map((pair) => Fp2.fromBigTuple(pair));
const FP6_FROBENIUS_COEFFICIENTS_2 = [

@@ -1034,3 +1045,3 @@ [0x1n, 0x0n],

],
].map((pair) => new Fp2(pair));
].map((pair) => Fp2.fromBigTuple(pair));
const FP12_FROBENIUS_COEFFICIENTS = [

@@ -1082,3 +1093,3 @@ [0x1n, 0x0n],

],
].map((pair) => new Fp2(pair));
].map(n => Fp2.fromBigTuple(n));
const xnum = [

@@ -1101,3 +1112,3 @@ [

],
].map((pair) => new Fp2(pair));
].map((pair) => Fp2.fromBigTuple(pair));
const xden = [

@@ -1114,3 +1125,3 @@ [

[0x0n, 0x0n],
].map((pair) => new Fp2(pair));
].map((pair) => Fp2.fromBigTuple(pair));
const ynum = [

@@ -1133,3 +1144,3 @@ [

],
].map((pair) => new Fp2(pair));
].map((pair) => Fp2.fromBigTuple(pair));
const yden = [

@@ -1149,3 +1160,3 @@ [

[0x1n, 0x0n],
].map((pair) => new Fp2(pair));
].map((pair) => Fp2.fromBigTuple(pair));
const ISOGENY_COEFFICIENTS = [xnum, xden, ynum, yden];

@@ -1,8 +0,9 @@

/*! noble-bls12-381 - MIT License (c) Paul Miller (paulmillr.com) */
/*! noble-bls12-381 - MIT License (c) 2019 Paul Miller (paulmillr.com) */
import { Fp, Fr, Fp2, Fp12, CURVE, ProjectivePoint, mod } from './math.js';
export { Fp, Fr, Fp2, Fp12, CURVE };
declare type Bytes = Uint8Array | string;
declare type PrivateKey = Bytes | bigint | number;
declare type Hex = Uint8Array | string;
declare type PrivateKey = Hex | bigint | number;
export declare const utils: {
hashToField: typeof hash_to_field;
hashToPrivateKey: (hash: Hex) => Uint8Array;
bytesToHex: typeof bytesToHex;

@@ -22,3 +23,3 @@ randomBytes: (bytesLength?: number) => Uint8Array;

constructor(x: Fp, y: Fp, z?: Fp);
static fromHex(bytes: Bytes): PointG1;
static fromHex(bytes: Hex): PointG1;
static fromPrivateKey(privateKey: PrivateKey): PointG1;

@@ -42,5 +43,5 @@ toRawBytes(isCompressed?: boolean): Uint8Array;

constructor(x: Fp2, y: Fp2, z?: Fp2);
static hashToCurve(msg: Bytes): Promise<PointG2>;
static fromSignature(hex: Bytes): PointG2;
static fromHex(bytes: Bytes): PointG2;
static hashToCurve(msg: Hex): Promise<PointG2>;
static fromSignature(hex: Hex): PointG2;
static fromHex(bytes: Hex): PointG2;
static fromPrivateKey(privateKey: PrivateKey): PointG2;

@@ -61,12 +62,12 @@ toSignature(): Uint8Array;

export declare function pairing(P: PointG1, Q: PointG2, withFinalExponent?: boolean): Fp12;
declare type G1Hex = Bytes | PointG1;
declare type G2Hex = Bytes | PointG2;
declare type G1Hex = Hex | PointG1;
declare type G2Hex = Hex | PointG2;
export declare function getPublicKey(privateKey: PrivateKey): Uint8Array;
export declare function sign(message: Bytes, privateKey: PrivateKey): Promise<Uint8Array>;
export declare function sign(message: Hex, privateKey: PrivateKey): Promise<Uint8Array>;
export declare function sign(message: PointG2, privateKey: PrivateKey): Promise<PointG2>;
export declare function verify(signature: G2Hex, message: G2Hex, publicKey: G1Hex): Promise<boolean>;
export declare function aggregatePublicKeys(publicKeys: Bytes[]): Uint8Array;
export declare function aggregatePublicKeys(publicKeys: Hex[]): Uint8Array;
export declare function aggregatePublicKeys(publicKeys: PointG1[]): PointG1;
export declare function aggregateSignatures(signatures: Bytes[]): Uint8Array;
export declare function aggregateSignatures(signatures: Hex[]): Uint8Array;
export declare function aggregateSignatures(signatures: PointG2[]): PointG2;
export declare function verifyBatch(signature: G2Hex, messages: G2Hex[], publicKeys: G1Hex[]): Promise<boolean>;
"use strict";
/*! noble-bls12-381 - MIT License (c) Paul Miller (paulmillr.com) */
/*! noble-bls12-381 - MIT License (c) 2019 Paul Miller (paulmillr.com) */
var __importDefault = (this && this.__importDefault) || function (mod) {

@@ -36,2 +36,11 @@ return (mod && mod.__esModule) ? mod : { "default": mod };

hashToField: hash_to_field,
hashToPrivateKey: (hash) => {
hash = ensureBytes(hash);
if (hash.length < 40 || hash.length > 1024)
throw new Error('Expected 40-1024 bytes of private key as per FIPS 186');
const num = (0, math_js_1.mod)(bytesToNumberBE(hash), math_js_1.CURVE.r);
if (num === 0n || num === 1n)
throw new Error('Invalid private key');
return numberTo32BytesBE(num);
},
bytesToHex,

@@ -51,10 +60,3 @@ randomBytes: (bytesLength = 32) => {

randomPrivateKey: () => {
let i = 8;
while (i--) {
const b32 = exports.utils.randomBytes(32);
const num = bytesToNumberBE(b32);
if (isWithinCurveOrder(num) && num !== 1n)
return b32;
}
throw new Error('Valid private key was not found in 8 iterations. PRNG is broken');
return exports.utils.hashToPrivateKey(exports.utils.randomBytes(40));
},

@@ -84,8 +86,6 @@ sha256: async (message) => {

};
function bytesToNumberBE(bytes) {
let value = 0n;
for (let i = bytes.length - 1, j = 0; i >= 0; i--, j++) {
value += (BigInt(bytes[i]) & 255n) << (8n * BigInt(j));
}
return value;
function bytesToNumberBE(uint8a) {
if (!(uint8a instanceof Uint8Array))
throw new Error('Expected Uint8Array');
return BigInt('0x' + bytesToHex(Uint8Array.from(uint8a)));
}

@@ -113,3 +113,3 @@ const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));

const byte = Number.parseInt(hexByte, 16);
if (Number.isNaN(byte))
if (Number.isNaN(byte) || byte < 0)
throw new Error('Invalid byte sequence');

@@ -120,5 +120,10 @@ array[i] = byte;

}
function numberTo32BytesBE(num) {
const length = 32;
const hex = num.toString(16).padStart(length * 2, '0');
return hexToBytes(hex);
}
function toPaddedHex(num, padding) {
if (num < 0n)
throw new Error('Expected valid number');
if (typeof num !== 'bigint' || num < 0n)
throw new Error('Expected valid bigint');
if (typeof padding !== 'number')

@@ -129,7 +134,3 @@ throw new TypeError('Expected valid padding');

function ensureBytes(hex) {
if (hex instanceof Uint8Array)
return hex;
if (typeof hex === 'string')
return hexToBytes(hex);
throw new TypeError('Expected hex string or Uint8Array');
return hex instanceof Uint8Array ? Uint8Array.from(hex) : hexToBytes(hex);
}

@@ -253,5 +254,5 @@ function concatBytes(...arrays) {

bytes = ensureBytes(bytes);
const { P } = math_js_1.CURVE;
let point;
if (bytes.length === 48) {
const { P } = math_js_1.CURVE;
const compressedValue = bytesToNumberBE(bytes);

@@ -293,4 +294,4 @@ const bflag = (0, math_js_1.mod)(compressedValue, POW_2_383) / POW_2_382;

this.assertValidity();
const { P } = math_js_1.CURVE;
if (isCompressed) {
const { P } = math_js_1.CURVE;
let hex;

@@ -394,10 +395,10 @@ if (this.isZero()) {

return this.ZERO;
const x1 = z1 % POW_2_381;
const x2 = z2;
const x = new math_js_1.Fp2([x2, x1]);
const y2 = x.pow(3n).add(new math_js_1.Fp2(math_js_1.CURVE.b2));
const x1 = new math_js_1.Fp(z1 % POW_2_381);
const x2 = new math_js_1.Fp(z2);
const x = new math_js_1.Fp2(x2, x1);
const y2 = x.pow(3n).add(math_js_1.Fp2.fromBigTuple(math_js_1.CURVE.b2));
let y = y2.sqrt();
if (!y)
throw new Error('Failed to find a square root');
const [y0, y1] = y.values;
const { re: y0, im: y1 } = y.reim();
const aflag1 = (z1 % POW_2_382) / POW_2_381;

@@ -414,7 +415,32 @@ const isGreater = y1 > 0n && (y1 * 2n) / P !== aflag1;

bytes = ensureBytes(bytes);
const m_byte = bytes[0] & 0xe0;
if (m_byte === 0x20 || m_byte === 0x60 || m_byte === 0xe0) {
throw new Error('Invalid encoding flag: ' + m_byte);
}
const bitC = m_byte & 0x80;
const bitI = m_byte & 0x40;
const bitS = m_byte & 0x20;
let point;
if (bytes.length === 96) {
throw new Error('Compressed format not supported yet.');
if (bytes.length === 96 && bitC) {
const { P, b2 } = math_js_1.CURVE;
const b = math_js_1.Fp2.fromBigTuple(b2);
bytes[0] = bytes[0] & 0x1f;
if (bitI) {
if (bytes.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
throw new Error('Invalid compressed G2 point');
}
return PointG2.ZERO;
}
const x_1 = bytesToNumberBE(bytes.slice(0, PUBLIC_KEY_LENGTH));
const x_0 = bytesToNumberBE(bytes.slice(PUBLIC_KEY_LENGTH));
const x = new math_js_1.Fp2(new math_js_1.Fp(x_0), new math_js_1.Fp(x_1));
const right = x.pow(3n).add(b);
let y = right.sqrt();
if (!y)
throw new Error('Invalid compressed G2 point');
const Y_bit = y.c1.value === 0n ? (y.c0.value * 2n) / P : (y.c1.value * 2n) / P ? 1n : 0n;
y = bitS > 0 && Y_bit > 0 ? y : y.negate();
return new PointG2(x, y);
}
else if (bytes.length === 192) {
else if (bytes.length === 192 && !bitC) {
if ((bytes[0] & (1 << 6)) !== 0) {

@@ -427,6 +453,6 @@ return PointG2.ZERO;

const y0 = bytesToNumberBE(bytes.slice(3 * PUBLIC_KEY_LENGTH));
point = new PointG2(new math_js_1.Fp2([x0, x1]), new math_js_1.Fp2([y0, y1]));
point = new PointG2(math_js_1.Fp2.fromBigTuple([x0, x1]), math_js_1.Fp2.fromBigTuple([y0, y1]));
}
else {
throw new Error('Invalid uncompressed point G2, expected 192 bytes');
throw new Error('Invalid point G2, expected 96/192 bytes');
}

@@ -445,3 +471,3 @@ point.assertValidity();

}
const [[x0, x1], [y0, y1]] = this.toAffine().map((a) => a.values);
const [{ re: x0, im: x1 }, { re: y0, im: y1 }] = this.toAffine().map((a) => a.reim());
const tmp = y1 > 0n ? y1 * 2n : y0 * 2n;

@@ -459,3 +485,15 @@ const aflag1 = tmp / math_js_1.CURVE.P;

if (isCompressed) {
throw new Error('Point compression has not yet been implemented');
const { P } = math_js_1.CURVE;
let x_1 = 0n;
let x_0 = 0n;
if (this.isZero()) {
x_1 = POW_2_383 + POW_2_382;
}
else {
const [x, y] = this.toAffine();
const flag = y.c1.value === 0n ? (y.c0.value * 2n) / P : (y.c1.value * 2n) / P ? 1n : 0n;
x_1 = x.c1.value + flag * POW_2_381 + POW_2_383;
x_0 = x.c0.value;
}
return toPaddedHex(x_1, PUBLIC_KEY_LENGTH) + toPaddedHex(x_0, PUBLIC_KEY_LENGTH);
}

@@ -466,3 +504,3 @@ else {

}
const [[x0, x1], [y0, y1]] = this.toAffine().map((a) => a.values);
const [{ re: x0, im: x1 }, { re: y0, im: y1 }] = this.toAffine().map((a) => a.reim());
return (toPaddedHex(x1, PUBLIC_KEY_LENGTH) +

@@ -507,3 +545,3 @@ toPaddedHex(x0, PUBLIC_KEY_LENGTH) +

isOnCurve() {
const b = new math_js_1.Fp2(math_js_1.CURVE.b2);
const b = math_js_1.Fp2.fromBigTuple(math_js_1.CURVE.b2);
const { x, y, z } = this;

@@ -532,3 +570,3 @@ const left = y.pow(2n).multiply(z).subtract(x.pow(3n));

exports.PointG2 = PointG2;
PointG2.BASE = new PointG2(new math_js_1.Fp2(math_js_1.CURVE.G2x), new math_js_1.Fp2(math_js_1.CURVE.G2y), math_js_1.Fp2.ONE);
PointG2.BASE = new PointG2(math_js_1.Fp2.fromBigTuple(math_js_1.CURVE.G2x), math_js_1.Fp2.fromBigTuple(math_js_1.CURVE.G2y), math_js_1.Fp2.ONE);
PointG2.ZERO = new PointG2(math_js_1.Fp2.ONE, math_js_1.Fp2.ONE, math_js_1.Fp2.ZERO);

@@ -535,0 +573,0 @@ function pairing(P, Q, withFinalExponent = true) {

@@ -49,3 +49,3 @@ export declare const CURVE: {

export declare function mod(a: bigint, b: bigint): bigint;
export declare function powMod(a: bigint, power: bigint, modulo: bigint): bigint;
export declare function powMod(num: bigint, power: bigint, modulo: bigint): bigint;
export declare class Fp implements Field<Fp> {

@@ -92,23 +92,5 @@ static readonly ORDER: bigint;

}
declare abstract class FQP<TT extends {
c: TTT;
} & Field<TT>, CT extends Field<CT>, TTT extends CT[]> implements Field<TT> {
abstract readonly c: CT[];
abstract init(c: TTT): TT;
abstract multiply(rhs: TT | bigint): TT;
abstract invert(): TT;
abstract square(): TT;
zip<T, RT extends T[]>(rhs: TT, mapper: (left: CT, right: CT) => T): RT;
map<T, RT extends T[]>(callbackfn: (value: CT) => T): RT;
isZero(): boolean;
equals(rhs: TT): boolean;
negate(): TT;
add(rhs: TT): TT;
subtract(rhs: TT): TT;
conjugate(): TT;
private one;
pow(n: bigint): TT;
div(rhs: TT | bigint): TT;
}
export declare class Fp2 extends FQP<Fp2, Fp, [Fp, Fp]> {
export declare class Fp2 implements Field<Fp2> {
readonly c0: Fp;
readonly c1: Fp;
static readonly ORDER: bigint;

@@ -118,8 +100,18 @@ static readonly MAX_BITS: number;

static readonly ONE: Fp2;
readonly c: [Fp, Fp];
constructor(coeffs: [Fp, Fp] | [bigint, bigint] | bigint[]);
init(tuple: [Fp, Fp]): Fp2;
constructor(c0: Fp, c1: Fp);
static fromBigTuple(tuple: BigintTuple | bigint[]): Fp2;
one(): Fp2;
isZero(): boolean;
toString(): string;
get values(): BigintTuple;
reim(): {
re: bigint;
im: bigint;
};
negate(): Fp2;
equals(rhs: Fp2): boolean;
add(rhs: Fp2): Fp2;
subtract(rhs: Fp2): Fp2;
multiply(rhs: Fp2 | bigint): Fp2;
pow(n: bigint): Fp2;
div(rhs: Fp2 | bigint): Fp2;
mulByNonresidue(): Fp2;

@@ -132,12 +124,21 @@ square(): Fp2;

}
export declare class Fp6 extends FQP<Fp6, Fp2, [Fp2, Fp2, Fp2]> {
readonly c: [Fp2, Fp2, Fp2];
export declare class Fp6 implements Field<Fp6> {
readonly c0: Fp2;
readonly c1: Fp2;
readonly c2: Fp2;
static readonly ZERO: Fp6;
static readonly ONE: Fp6;
static fromTuple(t: BigintSix): Fp6;
constructor(c: [Fp2, Fp2, Fp2]);
init(triple: [Fp2, Fp2, Fp2]): Fp6;
static fromBigSix(t: BigintSix): Fp6;
constructor(c0: Fp2, c1: Fp2, c2: Fp2);
fromTriple(triple: [Fp2, Fp2, Fp2]): Fp6;
one(): Fp6;
isZero(): boolean;
negate(): Fp6;
toString(): string;
conjugate(): any;
equals(rhs: Fp6): boolean;
add(rhs: Fp6): Fp6;
subtract(rhs: Fp6): Fp6;
multiply(rhs: Fp6 | bigint): Fp6;
pow(n: bigint): Fp6;
div(rhs: Fp6 | bigint): Fp6;
mulByNonresidue(): Fp6;

@@ -151,11 +152,20 @@ multiplyBy1(b1: Fp2): Fp6;

}
export declare class Fp12 extends FQP<Fp12, Fp6, [Fp6, Fp6]> {
readonly c: [Fp6, Fp6];
export declare class Fp12 implements Field<Fp12> {
readonly c0: Fp6;
readonly c1: Fp6;
static readonly ZERO: Fp12;
static readonly ONE: Fp12;
static fromTuple(t: BigintTwelve): Fp12;
constructor(c: [Fp6, Fp6]);
init(c: [Fp6, Fp6]): Fp12;
static fromBigTwelve(t: BigintTwelve): Fp12;
constructor(c0: Fp6, c1: Fp6);
fromTuple(c: [Fp6, Fp6]): Fp12;
one(): Fp12;
isZero(): boolean;
toString(): string;
negate(): Fp12;
equals(rhs: Fp12): boolean;
add(rhs: Fp12): Fp12;
subtract(rhs: Fp12): Fp12;
multiply(rhs: Fp12 | bigint): Fp12;
pow(n: bigint): Fp12;
div(rhs: Fp12 | bigint): Fp12;
multiplyBy014(o0: Fp2, o1: Fp2, o4: Fp2): Fp12;

@@ -165,2 +175,3 @@ multiplyByFp2(rhs: Fp2): Fp12;

invert(): Fp12;
conjugate(): Fp12;
frobeniusMap(power: number): Fp12;

@@ -167,0 +178,0 @@ private Fp4Square;

@@ -33,8 +33,12 @@ "use strict";

exports.mod = mod;
function powMod(a, power, modulo) {
function powMod(num, power, modulo) {
if (modulo <= 0n || power < 0n)
throw new Error('Expected power/modulo > 0');
if (modulo === 1n)
return 0n;
let res = 1n;
while (power > 0n) {
if (power & 1n)
res = (res * a) % modulo;
a = (a * a) % modulo;
res = (res * num) % modulo;
num = (num * num) % modulo;
power >>= 1n;

@@ -46,20 +50,17 @@ }

function genInvertBatch(cls, nums) {
const len = nums.length;
const scratch = new Array(len);
let acc = cls.ONE;
for (let i = 0; i < len; i++) {
if (nums[i].isZero())
continue;
scratch[i] = acc;
acc = acc.multiply(nums[i]);
}
acc = acc.invert();
for (let i = len - 1; i >= 0; i--) {
if (nums[i].isZero())
continue;
let tmp = acc.multiply(nums[i]);
nums[i] = acc.multiply(scratch[i]);
acc = tmp;
}
return nums;
const tmp = new Array(nums.length);
const lastMultiplied = nums.reduce((acc, num, i) => {
if (num.isZero())
return acc;
tmp[i] = acc;
return acc.multiply(num);
}, cls.ONE);
const inverted = lastMultiplied.invert();
nums.reduceRight((acc, num, i) => {
if (num.isZero())
return acc;
tmp[i] = acc.multiply(tmp[i]);
return acc.multiply(num);
}, inverted);
return tmp;
}

@@ -76,3 +77,5 @@ function bitLen(n) {

function invert(number, modulo = exports.CURVE.P) {
if (number === 0n || modulo <= 0n) {
const _0n = 0n;
const _1n = 1n;
if (number === _0n || modulo <= _0n) {
throw new Error(`invert: expected positive integers, got n=${number} mod=${modulo}`);

@@ -82,4 +85,4 @@ }

let b = modulo;
let [x, y, u, v] = [0n, 1n, 1n, 0n];
while (a !== 0n) {
let x = _0n, y = _1n, u = _1n, v = _0n;
while (a !== _0n) {
const q = b / a;

@@ -89,8 +92,6 @@ const r = b % a;

const n = y - v * q;
[b, a] = [a, r];
[x, y] = [u, v];
[u, v] = [m, n];
b = a, a = r, x = u, y = v, u = m, v = n;
}
const gcd = b;
if (gcd !== 1n)
if (gcd !== _1n)
throw new Error('invert: does not exist');

@@ -236,60 +237,74 @@ return mod(x, modulo);

Fr.ONE = new Fr(1n);
class FQP {
zip(rhs, mapper) {
const c0 = this.c;
const c1 = rhs.c;
const res = [];
for (let i = 0; i < c0.length; i++) {
res.push(mapper(c0[i], c1[i]));
}
return res;
function powMod_FQP(fqp, fqpOne, n) {
const elm = fqp;
if (n === 0n)
return fqpOne;
if (n === 1n)
return elm;
let p = fqpOne;
let d = elm;
while (n > 0n) {
if (n & 1n)
p = p.multiply(d);
n >>= 1n;
d = d.square();
}
map(callbackfn) {
return this.c.map(callbackfn);
return p;
}
class Fp2 {
constructor(c0, c1) {
this.c0 = c0;
this.c1 = c1;
if (typeof c0 === 'bigint')
throw new Error('c0: Expected Fp');
if (typeof c1 === 'bigint')
throw new Error('c1: Expected Fp');
}
static fromBigTuple(tuple) {
const fps = tuple.map(n => new Fp(n));
return new Fp2(...fps);
}
one() {
return Fp2.ONE;
}
isZero() {
return this.c.every((c) => c.isZero());
return this.c0.isZero() && this.c1.isZero();
}
equals(rhs) {
return this.zip(rhs, (left, right) => left.equals(right)).every((r) => r);
toString() {
return `Fp2(${this.c0} + ${this.c1}×i)`;
}
reim() {
return { re: this.c0.value, im: this.c1.value };
}
negate() {
return this.init(this.map((c) => c.negate()));
const { c0, c1 } = this;
return new Fp2(c0.negate(), c1.negate());
}
equals(rhs) {
const { c0, c1 } = this;
const { c0: r0, c1: r1 } = rhs;
return c0.equals(r0) && c1.equals(r1);
}
add(rhs) {
return this.init(this.zip(rhs, (left, right) => left.add(right)));
const { c0, c1 } = this;
const { c0: r0, c1: r1 } = rhs;
return new Fp2(c0.add(r0), c1.add(r1));
}
subtract(rhs) {
return this.init(this.zip(rhs, (left, right) => left.subtract(right)));
const { c0, c1 } = this;
const { c0: r0, c1: r1 } = rhs;
return new Fp2(c0.subtract(r0), c1.subtract(r1));
}
conjugate() {
return this.init([this.c[0], this.c[1].negate()]);
multiply(rhs) {
const { c0, c1 } = this;
if (typeof rhs === 'bigint') {
return new Fp2(c0.multiply(rhs), c1.multiply(rhs));
}
const { c0: r0, c1: r1 } = rhs;
let t1 = c0.multiply(r0);
let t2 = c1.multiply(r1);
return new Fp2(t1.subtract(t2), c0.add(c1).multiply(r0.add(r1)).subtract(t1.add(t2)));
}
one() {
const el = this;
let one;
if (el instanceof Fp2)
one = Fp2.ONE;
if (el instanceof Fp6)
one = Fp6.ONE;
if (el instanceof Fp12)
one = Fp12.ONE;
return one;
}
pow(n) {
const elm = this;
const one = this.one();
if (n === 0n)
return one;
if (n === 1n)
return elm;
let p = one;
let d = elm;
while (n > 0n) {
if (n & 1n)
p = p.multiply(d);
n >>= 1n;
d = d.square();
}
return p;
return powMod_FQP(this, Fp2.ONE, n);
}

@@ -300,44 +315,14 @@ div(rhs) {

}
}
class Fp2 extends FQP {
constructor(coeffs) {
super();
if (coeffs.length !== 2)
throw new Error(`Expected array with 2 elements`);
coeffs.forEach((c, i) => {
if (typeof c === 'bigint')
coeffs[i] = new Fp(c);
});
this.c = coeffs;
}
init(tuple) {
return new Fp2(tuple);
}
toString() {
return `Fp2(${this.c[0]} + ${this.c[1]}×i)`;
}
get values() {
return this.c.map((c) => c.value);
}
multiply(rhs) {
if (typeof rhs === 'bigint')
return new Fp2(this.map((c) => c.multiply(rhs)));
const [c0, c1] = this.c;
const [r0, r1] = rhs.c;
let t1 = c0.multiply(r0);
let t2 = c1.multiply(r1);
return new Fp2([t1.subtract(t2), c0.add(c1).multiply(r0.add(r1)).subtract(t1.add(t2))]);
}
mulByNonresidue() {
const c0 = this.c[0];
const c1 = this.c[1];
return new Fp2([c0.subtract(c1), c0.add(c1)]);
const c0 = this.c0;
const c1 = this.c1;
return new Fp2(c0.subtract(c1), c0.add(c1));
}
square() {
const c0 = this.c[0];
const c1 = this.c[1];
const c0 = this.c0;
const c1 = this.c1;
const a = c0.add(c1);
const b = c0.subtract(c1);
const c = c0.add(c0);
return new Fp2([a.multiply(b), c.multiply(c1)]);
return new Fp2(a.multiply(b), c.multiply(c1));
}

@@ -357,4 +342,4 @@ sqrt() {

const x2 = x1.negate();
const [re1, im1] = x1.values;
const [re2, im2] = x2.values;
const { re: re1, im: im1 } = x1.reim();
const { re: re2, im: im2 } = x2.reim();
if (im1 > im2 || (im1 === im2 && re1 > re2))

@@ -365,14 +350,15 @@ return x1;

invert() {
const [a, b] = this.values;
const { re: a, im: b } = this.reim();
const factor = new Fp(a * a + b * b).invert();
return new Fp2([factor.multiply(new Fp(a)), factor.multiply(new Fp(-b))]);
return new Fp2(factor.multiply(new Fp(a)), factor.multiply(new Fp(-b)));
}
frobeniusMap(power) {
return new Fp2([this.c[0], this.c[1].multiply(FP2_FROBENIUS_COEFFICIENTS[power % 2])]);
return new Fp2(this.c0, this.c1.multiply(FP2_FROBENIUS_COEFFICIENTS[power % 2]));
}
multiplyByB() {
let [c0, c1] = this.c;
let c0 = this.c0;
let c1 = this.c1;
let t0 = c0.multiply(4n);
let t1 = c1.multiply(4n);
return new Fp2([t0.subtract(t1), t0.add(t1)]);
return new Fp2(t0.subtract(t1), t0.add(t1));
}

@@ -383,64 +369,83 @@ }

Fp2.MAX_BITS = bitLen(exports.CURVE.P2);
Fp2.ZERO = new Fp2([0n, 0n]);
Fp2.ONE = new Fp2([1n, 0n]);
class Fp6 extends FQP {
constructor(c) {
super();
this.c = c;
if (c.length !== 3)
throw new Error(`Expected array with 3 elements`);
Fp2.ZERO = new Fp2(Fp.ZERO, Fp.ZERO);
Fp2.ONE = new Fp2(Fp.ONE, Fp.ZERO);
class Fp6 {
constructor(c0, c1, c2) {
this.c0 = c0;
this.c1 = c1;
this.c2 = c2;
}
static fromTuple(t) {
static fromBigSix(t) {
if (!Array.isArray(t) || t.length !== 6)
throw new Error('Invalid Fp6 usage');
return new Fp6([new Fp2(t.slice(0, 2)), new Fp2(t.slice(2, 4)), new Fp2(t.slice(4, 6))]);
const c = [t.slice(0, 2), t.slice(2, 4), t.slice(4, 6)].map(t => Fp2.fromBigTuple(t));
return new Fp6(...c);
}
init(triple) {
return new Fp6(triple);
fromTriple(triple) {
return new Fp6(...triple);
}
one() {
return Fp6.ONE;
}
isZero() {
return this.c0.isZero() && this.c1.isZero() && this.c2.isZero();
}
negate() {
const { c0, c1, c2 } = this;
return new Fp6(c0.negate(), c1.negate(), c2.negate());
}
toString() {
return `Fp6(${this.c[0]} + ${this.c[1]} * v, ${this.c[2]} * v^2)`;
return `Fp6(${this.c0} + ${this.c1} * v, ${this.c2} * v^2)`;
}
conjugate() {
throw new TypeError('No conjugate on Fp6');
equals(rhs) {
const { c0, c1, c2 } = this;
const { c0: r0, c1: r1, c2: r2 } = rhs;
return c0.equals(r0) && c1.equals(r1) && c2.equals(r2);
}
add(rhs) {
const { c0, c1, c2 } = this;
const { c0: r0, c1: r1, c2: r2 } = rhs;
return new Fp6(c0.add(r0), c1.add(r1), c2.add(r2));
}
subtract(rhs) {
const { c0, c1, c2 } = this;
const { c0: r0, c1: r1, c2: r2 } = rhs;
return new Fp6(c0.subtract(r0), c1.subtract(r1), c2.subtract(r2));
}
multiply(rhs) {
if (typeof rhs === 'bigint')
return new Fp6([this.c[0].multiply(rhs), this.c[1].multiply(rhs), this.c[2].multiply(rhs)]);
let [c0, c1, c2] = this.c;
const [r0, r1, r2] = rhs.c;
if (typeof rhs === 'bigint') {
return new Fp6(this.c0.multiply(rhs), this.c1.multiply(rhs), this.c2.multiply(rhs));
}
let { c0, c1, c2 } = this;
let { c0: r0, c1: r1, c2: r2 } = rhs;
let t0 = c0.multiply(r0);
let t1 = c1.multiply(r1);
let t2 = c2.multiply(r2);
return new Fp6([
t0.add(c1.add(c2).multiply(r1.add(r2)).subtract(t1.add(t2)).mulByNonresidue()),
c0.add(c1).multiply(r0.add(r1)).subtract(t0.add(t1)).add(t2.mulByNonresidue()),
t1.add(c0.add(c2).multiply(r0.add(r2)).subtract(t0.add(t2))),
]);
return new Fp6(t0.add(c1.add(c2).multiply(r1.add(r2)).subtract(t1.add(t2)).mulByNonresidue()), c0.add(c1).multiply(r0.add(r1)).subtract(t0.add(t1)).add(t2.mulByNonresidue()), t1.add(c0.add(c2).multiply(r0.add(r2)).subtract(t0.add(t2))));
}
pow(n) {
return powMod_FQP(this, Fp6.ONE, n);
}
div(rhs) {
const inv = typeof rhs === 'bigint' ? new Fp(rhs).invert().value : rhs.invert();
return this.multiply(inv);
}
mulByNonresidue() {
return new Fp6([this.c[2].mulByNonresidue(), this.c[0], this.c[1]]);
return new Fp6(this.c2.mulByNonresidue(), this.c0, this.c1);
}
multiplyBy1(b1) {
return new Fp6([
this.c[2].multiply(b1).mulByNonresidue(),
this.c[0].multiply(b1),
this.c[1].multiply(b1),
]);
return new Fp6(this.c2.multiply(b1).mulByNonresidue(), this.c0.multiply(b1), this.c1.multiply(b1));
}
multiplyBy01(b0, b1) {
let [c0, c1, c2] = this.c;
let { c0, c1, c2 } = this;
let t0 = c0.multiply(b0);
let t1 = c1.multiply(b1);
return new Fp6([
c1.add(c2).multiply(b1).subtract(t1).mulByNonresidue().add(t0),
b0.add(b1).multiply(c0.add(c1)).subtract(t0).subtract(t1),
c0.add(c2).multiply(b0).subtract(t0).add(t1),
]);
return new Fp6(c1.add(c2).multiply(b1).subtract(t1).mulByNonresidue().add(t0), b0.add(b1).multiply(c0.add(c1)).subtract(t0).subtract(t1), c0.add(c2).multiply(b0).subtract(t0).add(t1));
}
multiplyByFp2(rhs) {
return new Fp6(this.map((c) => c.multiply(rhs)));
let { c0, c1, c2 } = this;
return new Fp6(c0.multiply(rhs), c1.multiply(rhs), c2.multiply(rhs));
}
square() {
let [c0, c1, c2] = this.c;
let { c0, c1, c2 } = this;
let t0 = c0.square();

@@ -450,10 +455,6 @@ let t1 = c0.multiply(c1).multiply(2n);

let t4 = c2.square();
return new Fp6([
t3.mulByNonresidue().add(t0),
t4.mulByNonresidue().add(t1),
t1.add(c0.subtract(c1).add(c2).square()).add(t3).subtract(t0).subtract(t4),
]);
return new Fp6(t3.mulByNonresidue().add(t0), t4.mulByNonresidue().add(t1), t1.add(c0.subtract(c1).add(c2).square()).add(t3).subtract(t0).subtract(t4));
}
invert() {
let [c0, c1, c2] = this.c;
let { c0, c1, c2 } = this;
let t0 = c0.square().subtract(c2.multiply(c1).mulByNonresidue());

@@ -463,107 +464,110 @@ let t1 = c2.square().mulByNonresidue().subtract(c0.multiply(c1));

let t4 = c2.multiply(t1).add(c1.multiply(t2)).mulByNonresidue().add(c0.multiply(t0)).invert();
return new Fp6([t4.multiply(t0), t4.multiply(t1), t4.multiply(t2)]);
return new Fp6(t4.multiply(t0), t4.multiply(t1), t4.multiply(t2));
}
frobeniusMap(power) {
return new Fp6([
this.c[0].frobeniusMap(power),
this.c[1].frobeniusMap(power).multiply(FP6_FROBENIUS_COEFFICIENTS_1[power % 6]),
this.c[2].frobeniusMap(power).multiply(FP6_FROBENIUS_COEFFICIENTS_2[power % 6]),
]);
return new Fp6(this.c0.frobeniusMap(power), this.c1.frobeniusMap(power).multiply(FP6_FROBENIUS_COEFFICIENTS_1[power % 6]), this.c2.frobeniusMap(power).multiply(FP6_FROBENIUS_COEFFICIENTS_2[power % 6]));
}
}
exports.Fp6 = Fp6;
Fp6.ZERO = new Fp6([Fp2.ZERO, Fp2.ZERO, Fp2.ZERO]);
Fp6.ONE = new Fp6([Fp2.ONE, Fp2.ZERO, Fp2.ZERO]);
class Fp12 extends FQP {
constructor(c) {
super();
this.c = c;
if (c.length !== 2)
throw new Error(`Expected array with 2 elements`);
Fp6.ZERO = new Fp6(Fp2.ZERO, Fp2.ZERO, Fp2.ZERO);
Fp6.ONE = new Fp6(Fp2.ONE, Fp2.ZERO, Fp2.ZERO);
class Fp12 {
constructor(c0, c1) {
this.c0 = c0;
this.c1 = c1;
}
static fromTuple(t) {
return new Fp12([
Fp6.fromTuple(t.slice(0, 6)),
Fp6.fromTuple(t.slice(6, 12)),
]);
static fromBigTwelve(t) {
return new Fp12(Fp6.fromBigSix(t.slice(0, 6)), Fp6.fromBigSix(t.slice(6, 12)));
}
init(c) {
return new Fp12(c);
fromTuple(c) {
return new Fp12(...c);
}
one() {
return Fp12.ONE;
}
isZero() {
return this.c0.isZero() && this.c1.isZero();
}
toString() {
return `Fp12(${this.c[0]} + ${this.c[1]} * w)`;
return `Fp12(${this.c0} + ${this.c1} * w)`;
}
negate() {
const { c0, c1 } = this;
return new Fp12(c0.negate(), c1.negate());
}
equals(rhs) {
const { c0, c1 } = this;
const { c0: r0, c1: r1 } = rhs;
return c0.equals(r0) && c1.equals(r1);
}
add(rhs) {
const { c0, c1 } = this;
const { c0: r0, c1: r1 } = rhs;
return new Fp12(c0.add(r0), c1.add(r1));
}
subtract(rhs) {
const { c0, c1 } = this;
const { c0: r0, c1: r1 } = rhs;
return new Fp12(c0.subtract(r0), c1.subtract(r1));
}
multiply(rhs) {
if (typeof rhs === 'bigint')
return new Fp12([this.c[0].multiply(rhs), this.c[1].multiply(rhs)]);
let [c0, c1] = this.c;
const [r0, r1] = rhs.c;
return new Fp12(this.c0.multiply(rhs), this.c1.multiply(rhs));
let { c0, c1 } = this;
let { c0: r0, c1: r1 } = rhs;
let t1 = c0.multiply(r0);
let t2 = c1.multiply(r1);
return new Fp12([
t1.add(t2.mulByNonresidue()),
c0.add(c1).multiply(r0.add(r1)).subtract(t1.add(t2)),
]);
return new Fp12(t1.add(t2.mulByNonresidue()), c0.add(c1).multiply(r0.add(r1)).subtract(t1.add(t2)));
}
pow(n) {
return powMod_FQP(this, Fp12.ONE, n);
}
div(rhs) {
const inv = typeof rhs === 'bigint' ? new Fp(rhs).invert().value : rhs.invert();
return this.multiply(inv);
}
multiplyBy014(o0, o1, o4) {
let [c0, c1] = this.c;
let [t0, t1] = [c0.multiplyBy01(o0, o1), c1.multiplyBy1(o4)];
return new Fp12([
t1.mulByNonresidue().add(t0),
c1.add(c0).multiplyBy01(o0, o1.add(o4)).subtract(t0).subtract(t1),
]);
let { c0, c1 } = this;
let t0 = c0.multiplyBy01(o0, o1);
let t1 = c1.multiplyBy1(o4);
return new Fp12(t1.mulByNonresidue().add(t0), c1.add(c0).multiplyBy01(o0, o1.add(o4)).subtract(t0).subtract(t1));
}
multiplyByFp2(rhs) {
return this.init(this.map((c) => c.multiplyByFp2(rhs)));
return new Fp12(this.c0.multiplyByFp2(rhs), this.c1.multiplyByFp2(rhs));
}
square() {
let [c0, c1] = this.c;
let { c0, c1 } = this;
let ab = c0.multiply(c1);
return new Fp12([
c1.mulByNonresidue().add(c0).multiply(c0.add(c1)).subtract(ab).subtract(ab.mulByNonresidue()),
ab.add(ab),
]);
return new Fp12(c1.mulByNonresidue().add(c0).multiply(c0.add(c1)).subtract(ab).subtract(ab.mulByNonresidue()), ab.add(ab));
}
invert() {
let [c0, c1] = this.c;
let { c0, c1 } = this;
let t = c0.square().subtract(c1.square().mulByNonresidue()).invert();
return new Fp12([c0.multiply(t), c1.multiply(t).negate()]);
return new Fp12(c0.multiply(t), c1.multiply(t).negate());
}
conjugate() {
return new Fp12(this.c0, this.c1.negate());
}
frobeniusMap(power) {
const [c0, c1] = this.c;
let r0 = c0.frobeniusMap(power);
let [c1_0, c1_1, c1_2] = c1.frobeniusMap(power).c;
const r0 = this.c0.frobeniusMap(power);
const { c0, c1, c2 } = this.c1.frobeniusMap(power);
const coeff = FP12_FROBENIUS_COEFFICIENTS[power % 12];
return new Fp12([
r0,
new Fp6([c1_0.multiply(coeff), c1_1.multiply(coeff), c1_2.multiply(coeff)]),
]);
return new Fp12(r0, new Fp6(c0.multiply(coeff), c1.multiply(coeff), c2.multiply(coeff)));
}
Fp4Square(a, b) {
const a2 = a.square(), b2 = b.square();
return [
b2.mulByNonresidue().add(a2),
a.add(b).square().subtract(a2).subtract(b2),
];
const a2 = a.square();
const b2 = b.square();
return {
first: b2.mulByNonresidue().add(a2),
second: a.add(b).square().subtract(a2).subtract(b2),
};
}
cyclotomicSquare() {
const [c0, c1] = this.c;
const [c0c0, c0c1, c0c2] = c0.c;
const [c1c0, c1c1, c1c2] = c1.c;
let [t3, t4] = this.Fp4Square(c0c0, c1c1);
let [t5, t6] = this.Fp4Square(c1c0, c0c2);
let [t7, t8] = this.Fp4Square(c0c1, c1c2);
const { c0: c0c0, c1: c0c1, c2: c0c2 } = this.c0;
const { c0: c1c0, c1: c1c1, c2: c1c2 } = this.c1;
const { first: t3, second: t4 } = this.Fp4Square(c0c0, c1c1);
const { first: t5, second: t6 } = this.Fp4Square(c1c0, c0c2);
const { first: t7, second: t8 } = this.Fp4Square(c0c1, c1c2);
let t9 = t8.mulByNonresidue();
return new Fp12([
new Fp6([
t3.subtract(c0c0).multiply(2n).add(t3),
t5.subtract(c0c1).multiply(2n).add(t5),
t7.subtract(c0c2).multiply(2n).add(t7),
]),
new Fp6([
t9.add(c1c0).multiply(2n).add(t9),
t4.add(c1c1).multiply(2n).add(t4),
t6.add(c1c2).multiply(2n).add(t6),
]),
]);
return new Fp12(new Fp6(t3.subtract(c0c0).multiply(2n).add(t3), t5.subtract(c0c1).multiply(2n).add(t5), t7.subtract(c0c2).multiply(2n).add(t7)), new Fp6(t9.add(c1c0).multiply(2n).add(t9), t4.add(c1c1).multiply(2n).add(t4), t6.add(c1c2).multiply(2n).add(t6)));
}

@@ -597,4 +601,4 @@ cyclotomicExp(n) {

exports.Fp12 = Fp12;
Fp12.ZERO = new Fp12([Fp6.ZERO, Fp6.ZERO]);
Fp12.ONE = new Fp12([Fp6.ONE, Fp6.ZERO]);
Fp12.ZERO = new Fp12(Fp6.ZERO, Fp6.ZERO);
Fp12.ONE = new Fp12(Fp6.ONE, Fp6.ZERO);
class ProjectivePoint {

@@ -629,2 +633,5 @@ constructor(x, y, z, C) {

toString(isAffine = true) {
if (this.isZero()) {
return `Point<Zero>`;
}
if (!isAffine) {

@@ -640,2 +647,4 @@ return `Point<x=${this.x}, y=${this.y}, z=${this.z}>`;

toAffine(invZ = this.z.invert()) {
if (invZ.isZero())
throw new Error('Invalid inverted z');
return [this.x.multiply(invZ), this.y.multiply(invZ)];

@@ -779,3 +788,4 @@ }

}
let [p, f] = [this.getZero(), this.getZero()];
let p = this.getZero();
let f = this.getZero();
const windows = Math.ceil(this.maxBits() / W);

@@ -810,3 +820,3 @@ const windowSize = 2 ** (W - 1);

function sgn0(x) {
const [x0, x1] = x.values;
const { re: x0, im: x1 } = x.reim();
const sign_0 = x0 % 2n;

@@ -826,3 +836,3 @@ const zero_0 = x0 === 0n;

const positiveRootsOfUnity = FP2_ROOTS_OF_UNITY.slice(0, 4);
for (const root of positiveRootsOfUnity) {
positiveRootsOfUnity.forEach((root) => {
const candidate = root.multiply(gamma);

@@ -833,11 +843,11 @@ if (candidate.pow(2n).multiply(v).subtract(u).isZero() && !success) {

}
}
return [success, result];
});
return { success, sqrtCandidateOrGamma: result };
}
function map_to_curve_simple_swu_9mod16(t) {
const iso_3_a = new Fp2([0n, 240n]);
const iso_3_b = new Fp2([1012n, 1012n]);
const iso_3_z = new Fp2([-2n, -1n]);
const iso_3_a = new Fp2(new Fp(0n), new Fp(240n));
const iso_3_b = new Fp2(new Fp(1012n), new Fp(1012n));
const iso_3_z = new Fp2(new Fp(-2n), new Fp(-1n));
if (Array.isArray(t))
t = new Fp2(t);
t = Fp2.fromBigTuple(t);
const t2 = t.pow(2n);

@@ -855,3 +865,3 @@ const iso_3_z_t2 = iso_3_z.multiply(t2);

.add(iso_3_b.multiply(v));
const [success, sqrtCandidateOrGamma] = sqrt_div_fp2(u, v);
const { success, sqrtCandidateOrGamma } = sqrt_div_fp2(u, v);
let y;

@@ -863,3 +873,3 @@ if (success)

let success2 = false;
for (const eta of FP2_ETAs) {
FP2_ETAs.forEach((eta) => {
const etaSqrtCandidate = eta.multiply(sqrtCandidateX1);

@@ -871,3 +881,3 @@ const temp = etaSqrtCandidate.pow(2n).multiply(v).subtract(u);

}
}
});
if (!success && !success2)

@@ -885,3 +895,3 @@ throw new Error('Hash to Curve - Optimized SWU failure');

function isogenyMapG2(xyz) {
const [x, y, z] = xyz;
const x = xyz[0], y = xyz[1], z = xyz[2];
const zz = z.multiply(z);

@@ -909,4 +919,4 @@ const zzz = zz.multiply(z);

function calcPairingPrecomputes(x, y) {
const [Qx, Qy, Qz] = [x, y, Fp2.ONE];
let [Rx, Ry, Rz] = [Qx, Qy, Qz];
const Qx = x, Qy = y, Qz = Fp2.ONE;
let Rx = Qx, Ry = Qy, Rz = Qz;
let ell_coeff = [];

@@ -948,10 +958,12 @@ for (let i = BLS_X_LEN - 2; i >= 0; i--) {

function millerLoop(ell, g1) {
const Px = g1[0].value;
const Py = g1[1].value;
let f12 = Fp12.ONE;
const [x, y] = g1;
const [Px, Py] = [x, y];
for (let j = 0, i = BLS_X_LEN - 2; i >= 0; i--, j++) {
f12 = f12.multiplyBy014(ell[j][0], ell[j][1].multiply(Px.value), ell[j][2].multiply(Py.value));
const E = ell[j];
f12 = f12.multiplyBy014(E[0], E[1].multiply(Px), E[2].multiply(Py));
if (bitGet(exports.CURVE.x, i)) {
j += 1;
f12 = f12.multiplyBy014(ell[j][0], ell[j][1].multiply(Px.value), ell[j][2].multiply(Py.value));
const F = ell[j];
f12 = f12.multiplyBy014(F[0], F[1].multiply(Px), F[2].multiply(Py));
}

@@ -964,10 +976,9 @@ if (i !== 0)

exports.millerLoop = millerLoop;
const ut_root = new Fp6([Fp2.ZERO, Fp2.ONE, Fp2.ZERO]);
const wsq = new Fp12([ut_root, Fp6.ZERO]);
const wsq_inv = wsq.invert();
const wcu = new Fp12([Fp6.ZERO, ut_root]);
const wcu_inv = wcu.invert();
const ut_root = new Fp6(Fp2.ZERO, Fp2.ONE, Fp2.ZERO);
const wsq = new Fp12(ut_root, Fp6.ZERO);
const wcu = new Fp12(Fp6.ZERO, ut_root);
const [wsq_inv, wcu_inv] = genInvertBatch(Fp12, [wsq, wcu]);
function psi(x, y) {
const x2 = wsq_inv.multiplyByFp2(x).frobeniusMap(1).multiply(wsq).c[0].c[0];
const y2 = wcu_inv.multiplyByFp2(y).frobeniusMap(1).multiply(wcu).c[0].c[0];
const x2 = wsq_inv.multiplyByFp2(x).frobeniusMap(1).multiply(wsq).c0.c0;
const y2 = wcu_inv.multiplyByFp2(y).frobeniusMap(1).multiply(wcu).c0.c0;
return [x2, y2];

@@ -999,3 +1010,3 @@ }

[-rv1, -rv1],
].map((pair) => new Fp2(pair));
].map((pair) => Fp2.fromBigTuple(pair));
const FP2_ETAs = [

@@ -1006,3 +1017,3 @@ [ev1, ev2],

[-ev4, ev3],
].map((pair) => new Fp2(pair));
].map((pair) => Fp2.fromBigTuple(pair));
const FP6_FROBENIUS_COEFFICIENTS_1 = [

@@ -1027,3 +1038,3 @@ [0x1n, 0x0n],

],
].map((pair) => new Fp2(pair));
].map((pair) => Fp2.fromBigTuple(pair));
const FP6_FROBENIUS_COEFFICIENTS_2 = [

@@ -1051,3 +1062,3 @@ [0x1n, 0x0n],

],
].map((pair) => new Fp2(pair));
].map((pair) => Fp2.fromBigTuple(pair));
const FP12_FROBENIUS_COEFFICIENTS = [

@@ -1099,3 +1110,3 @@ [0x1n, 0x0n],

],
].map((pair) => new Fp2(pair));
].map(n => Fp2.fromBigTuple(n));
const xnum = [

@@ -1118,3 +1129,3 @@ [

],
].map((pair) => new Fp2(pair));
].map((pair) => Fp2.fromBigTuple(pair));
const xden = [

@@ -1131,3 +1142,3 @@ [

[0x0n, 0x0n],
].map((pair) => new Fp2(pair));
].map((pair) => Fp2.fromBigTuple(pair));
const ynum = [

@@ -1150,3 +1161,3 @@ [

],
].map((pair) => new Fp2(pair));
].map((pair) => Fp2.fromBigTuple(pair));
const yden = [

@@ -1166,3 +1177,3 @@ [

[0x1n, 0x0n],
].map((pair) => new Fp2(pair));
].map((pair) => Fp2.fromBigTuple(pair));
const ISOGENY_COEFFICIENTS = [xnum, xden, ynum, yden];
{
"name": "@noble/bls12-381",
"version": "1.2.0",
"version": "1.3.0",
"description": "Fastest JS implementation of BLS12-381. Auditable, secure, 0-dependency aggregated signatures & pairings",

@@ -14,3 +14,3 @@ "files": [

"build": "tsc -d && tsc -p tsconfig.esm.json",
"build-release": "rollup -c rollup.config.js",
"build:release": "rollup -c rollup.config.js",
"bench": "node test/benchmark.js",

@@ -30,13 +30,13 @@ "lint": "prettier --print-width 100 --single-quote --check index.ts"

"devDependencies": {
"@rollup/plugin-commonjs": "^19",
"@rollup/plugin-node-resolve": "^13",
"@types/jest": "^27",
"@types/node": "^16.9.2",
"fast-check": "^2.17",
"jest": "^27.0.5",
"micro-bmark": "^0.1.3",
"prettier": "^2.3.2",
"rollup": "^2.52.2",
"ts-jest": "^27",
"typescript": "4.5.4"
"@rollup/plugin-commonjs": "22.0.0",
"@rollup/plugin-node-resolve": "13.3.0",
"@types/jest": "28.1.1",
"@types/node": "18.0.0",
"fast-check": "3.0.0",
"jest": "28.1.0",
"micro-bmark": "0.1.3",
"prettier": "2.6.2",
"rollup": "2.75.5",
"ts-jest": "28.0.4",
"typescript": "4.7.3"
},

@@ -61,12 +61,18 @@ "keywords": [

"./math": {
"types": "./lib/math.d.ts",
"import": "./lib/esm/math.js",
"default": "./lib/math.js"
},
"./math.d.ts": "./lib/math.d.ts",
".": {
"types": "./lib/index.d.ts",
"import": "./lib/esm/index.js",
"default": "./lib/index.js"
},
"./index.d.ts": "./lib/index.d.ts"
}
}
},
"funding": [
{
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
]
}

@@ -12,6 +12,5 @@ # noble-bls12-381 ![Node CI](https://github.com/paulmillr/noble-secp256k1/workflows/Node%20CI/badge.svg) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)

Compatible with Algorand, Chia, Dfinity, Ethereum, FIL, Zcash. Matches specs [pairing-curves-10](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-10), [bls-sigs-04](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04), [hash-to-curve-12](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-12).
Compatible with Algorand, Chia, Dfinity, Ethereum, FIL, Zcash. Matches specs [pairing-curves-10](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-10), [bls-sigs-04](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04), [hash-to-curve-12](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-12). To learn more about internals, navigate to
[utilities](#utilities) section.
To learn more about internals, check out [BLS12-381 for the rest of us](https://hackmd.io/@benjaminion/bls12-381) & [key concepts of pairings](https://medium.com/@alonmuroch_65570/bls-signatures-part-2-key-concepts-of-pairings-27a8a9533d0c). To try it live, see [the online demo](https://paulmillr.com/ecc) & [threshold sigs demo](https://genthresh.com).
### This library belongs to *noble* crypto

@@ -41,33 +40,26 @@

const bls = require('@noble/bls12-381');
// if you're using single file, use global variable nobleBls12381
// If you're using single file, use global variable instead: `window.nobleBls12381`
// You can use Uint8Array, or hex string for readability
const privateKey = '67d53f170b908cabb9eb326c3c337762d59289a8fec79f7bc9254b584b73265c';
const privateKeys = [
'18f020b98eb798752a50ed0563b079c125b0db5dd0b1060d1c1b47d4a193e1e4',
'ed69a8c50cf8c9836be3b67c7eeff416612d45ba39a5c099d48fa668bf558c9c',
'16ae669f3be7a2121e17d0c68c05a8f3d6bef21ec0f2315f1d7aec12484e4cf5'
];
const message = '64726e3da8';
const messages = ['d2', '0d98', '05caf3'];
(async () => {
// keys, messages & other inputs can be Uint8Arrays or hex strings
const privateKey = '67d53f170b908cabb9eb326c3c337762d59289a8fec79f7bc9254b584b73265c';
const message = '64726e3da8';
const publicKey = bls.getPublicKey(privateKey);
const publicKeys = privateKeys.map(bls.getPublicKey);
const signature = await bls.sign(message, privateKey);
const isCorrect = await bls.verify(signature, message, publicKey);
console.log('key', publicKey);
console.log('signature', signature);
console.log('is correct:', isCorrect);
const isValid = await bls.verify(signature, message, publicKey);
console.log({ publicKey, signature, isValid });
// Sign 1 msg with 3 keys
const privateKeys = [
'18f020b98eb798752a50ed0563b079c125b0db5dd0b1060d1c1b47d4a193e1e4',
'ed69a8c50cf8c9836be3b67c7eeff416612d45ba39a5c099d48fa668bf558c9c',
'16ae669f3be7a2121e17d0c68c05a8f3d6bef21ec0f2315f1d7aec12484e4cf5'
];
const messages = ['d2', '0d98', '05caf3'];
const publicKeys = privateKeys.map(bls.getPublicKey);
const signatures2 = await Promise.all(privateKeys.map(p => bls.sign(message, p)));
const aggPubKey2 = bls.aggregatePublicKeys(publicKeys);
const aggSignature2 = bls.aggregateSignatures(signatures2);
const isCorrect2 = await bls.verify(aggSignature2, message, aggPubKey2);
console.log();
console.log('signatures are', signatures2);
console.log('merged to one signature', aggSignature2);
console.log('is correct:', isCorrect2);
const isValid2 = await bls.verify(aggSignature2, message, aggPubKey2);
console.log({ signatures2, aggSignature2, isValid2 });

@@ -77,8 +69,4 @@ // Sign 3 msgs with 3 keys

const aggSignature3 = bls.aggregateSignatures(signatures3);
const isCorrect3 = await bls.verifyBatch(aggSignature3, messages, publicKeys);
console.log();
console.log('keys', publicKeys);
console.log('signatures', signatures3);
console.log('merged to one signature', aggSignature3);
console.log('is correct:', isCorrect3);
const isValid3 = await bls.verifyBatch(aggSignature3, messages, publicKeys);
console.log({ publicKeys, signatures3, aggSignature3, isValid3 });
})();

@@ -91,21 +79,5 @@ ```

- `deno run --import-map=imports.json app.ts`
- app.ts: `import * as bls from "https://deno.land/x/bls12_381/mod.ts";`
- imports.json: `{"imports": {"crypto": "https://deno.land/std@0.119.0/node/crypto.ts"}}`
- `app.ts`
```typescript
import * as bls from "https://deno.land/x/bls12_381/mod.ts";
const publicKey = bls.getPublicKey(bls.utils.randomPrivateKey());
console.log(publicKey);
```
- `imports.json`
```json
{
"imports": {
"crypto": "https://deno.land/std@0.119.0/node/crypto.ts",
"./math": "./math.ts"
}
}
```
## API

@@ -120,2 +92,3 @@

- [`pairing(G1Point, G2Point)`](#pairingg1point-g2point)
- [Utilities](#utilities)

@@ -131,3 +104,3 @@ ##### `getPublicKey(privateKey)`

**Note:** if you need spec-based `KeyGen`, use [paulmillr/bls12-381-keygen](https://github.com/paulmillr/bls12-381-keygen). It should work properly with ETH2 and FIL keys.
**Note:** if you need EIP2333-compliant `KeyGen` (eth2/fil), use [paulmillr/bls12-381-keygen](https://github.com/paulmillr/bls12-381-keygen).

@@ -143,3 +116,3 @@ ##### `sign(message, privateKey)`

Check out **Internals** section on instructions about domain separation tag (DST).
Check out [Utilities](#utilities) section on instructions about domain separation tag (DST).

@@ -201,43 +174,14 @@ ##### `verify(signature, message, publicKey)`

##### Helpers
### Utilities
Use `utils.bytesToHex(str)` to convert byte output to hexademical string.
Resources that help to understand bls12-381:
```typescript
// characteristic; z + (z⁴ - z² + 1)(z - 1)²/3
bls.CURVE.P // 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
- [BLS12-381 for the rest of us](https://hackmd.io/@benjaminion/bls12-381)
- [Key concepts of pairings](https://medium.com/@alonmuroch_65570/bls-signatures-part-2-key-concepts-of-pairings-27a8a9533d0c)
- Pairing over bls12-381: [part 1](https://research.nccgroup.com/2020/07/06/pairing-over-bls12-381-part-1-fields/),
[part 2](https://research.nccgroup.com/2020/07/13/pairing-over-bls12-381-part-2-curves/),
[part 3](https://research.nccgroup.com/2020/08/13/pairing-over-bls12-381-part-3-pairing/)
- [Estimating the bit security of pairing-friendly curves](https://research.nccgroup.com/2022/02/03/estimating-the-bit-security-of-pairing-friendly-curves/)
- Check out [the online demo](https://paulmillr.com/ecc) and [threshold sigs demo](https://genthresh.com)
// curve order; z⁴ − z² + 1
bls.CURVE.r // 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001
// cofactor; (z - 1)²/3
bls.curve.h // 0x396c8c005555e1568c00aaab0000aaab
// G1 base point coordinates (x, y)
bls.CURVE.Gx
// x = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507
bls.CURVE.Gy
// y = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569
// G2 base point coordinates (x₁, x₂+i), (y₁, y₂+i)
bls.CURVE.G2x
// x =
// 3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758,
// 352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160
bls.CURVE.G2y
// y =
// 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582,
// 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905
// Classes
bls.Fp // field over Fp
bls.Fp2 // field over Fp₂
bls.Fp12 // finite extension field over irreducible polynominal
bls.PointG1 // projective point (xyz) at G1
bls.PointG2 // projective point (xyz) at G2
```
## Internals
The library uses G1 for public keys and G2 for signatures. Adding support for G1 signatures is planned.

@@ -269,2 +213,58 @@

```typescript
// Exports `CURVE`, `utils`, `PointG1`, `PointG2`, `Fp`, `Fp2`, `Fp12` helpers
const utils: {
hashToField(msg: Uint8Array, count: number, options = {}): Promise<bigint[][]>;
bytesToHex: (bytes: Uint8Array): string;
randomBytes: (bytesLength?: number) => Uint8Array;
randomPrivateKey: () => Uint8Array;
sha256: (message: Uint8Array) => Promise<Uint8Array>;
mod: (a: bigint, b = CURVE.P): bigint;
getDSTLabel(): string;
setDSTLabel(newLabel: string): void;
};
// characteristic; z + (z⁴ - z² + 1)(z - 1)²/3
CURVE.P // 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
CURVE.r // curve order; z⁴ − z² + 1, 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001
curve.h // cofactor; (z - 1)²/3, 0x396c8c005555e1568c00aaab0000aaab
CURVE.Gx, CURVE.Gy // G1 base point coordinates (x, y)
CURVE.G2x, CURVE.G2y // G2 base point coordinates (x₁, x₂+i), (y₁, y₂+i)
// Classes
bls.Fp // field over Fp
bls.Fp2 // field over Fp₂
bls.Fp12 // finite extension field over irreducible polynominal
// projective point (xyz) at G1
class PointG1 extends ProjectivePoint<Fp> {
constructor(x: Fp, y: Fp, z?: Fp);
static BASE: PointG1;
static ZERO: PointG1;
static fromHex(bytes: Bytes): PointG1;
static fromPrivateKey(privateKey: PrivateKey): PointG1;
toRawBytes(isCompressed?: boolean): Uint8Array;
toHex(isCompressed?: boolean): string;
assertValidity(): this;
millerLoop(P: PointG2): Fp12;
clearCofactor(): PointG1;
}
// projective point (xyz) at G2
class PointG2 extends ProjectivePoint<Fp2> {
constructor(x: Fp2, y: Fp2, z?: Fp2);
static BASE: PointG2;
static ZERO: PointG2;
static hashToCurve(msg: Bytes): Promise<PointG2>;
static fromSignature(hex: Bytes): PointG2;
static fromHex(bytes: Bytes): PointG2;
static fromPrivateKey(privateKey: PrivateKey): PointG2;
toSignature(): Uint8Array;
toRawBytes(isCompressed?: boolean): Uint8Array;
toHex(isCompressed?: boolean): string;
assertValidity(): this;
clearCofactor(): PointG2;
}
```
## Speed

@@ -281,20 +281,20 @@

```
getPublicKey x 737 ops/sec @ 1ms/op
sign x 37 ops/sec @ 26ms/op
verify x 28 ops/sec @ 34ms/op
pairing x 70 ops/sec @ 14ms/op
aggregatePublicKeys/8 x 102 ops/sec @ 9ms/op
aggregateSignatures/8 x 39 ops/sec @ 25ms/op
getPublicKey x 742 ops/sec @ 1ms/op
sign x 39 ops/sec @ 25ms/op
verify x 31 ops/sec @ 32ms/op
pairing x 77 ops/sec @ 12ms/op
aggregatePublicKeys/8 x 105 ops/sec @ 9ms/op
aggregateSignatures/8 x 41 ops/sec @ 24ms/op
with compression / decompression disabled:
sign/nc x 52 ops/sec @ 18ms/op
verify/nc x 47 ops/sec @ 21ms/op
aggregatePublicKeys/32 x 1,014 ops/sec @ 986μs/op
aggregatePublicKeys/128 x 662 ops/sec @ 1ms/op
aggregatePublicKeys/512 x 278 ops/sec @ 3ms/op
aggregatePublicKeys/2048 x 84 ops/sec @ 11ms/op
aggregateSignatures/32 x 444 ops/sec @ 2ms/op
aggregateSignatures/128 x 236 ops/sec @ 4ms/op
aggregateSignatures/512 x 81 ops/sec @ 12ms/op
aggregateSignatures/2048 x 22 ops/sec @ 44ms/op
sign/nc x 55 ops/sec @ 17ms/op
verify/nc x 52 ops/sec @ 19ms/op
aggregatePublicKeys/32 x 1,045 ops/sec @ 956μs/op
aggregatePublicKeys/128 x 681 ops/sec @ 1ms/op
aggregatePublicKeys/512 x 285 ops/sec @ 3ms/op
aggregatePublicKeys/2048 x 85 ops/sec @ 11ms/op
aggregateSignatures/32 x 471 ops/sec @ 2ms/op
aggregateSignatures/128 x 247 ops/sec @ 4ms/op
aggregateSignatures/512 x 85 ops/sec @ 11ms/op
aggregateSignatures/2048 x 23 ops/sec @ 41ms/op
```

@@ -314,3 +314,3 @@

We however consider infrastructure attacks like rogue NPM modules very important; that's why it's crucial to minimize the amount of 3rd-party dependencies & native bindings. If your app uses 500 dependencies, any dep could get hacked and you'll be downloading rootkits with every `npm install`. Our goal is to minimize this attack vector.
We however consider infrastructure attacks like rogue NPM modules very important; that's why it's crucial to minimize the amount of 3rd-party dependencies & native bindings. If your app uses 500 dependencies, any dep could get hacked and you'll be downloading malware with every `npm install`. Our goal is to minimize this attack vector.

@@ -328,2 +328,2 @@ ## Contributing

MIT (c) Paul Miller [(https://paulmillr.com)](https://paulmillr.com), see LICENSE file.
MIT (c) 2019 Paul Miller [(https://paulmillr.com)](https://paulmillr.com), see LICENSE file.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc