@noble/bls12-381
Advanced tools
Comparing version 1.3.0 to 1.4.0
/*! noble-bls12-381 - MIT License (c) 2019 Paul Miller (paulmillr.com) */ | ||
import nodeCrypto from 'crypto'; | ||
import { Fp, Fr, Fp2, Fp12, CURVE, ProjectivePoint, map_to_curve_simple_swu_9mod16, isogenyMapG2, millerLoop, psi, psi2, calcPairingPrecomputes, mod } from './math.js'; | ||
import { hexToBytes, bytesToHex, bytesToNumberBE, concatBytes, Fp, Fr, Fp2, Fp12, CURVE, ProjectivePoint, map_to_curve_simple_swu_9mod16, map_to_curve_simple_swu_3mod4, isogenyMapG1, isogenyMapG2, millerLoop, psi, psi2, calcPairingPrecomputes, mod } from './math.js'; | ||
export { Fp, Fr, Fp2, Fp12, CURVE }; | ||
@@ -9,3 +9,19 @@ const POW_2_381 = 2n ** 381n; | ||
const PUBLIC_KEY_LENGTH = 48; | ||
const SHA256_DIGEST_SIZE = 32; | ||
function wrapHash(outputLen, h) { | ||
let tmp = h; | ||
tmp.outputLen = outputLen; | ||
return tmp; | ||
} | ||
const sha256 = wrapHash(32, async (message) => { | ||
if (crypto.web) { | ||
const buffer = await crypto.web.subtle.digest('SHA-256', message.buffer); | ||
return new Uint8Array(buffer); | ||
} | ||
else if (crypto.node) { | ||
return Uint8Array.from(crypto.node.createHash('sha256').update(message).digest()); | ||
} | ||
else { | ||
throw new Error("The environment doesn't have sha256 function"); | ||
} | ||
}); | ||
const htfDefaults = { | ||
@@ -17,2 +33,3 @@ DST: 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_', | ||
expand: true, | ||
hash: sha256, | ||
}; | ||
@@ -28,2 +45,3 @@ function isWithinCurveOrder(num) { | ||
hashToField: hash_to_field, | ||
expandMessageXMD: expand_message_xmd, | ||
hashToPrivateKey: (hash) => { | ||
@@ -38,3 +56,5 @@ hash = ensureBytes(hash); | ||
}, | ||
stringToBytes, | ||
bytesToHex, | ||
hexToBytes, | ||
randomBytes: (bytesLength = 32) => { | ||
@@ -55,14 +75,3 @@ if (crypto.web) { | ||
}, | ||
sha256: async (message) => { | ||
if (crypto.web) { | ||
const buffer = await crypto.web.subtle.digest('SHA-256', message.buffer); | ||
return new Uint8Array(buffer); | ||
} | ||
else if (crypto.node) { | ||
return Uint8Array.from(crypto.node.createHash('sha256').update(message).digest()); | ||
} | ||
else { | ||
throw new Error("The environment doesn't have sha256 function"); | ||
} | ||
}, | ||
sha256, | ||
mod, | ||
@@ -79,34 +88,2 @@ getDSTLabel() { | ||
}; | ||
function bytesToNumberBE(uint8a) { | ||
if (!(uint8a instanceof Uint8Array)) | ||
throw new Error('Expected Uint8Array'); | ||
return BigInt('0x' + bytesToHex(Uint8Array.from(uint8a))); | ||
} | ||
const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0')); | ||
function bytesToHex(uint8a) { | ||
let hex = ''; | ||
for (let i = 0; i < uint8a.length; i++) { | ||
hex += hexes[uint8a[i]]; | ||
} | ||
return hex; | ||
} | ||
function hexToBytes(hex) { | ||
if (typeof hex !== 'string') { | ||
throw new TypeError('hexToBytes: expected string, got ' + typeof hex); | ||
} | ||
if (hex.length % 2) | ||
throw new Error('hexToBytes: received invalid unpadded hex'); | ||
const array = new Uint8Array(hex.length / 2); | ||
for (let i = 0; i < array.length; i++) { | ||
const j = i * 2; | ||
const hexByte = hex.slice(j, j + 2); | ||
if (hexByte.length !== 2) | ||
throw new Error('Invalid byte sequence'); | ||
const byte = Number.parseInt(hexByte, 16); | ||
if (Number.isNaN(byte) || byte < 0) | ||
throw new Error('Invalid byte sequence'); | ||
array[i] = byte; | ||
} | ||
return array; | ||
} | ||
function numberTo32BytesBE(num) { | ||
@@ -127,14 +104,2 @@ const length = 32; | ||
} | ||
function concatBytes(...arrays) { | ||
if (arrays.length === 1) | ||
return arrays[0]; | ||
const length = arrays.reduce((a, arr) => a + arr.length, 0); | ||
const result = new Uint8Array(length); | ||
for (let i = 0, pad = 0; i < arrays.length; i++) { | ||
const arr = arrays[i]; | ||
result.set(arr, pad); | ||
pad += arr.length; | ||
} | ||
return result; | ||
} | ||
function stringToBytes(str) { | ||
@@ -173,5 +138,6 @@ const bytes = new Uint8Array(str.length); | ||
} | ||
async function expand_message_xmd(msg, DST, lenInBytes) { | ||
const H = utils.sha256; | ||
const b_in_bytes = SHA256_DIGEST_SIZE; | ||
async function expand_message_xmd(msg, DST, lenInBytes, H = utils.sha256) { | ||
if (DST.length > 255) | ||
DST = await H(concatBytes(stringToBytes('H2C-OVERSIZE-DST-'), DST)); | ||
const b_in_bytes = H.outputLen; | ||
const r_in_bytes = b_in_bytes * 2; | ||
@@ -202,3 +168,3 @@ const ell = Math.ceil(lenInBytes / b_in_bytes); | ||
if (htfOptions.expand) { | ||
pseudo_random_bytes = await expand_message_xmd(msg, DST, len_in_bytes); | ||
pseudo_random_bytes = await expand_message_xmd(msg, DST, len_in_bytes, htfOptions.hash); | ||
} | ||
@@ -210,3 +176,3 @@ const u = new Array(count); | ||
const elm_offset = L * (j + i * htfOptions.m); | ||
const tv = pseudo_random_bytes.slice(elm_offset, elm_offset + L); | ||
const tv = pseudo_random_bytes.subarray(elm_offset, elm_offset + L); | ||
e[j] = mod(os2ip(tv), htfOptions.p); | ||
@@ -279,2 +245,21 @@ } | ||
} | ||
static async hashToCurve(msg, options) { | ||
msg = ensureBytes(msg); | ||
const [[u0], [u1]] = await hash_to_field(msg, 2, { m: 1, ...options }); | ||
const [x0, y0] = map_to_curve_simple_swu_3mod4(new Fp(u0)); | ||
const [x1, y1] = map_to_curve_simple_swu_3mod4(new Fp(u1)); | ||
const [x2, y2] = new PointG1(x0, y0).add(new PointG1(x1, y1)).toAffine(); | ||
const [x3, y3] = isogenyMapG1(x2, y2); | ||
return new PointG1(x3, y3).clearCofactor(); | ||
} | ||
static async encodeToCurve(msg, options) { | ||
msg = ensureBytes(msg); | ||
const u = await hash_to_field(msg, 1, { | ||
m: 1, | ||
...options, | ||
}); | ||
const [x0, y0] = map_to_curve_simple_swu_3mod4(new Fp(u[0][0])); | ||
const [x1, y1] = isogenyMapG1(x0, y0); | ||
return new PointG1(x1, y1).clearCofactor(); | ||
} | ||
static fromPrivateKey(privateKey) { | ||
@@ -367,11 +352,18 @@ return this.BASE.multiplyPrecomputed(normalizePrivKey(privateKey)); | ||
} | ||
static async hashToCurve(msg) { | ||
static async hashToCurve(msg, options) { | ||
msg = ensureBytes(msg); | ||
const u = await hash_to_field(msg, 2); | ||
const Q0 = new PointG2(...isogenyMapG2(map_to_curve_simple_swu_9mod16(u[0]))); | ||
const Q1 = new PointG2(...isogenyMapG2(map_to_curve_simple_swu_9mod16(u[1]))); | ||
const R = Q0.add(Q1); | ||
const P = R.clearCofactor(); | ||
return P; | ||
const u = await hash_to_field(msg, 2, options); | ||
const [x0, y0] = map_to_curve_simple_swu_9mod16(Fp2.fromBigTuple(u[0])); | ||
const [x1, y1] = map_to_curve_simple_swu_9mod16(Fp2.fromBigTuple(u[1])); | ||
const [x2, y2] = new PointG2(x0, y0).add(new PointG2(x1, y1)).toAffine(); | ||
const [x3, y3] = isogenyMapG2(x2, y2); | ||
return new PointG2(x3, y3).clearCofactor(); | ||
} | ||
static async encodeToCurve(msg, options) { | ||
msg = ensureBytes(msg); | ||
const u = await hash_to_field(msg, 1, options); | ||
const [x0, y0] = map_to_curve_simple_swu_9mod16(Fp2.fromBigTuple(u[0])); | ||
const [x1, y1] = isogenyMapG2(x0, y0); | ||
return new PointG2(x1, y1).clearCofactor(); | ||
} | ||
static fromSignature(hex) { | ||
@@ -378,0 +370,0 @@ hex = ensureBytes(hex); |
@@ -0,1 +1,2 @@ | ||
var _a, _b; | ||
export const CURVE = { | ||
@@ -90,2 +91,57 @@ P: 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn, | ||
} | ||
export function hexToBytes(hex) { | ||
if (typeof hex !== 'string') { | ||
throw new TypeError('hexToBytes: expected string, got ' + typeof hex); | ||
} | ||
if (hex.length % 2) | ||
throw new Error('hexToBytes: received invalid unpadded hex'); | ||
const array = new Uint8Array(hex.length / 2); | ||
for (let i = 0; i < array.length; i++) { | ||
const j = i * 2; | ||
const hexByte = hex.slice(j, j + 2); | ||
if (hexByte.length !== 2) | ||
throw new Error('Invalid byte sequence'); | ||
const byte = Number.parseInt(hexByte, 16); | ||
if (Number.isNaN(byte) || byte < 0) | ||
throw new Error('Invalid byte sequence'); | ||
array[i] = byte; | ||
} | ||
return array; | ||
} | ||
function numberToHex(num, byteLength) { | ||
if (!byteLength) | ||
throw new Error('byteLength target must be specified'); | ||
const hex = num.toString(16); | ||
const p1 = hex.length & 1 ? `0${hex}` : hex; | ||
return p1.padStart(byteLength * 2, '0'); | ||
} | ||
export function numberToBytesBE(num, byteLength) { | ||
const res = hexToBytes(numberToHex(num, byteLength)); | ||
if (res.length !== byteLength) | ||
throw new Error('numberToBytesBE: wrong byteLength'); | ||
return res; | ||
} | ||
const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0')); | ||
export function bytesToHex(uint8a) { | ||
let hex = ''; | ||
for (let i = 0; i < uint8a.length; i++) { | ||
hex += hexes[uint8a[i]]; | ||
} | ||
return hex; | ||
} | ||
export function bytesToNumberBE(bytes) { | ||
return BigInt('0x' + bytesToHex(bytes)); | ||
} | ||
export function concatBytes(...arrays) { | ||
if (arrays.length === 1) | ||
return arrays[0]; | ||
const length = arrays.reduce((a, arr) => a + arr.length, 0); | ||
const result = new Uint8Array(length); | ||
for (let i = 0, pad = 0; i < arrays.length; i++) { | ||
const arr = arrays[i]; | ||
result.set(arr, pad); | ||
pad += arr.length; | ||
} | ||
return result; | ||
} | ||
export class Fp { | ||
@@ -139,5 +195,15 @@ constructor(value) { | ||
} | ||
static fromBytes(b) { | ||
if (b.length !== Fp.BYTES_LEN) | ||
throw new Error(`fromBytes wrong length=${b.length}`); | ||
return new Fp(bytesToNumberBE(b)); | ||
} | ||
toBytes() { | ||
return numberToBytesBE(this.value, Fp.BYTES_LEN); | ||
} | ||
} | ||
_a = Fp; | ||
Fp.ORDER = CURVE.P; | ||
Fp.MAX_BITS = bitLen(CURVE.P); | ||
Fp.BYTES_LEN = Math.ceil(_a.MAX_BITS / 8); | ||
Fp.ZERO = new Fp(0n); | ||
@@ -253,3 +319,3 @@ Fp.ONE = new Fp(1n); | ||
static fromBigTuple(tuple) { | ||
const fps = tuple.map(n => new Fp(n)); | ||
const fps = tuple.map((n) => new Fp(n)); | ||
return new Fp2(...fps); | ||
@@ -352,5 +418,15 @@ } | ||
} | ||
static fromBytes(b) { | ||
if (b.length !== Fp2.BYTES_LEN) | ||
throw new Error(`fromBytes wrong length=${b.length}`); | ||
return new Fp2(Fp.fromBytes(b.subarray(0, Fp.BYTES_LEN)), Fp.fromBytes(b.subarray(Fp.BYTES_LEN))); | ||
} | ||
toBytes() { | ||
return concatBytes(this.c0.toBytes(), this.c1.toBytes()); | ||
} | ||
} | ||
_b = Fp2; | ||
Fp2.ORDER = CURVE.P2; | ||
Fp2.MAX_BITS = bitLen(CURVE.P2); | ||
Fp2.BYTES_LEN = Math.ceil(_b.MAX_BITS / 8); | ||
Fp2.ZERO = new Fp2(Fp.ZERO, Fp.ZERO); | ||
@@ -367,3 +443,3 @@ Fp2.ONE = new Fp2(Fp.ONE, Fp.ZERO); | ||
throw new Error('Invalid Fp6 usage'); | ||
const c = [t.slice(0, 2), t.slice(2, 4), t.slice(4, 6)].map(t => Fp2.fromBigTuple(t)); | ||
const c = [t.slice(0, 2), t.slice(2, 4), t.slice(4, 6)].map((t) => Fp2.fromBigTuple(t)); | ||
return new Fp6(...c); | ||
@@ -455,5 +531,14 @@ } | ||
} | ||
static fromBytes(b) { | ||
if (b.length !== Fp6.BYTES_LEN) | ||
throw new Error(`fromBytes wrong length=${b.length}`); | ||
return new Fp6(Fp2.fromBytes(b.subarray(0, Fp2.BYTES_LEN)), Fp2.fromBytes(b.subarray(Fp2.BYTES_LEN, 2 * Fp2.BYTES_LEN)), Fp2.fromBytes(b.subarray(2 * Fp2.BYTES_LEN))); | ||
} | ||
toBytes() { | ||
return concatBytes(this.c0.toBytes(), this.c1.toBytes(), this.c2.toBytes()); | ||
} | ||
} | ||
Fp6.ZERO = new Fp6(Fp2.ZERO, Fp2.ZERO, Fp2.ZERO); | ||
Fp6.ONE = new Fp6(Fp2.ONE, Fp2.ZERO, Fp2.ZERO); | ||
Fp6.BYTES_LEN = 3 * Fp2.BYTES_LEN; | ||
export class Fp12 { | ||
@@ -584,5 +669,14 @@ constructor(c0, c1) { | ||
} | ||
static fromBytes(b) { | ||
if (b.length !== Fp12.BYTES_LEN) | ||
throw new Error(`fromBytes wrong length=${b.length}`); | ||
return new Fp12(Fp6.fromBytes(b.subarray(0, Fp6.BYTES_LEN)), Fp6.fromBytes(b.subarray(Fp6.BYTES_LEN))); | ||
} | ||
toBytes() { | ||
return concatBytes(this.c0.toBytes(), this.c1.toBytes()); | ||
} | ||
} | ||
Fp12.ZERO = new Fp12(Fp6.ZERO, Fp6.ZERO); | ||
Fp12.ONE = new Fp12(Fp6.ONE, Fp6.ZERO); | ||
Fp12.BYTES_LEN = 2 * Fp6.BYTES_LEN; | ||
export class ProjectivePoint { | ||
@@ -799,3 +893,3 @@ constructor(x, y, z, C) { | ||
} | ||
function sgn0(x) { | ||
function sgn0_fp2(x) { | ||
const { re: x0, im: x1 } = x.reim(); | ||
@@ -807,2 +901,5 @@ const sign_0 = x0 % 2n; | ||
} | ||
function sgn0_m_eq_1(x) { | ||
return Boolean(x.value % 2n); | ||
} | ||
const P_MINUS_9_DIV_16 = (CURVE.P ** 2n - 9n) / 16n; | ||
@@ -864,29 +961,51 @@ function sqrt_div_fp2(u, v) { | ||
y = y; | ||
if (sgn0(t) !== sgn0(y)) | ||
if (sgn0_fp2(t) !== sgn0_fp2(y)) | ||
y = y.negate(); | ||
y = y.multiply(denominator); | ||
return [numerator, y, denominator]; | ||
return [numerator.div(denominator), y]; | ||
} | ||
export function isogenyMapG2(xyz) { | ||
const x = xyz[0], y = xyz[1], z = xyz[2]; | ||
const zz = z.multiply(z); | ||
const zzz = zz.multiply(z); | ||
const zPowers = [z, zz, zzz]; | ||
const mapped = [Fp2.ZERO, Fp2.ZERO, Fp2.ZERO, Fp2.ZERO]; | ||
for (let i = 0; i < ISOGENY_COEFFICIENTS.length; i++) { | ||
const k_i = ISOGENY_COEFFICIENTS[i]; | ||
mapped[i] = k_i.slice(-1)[0]; | ||
const arr = k_i.slice(0, -1).reverse(); | ||
for (let j = 0; j < arr.length; j++) { | ||
const k_i_j = arr[j]; | ||
mapped[i] = mapped[i].multiply(x).add(zPowers[j].multiply(k_i_j)); | ||
} | ||
export function map_to_curve_simple_swu_3mod4(u) { | ||
const A = new Fp(0x144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1dn); | ||
const B = new Fp(0x12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0n); | ||
const Z = new Fp(11n); | ||
const c1 = (Fp.ORDER - 3n) / 4n; | ||
const c2 = Z.negate().pow(3n).sqrt(); | ||
const tv1 = u.square(); | ||
const tv3 = Z.multiply(tv1); | ||
let xDen = tv3.square().add(tv3); | ||
const xNum1 = xDen.add(Fp.ONE).multiply(B); | ||
const xNum2 = tv3.multiply(xNum1); | ||
xDen = A.negate().multiply(xDen); | ||
if (xDen.isZero()) | ||
xDen = A.multiply(Z); | ||
let tv2 = xDen.square(); | ||
const gxd = tv2.multiply(xDen); | ||
tv2 = A.multiply(tv2); | ||
let gx1 = xNum1.square().add(tv2).multiply(xNum1); | ||
tv2 = B.multiply(gxd); | ||
gx1 = gx1.add(tv2); | ||
tv2 = gx1.multiply(gxd); | ||
const tv4 = gxd.square().multiply(tv2); | ||
const y1 = tv4.pow(c1).multiply(tv2); | ||
const y2 = y1.multiply(c2).multiply(tv1).multiply(u); | ||
let xNum, yPos; | ||
if (y1.square().multiply(gxd).equals(gx1)) { | ||
xNum = xNum1; | ||
yPos = y1; | ||
} | ||
mapped[2] = mapped[2].multiply(y); | ||
mapped[3] = mapped[3].multiply(z); | ||
const z2 = mapped[1].multiply(mapped[3]); | ||
const x2 = mapped[0].multiply(mapped[3]); | ||
const y2 = mapped[1].multiply(mapped[2]); | ||
return [x2, y2, z2]; | ||
else { | ||
xNum = xNum2; | ||
yPos = y2; | ||
} | ||
const yNeg = yPos.negate(); | ||
const y = sgn0_m_eq_1(u) == sgn0_m_eq_1(yPos) ? yPos : yNeg; | ||
return [xNum.div(xDen), y]; | ||
} | ||
function isogenyMap(COEFF, x, y) { | ||
const [xNum, xDen, yNum, yDen] = COEFF.map((val) => val.reduce((acc, i) => acc.multiply(x).add(i))); | ||
x = xNum.div(xDen); | ||
y = y.multiply(yNum.div(yDen)); | ||
return [x, y]; | ||
} | ||
export const isogenyMapG2 = (x, y) => isogenyMap(ISOGENY_COEFFICIENTS_G2, x, y); | ||
export const isogenyMapG1 = (x, y) => isogenyMap(ISOGENY_COEFFICIENTS_G1, x, y); | ||
export function calcPairingPrecomputes(x, y) { | ||
@@ -1073,11 +1192,7 @@ const Qx = x, Qy = y, Qz = Fp2.ONE; | ||
], | ||
].map(n => Fp2.fromBigTuple(n)); | ||
].map((n) => Fp2.fromBigTuple(n)); | ||
const xnum = [ | ||
[ | ||
0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6n, | ||
0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6n, | ||
], | ||
[ | ||
0x171d6541fa38ccfaed6dea691f5fb614cb14b4e7f4e810aa22d6108f142b85757098e38d0f671c7188e2aaaaaaaa5ed1n, | ||
0x0n, | ||
0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71an, | ||
], | ||
@@ -1089,26 +1204,26 @@ [ | ||
[ | ||
0x171d6541fa38ccfaed6dea691f5fb614cb14b4e7f4e810aa22d6108f142b85757098e38d0f671c7188e2aaaaaaaa5ed1n, | ||
0x0n, | ||
0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71an, | ||
], | ||
[ | ||
0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6n, | ||
0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6n, | ||
], | ||
].map((pair) => Fp2.fromBigTuple(pair)); | ||
const xden = [ | ||
[0x0n, 0x0n], | ||
[0x1n, 0x0n], | ||
[ | ||
0xcn, | ||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa9fn, | ||
], | ||
[ | ||
0x0n, | ||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa63n, | ||
], | ||
[ | ||
0xcn, | ||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa9fn, | ||
], | ||
[0x1n, 0x0n], | ||
[0x0n, 0x0n], | ||
].map((pair) => Fp2.fromBigTuple(pair)); | ||
const ynum = [ | ||
[ | ||
0x1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706n, | ||
0x1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706n, | ||
], | ||
[ | ||
0x124c9ad43b6cf79bfbf7043de3811ad0761b0f37a1e26286b0e977c69aa274524e79097a56dc4bd9e1b371c71c718b10n, | ||
0x0n, | ||
0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97ben, | ||
], | ||
@@ -1120,10 +1235,15 @@ [ | ||
[ | ||
0x124c9ad43b6cf79bfbf7043de3811ad0761b0f37a1e26286b0e977c69aa274524e79097a56dc4bd9e1b371c71c718b10n, | ||
0x0n, | ||
0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97ben, | ||
], | ||
[ | ||
0x1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706n, | ||
0x1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706n, | ||
], | ||
].map((pair) => Fp2.fromBigTuple(pair)); | ||
const yden = [ | ||
[0x1n, 0x0n], | ||
[ | ||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fbn, | ||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fbn, | ||
0x12n, | ||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa99n, | ||
], | ||
@@ -1135,7 +1255,71 @@ [ | ||
[ | ||
0x12n, | ||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa99n, | ||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fbn, | ||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fbn, | ||
], | ||
[0x1n, 0x0n], | ||
].map((pair) => Fp2.fromBigTuple(pair)); | ||
const ISOGENY_COEFFICIENTS = [xnum, xden, ynum, yden]; | ||
const ISOGENY_COEFFICIENTS_G2 = [xnum, xden, ynum, yden]; | ||
const ISOGENY_COEFFICIENTS_G1 = [ | ||
[ | ||
new Fp(0x06e08c248e260e70bd1e962381edee3d31d79d7e22c837bc23c0bf1bc24c6b68c24b1b80b64d391fa9c8ba2e8ba2d229n), | ||
new Fp(0x10321da079ce07e272d8ec09d2565b0dfa7dccdde6787f96d50af36003b14866f69b771f8c285decca67df3f1605fb7bn), | ||
new Fp(0x169b1f8e1bcfa7c42e0c37515d138f22dd2ecb803a0c5c99676314baf4bb1b7fa3190b2edc0327797f241067be390c9en), | ||
new Fp(0x080d3cf1f9a78fc47b90b33563be990dc43b756ce79f5574a2c596c928c5d1de4fa295f296b74e956d71986a8497e317n), | ||
new Fp(0x17b81e7701abdbe2e8743884d1117e53356de5ab275b4db1a682c62ef0f2753339b7c8f8c8f475af9ccb5618e3f0c88en), | ||
new Fp(0x0d6ed6553fe44d296a3726c38ae652bfb11586264f0f8ce19008e218f9c86b2a8da25128c1052ecaddd7f225a139ed84n), | ||
new Fp(0x1630c3250d7313ff01d1201bf7a74ab5db3cb17dd952799b9ed3ab9097e68f90a0870d2dcae73d19cd13c1c66f652983n), | ||
new Fp(0x0e99726a3199f4436642b4b3e4118e5499db995a1257fb3f086eeb65982fac18985a286f301e77c451154ce9ac8895d9n), | ||
new Fp(0x1778e7166fcc6db74e0609d307e55412d7f5e4656a8dbf25f1b33289f1b330835336e25ce3107193c5b388641d9b6861n), | ||
new Fp(0x0d54005db97678ec1d1048c5d10a9a1bce032473295983e56878e501ec68e25c958c3e3d2a09729fe0179f9dac9edcb0n), | ||
new Fp(0x17294ed3e943ab2f0588bab22147a81c7c17e75b2f6a8417f565e33c70d1e86b4838f2a6f318c356e834eef1b3cb83bbn), | ||
new Fp(0x11a05f2b1e833340b809101dd99815856b303e88a2d7005ff2627b56cdb4e2c85610c2d5f2e62d6eaeac1662734649b7n), | ||
], | ||
[ | ||
new Fp(0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001n), | ||
new Fp(0x095fc13ab9e92ad4476d6e3eb3a56680f682b4ee96f7d03776df533978f31c1593174e4b4b7865002d6384d168ecdd0an), | ||
new Fp(0x0a10ecf6ada54f825e920b3dafc7a3cce07f8d1d7161366b74100da67f39883503826692abba43704776ec3a79a1d641n), | ||
new Fp(0x14a7ac2a9d64a8b230b3f5b074cf01996e7f63c21bca68a81996e1cdf9822c580fa5b9489d11e2d311f7d99bbdcc5a5en), | ||
new Fp(0x0772caacf16936190f3e0c63e0596721570f5799af53a1894e2e073062aede9cea73b3538f0de06cec2574496ee84a3an), | ||
new Fp(0x0e7355f8e4e667b955390f7f0506c6e9395735e9ce9cad4d0a43bcef24b8982f7400d24bc4228f11c02df9a29f6304a5n), | ||
new Fp(0x13a8e162022914a80a6f1d5f43e7a07dffdfc759a12062bb8d6b44e833b306da9bd29ba81f35781d539d395b3532a21en), | ||
new Fp(0x03425581a58ae2fec83aafef7c40eb545b08243f16b1655154cca8abc28d6fd04976d5243eecf5c4130de8938dc62cd8n), | ||
new Fp(0x0b2962fe57a3225e8137e629bff2991f6f89416f5a718cd1fca64e00b11aceacd6a3d0967c94fedcfcc239ba5cb83e19n), | ||
new Fp(0x12561a5deb559c4348b4711298e536367041e8ca0cf0800c0126c2588c48bf5713daa8846cb026e9e5c8276ec82b3bffn), | ||
new Fp(0x08ca8d548cff19ae18b2e62f4bd3fa6f01d5ef4ba35b48ba9c9588617fc8ac62b558d681be343df8993cf9fa40d21b1cn), | ||
], | ||
[ | ||
new Fp(0x15e6be4e990f03ce4ea50b3b42df2eb5cb181d8f84965a3957add4fa95af01b2b665027efec01c7704b456be69c8b604n), | ||
new Fp(0x05c129645e44cf1102a159f748c4a3fc5e673d81d7e86568d9ab0f5d396a7ce46ba1049b6579afb7866b1e715475224bn), | ||
new Fp(0x0245a394ad1eca9b72fc00ae7be315dc757b3b080d4c158013e6632d3c40659cc6cf90ad1c232a6442d9d3f5db980133n), | ||
new Fp(0x0b182cac101b9399d155096004f53f447aa7b12a3426b08ec02710e807b4633f06c851c1919211f20d4c04f00b971ef8n), | ||
new Fp(0x18b46a908f36f6deb918c143fed2edcc523559b8aaf0c2462e6bfe7f911f643249d9cdf41b44d606ce07c8a4d0074d8en), | ||
new Fp(0x19713e47937cd1be0dfd0b8f1d43fb93cd2fcbcb6caf493fd1183e416389e61031bf3a5cce3fbafce813711ad011c132n), | ||
new Fp(0x0e1bba7a1186bdb5223abde7ada14a23c42a0ca7915af6fe06985e7ed1e4d43b9b3f7055dd4eba6f2bafaaebca731c30n), | ||
new Fp(0x09fc4018bd96684be88c9e221e4da1bb8f3abd16679dc26c1e8b6e6a1f20cabe69d65201c78607a360370e577bdba587n), | ||
new Fp(0x0987c8d5333ab86fde9926bd2ca6c674170a05bfe3bdd81ffd038da6c26c842642f64550fedfe935a15e4ca31870fb29n), | ||
new Fp(0x04ab0b9bcfac1bbcb2c977d027796b3ce75bb8ca2be184cb5231413c4d634f3747a87ac2460f415ec961f8855fe9d6f2n), | ||
new Fp(0x16603fca40634b6a2211e11db8f0a6a074a7d0d4afadb7bd76505c3d3ad5544e203f6326c95a807299b23ab13633a5f0n), | ||
new Fp(0x08cc03fdefe0ff135caf4fe2a21529c4195536fbe3ce50b879833fd221351adc2ee7f8dc099040a841b6daecf2e8fedbn), | ||
new Fp(0x01f86376e8981c217898751ad8746757d42aa7b90eeb791c09e4a3ec03251cf9de405aba9ec61deca6355c77b0e5f4cbn), | ||
new Fp(0x00cc786baa966e66f4a384c86a3b49942552e2d658a31ce2c344be4b91400da7d26d521628b00523b8dfe240c72de1f6n), | ||
new Fp(0x134996a104ee5811d51036d776fb46831223e96c254f383d0f906343eb67ad34d6c56711962fa8bfe097e75a2e41c696n), | ||
new Fp(0x090d97c81ba24ee0259d1f094980dcfa11ad138e48a869522b52af6c956543d3cd0c7aee9b3ba3c2be9845719707bb33n), | ||
], | ||
[ | ||
new Fp(0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001n), | ||
new Fp(0x0e0fa1d816ddc03e6b24255e0d7819c171c40f65e273b853324efcd6356caa205ca2f570f13497804415473a1d634b8fn), | ||
new Fp(0x02660400eb2e4f3b628bdd0d53cd76f2bf565b94e72927c1cb748df27942480e420517bd8714cc80d1fadc1326ed06f7n), | ||
new Fp(0x0ad6b9514c767fe3c3613144b45f1496543346d98adf02267d5ceef9a00d9b8693000763e3b90ac11e99b138573345ccn), | ||
new Fp(0x0accbb67481d033ff5852c1e48c50c477f94ff8aefce42d28c0f9a88cea7913516f968986f7ebbea9684b529e2561092n), | ||
new Fp(0x04d2f259eea405bd48f010a01ad2911d9c6dd039bb61a6290e591b36e636a5c871a5c29f4f83060400f8b49cba8f6aa8n), | ||
new Fp(0x167a55cda70a6e1cea820597d94a84903216f763e13d87bb5308592e7ea7d4fbc7385ea3d529b35e346ef48bb8913f55n), | ||
new Fp(0x1866c8ed336c61231a1be54fd1d74cc4f9fb0ce4c6af5920abc5750c4bf39b4852cfe2f7bb9248836b233d9d55535d4an), | ||
new Fp(0x16a3ef08be3ea7ea03bcddfabba6ff6ee5a4375efa1f4fd7feb34fd206357132b920f5b00801dee460ee415a15812ed9n), | ||
new Fp(0x166007c08a99db2fc3ba8734ace9824b5eecfdfa8d0cf8ef5dd365bc400a0051d5fa9c01a58b1fb93d1a1399126a775cn), | ||
new Fp(0x08d9e5297186db2d9fb266eaac783182b70152c65550d881c5ecd87b6f0f5a6449f38db9dfa9cce202c6477faaf9b7acn), | ||
new Fp(0x0be0e079545f43e4b00cc912f8228ddcc6d19c9f0f69bbb0542eda0fc9dec916a20b15dc0fd2ededda39142311a5001dn), | ||
new Fp(0x16b7d288798e5395f20d23bf89edb4d1d115c5dbddbcd30e123da489e726af41727364f2c28297ada8d26d98445f5416n), | ||
new Fp(0x058df3306640da276faaae7d6e8eb15778c4855551ae7f310c35a5dd279cd2eca6757cd636f96f891e2538b53dbf67f2n), | ||
new Fp(0x1962d75c2381201e1a0cbd6c43c348b885c84ff731c4d59ca4a10356f453e01f78a4260763529e3532f6102c2e49a03dn), | ||
new Fp(0x16112c4c3a9c98b252181140fad0eae9601a6de578980be6eec3232b5be72e7a07f3688ef60c206d01479253b03663c1n), | ||
], | ||
]; |
/*! noble-bls12-381 - MIT License (c) 2019 Paul Miller (paulmillr.com) */ | ||
import { Fp, Fr, Fp2, Fp12, CURVE, ProjectivePoint, mod } from './math.js'; | ||
import { hexToBytes, bytesToHex, Fp, Fr, Fp2, Fp12, CURVE, ProjectivePoint, mod } from './math.js'; | ||
export { Fp, Fr, Fp2, Fp12, CURVE }; | ||
declare type Hex = Uint8Array | string; | ||
declare type PrivateKey = Hex | bigint | number; | ||
declare type BasicHash = (msg: Uint8Array) => Uint8Array | Promise<Uint8Array>; | ||
declare type Hash = BasicHash & { | ||
outputLen: number; | ||
}; | ||
declare const htfDefaults: { | ||
DST: string; | ||
p: bigint; | ||
m: number; | ||
k: number; | ||
expand: boolean; | ||
hash: Hash; | ||
}; | ||
export declare const utils: { | ||
hashToField: typeof hash_to_field; | ||
expandMessageXMD: typeof expand_message_xmd; | ||
hashToPrivateKey: (hash: Hex) => Uint8Array; | ||
stringToBytes: typeof stringToBytes; | ||
bytesToHex: typeof bytesToHex; | ||
hexToBytes: typeof hexToBytes; | ||
randomBytes: (bytesLength?: number) => Uint8Array; | ||
randomPrivateKey: () => Uint8Array; | ||
sha256: (message: Uint8Array) => Promise<Uint8Array>; | ||
sha256: Hash; | ||
mod: typeof mod; | ||
@@ -17,4 +32,5 @@ getDSTLabel(): string; | ||
}; | ||
declare function bytesToHex(uint8a: Uint8Array): string; | ||
declare function hash_to_field(msg: Uint8Array, count: number, options?: {}): Promise<bigint[][]>; | ||
declare function stringToBytes(str: string): Uint8Array; | ||
declare function expand_message_xmd(msg: Uint8Array, DST: Uint8Array, lenInBytes: number, H?: Hash): Promise<Uint8Array>; | ||
declare function hash_to_field(msg: Uint8Array, count: number, options?: Partial<typeof htfDefaults>): Promise<bigint[][]>; | ||
export declare class PointG1 extends ProjectivePoint<Fp> { | ||
@@ -25,2 +41,4 @@ static BASE: PointG1; | ||
static fromHex(bytes: Hex): PointG1; | ||
static hashToCurve(msg: Hex, options?: Partial<typeof htfDefaults>): Promise<PointG1>; | ||
static encodeToCurve(msg: Hex, options?: Partial<typeof htfDefaults>): Promise<PointG1>; | ||
static fromPrivateKey(privateKey: PrivateKey): PointG1; | ||
@@ -44,3 +62,4 @@ toRawBytes(isCompressed?: boolean): Uint8Array; | ||
constructor(x: Fp2, y: Fp2, z?: Fp2); | ||
static hashToCurve(msg: Hex): Promise<PointG2>; | ||
static hashToCurve(msg: Hex, options?: Partial<typeof htfDefaults>): Promise<PointG2>; | ||
static encodeToCurve(msg: Hex, options?: Partial<typeof htfDefaults>): Promise<PointG2>; | ||
static fromSignature(hex: Hex): PointG2; | ||
@@ -47,0 +66,0 @@ static fromHex(bytes: Hex): PointG2; |
180
lib/index.js
@@ -19,3 +19,19 @@ "use strict"; | ||
const PUBLIC_KEY_LENGTH = 48; | ||
const SHA256_DIGEST_SIZE = 32; | ||
function wrapHash(outputLen, h) { | ||
let tmp = h; | ||
tmp.outputLen = outputLen; | ||
return tmp; | ||
} | ||
const sha256 = wrapHash(32, async (message) => { | ||
if (crypto.web) { | ||
const buffer = await crypto.web.subtle.digest('SHA-256', message.buffer); | ||
return new Uint8Array(buffer); | ||
} | ||
else if (crypto.node) { | ||
return Uint8Array.from(crypto.node.createHash('sha256').update(message).digest()); | ||
} | ||
else { | ||
throw new Error("The environment doesn't have sha256 function"); | ||
} | ||
}); | ||
const htfDefaults = { | ||
@@ -27,2 +43,3 @@ DST: 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_', | ||
expand: true, | ||
hash: sha256, | ||
}; | ||
@@ -38,2 +55,3 @@ function isWithinCurveOrder(num) { | ||
hashToField: hash_to_field, | ||
expandMessageXMD: expand_message_xmd, | ||
hashToPrivateKey: (hash) => { | ||
@@ -43,3 +61,3 @@ hash = ensureBytes(hash); | ||
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); | ||
const num = (0, math_js_1.mod)((0, math_js_1.bytesToNumberBE)(hash), math_js_1.CURVE.r); | ||
if (num === 0n || num === 1n) | ||
@@ -49,3 +67,5 @@ throw new Error('Invalid private key'); | ||
}, | ||
bytesToHex, | ||
stringToBytes, | ||
bytesToHex: math_js_1.bytesToHex, | ||
hexToBytes: math_js_1.hexToBytes, | ||
randomBytes: (bytesLength = 32) => { | ||
@@ -66,14 +86,3 @@ if (crypto.web) { | ||
}, | ||
sha256: async (message) => { | ||
if (crypto.web) { | ||
const buffer = await crypto.web.subtle.digest('SHA-256', message.buffer); | ||
return new Uint8Array(buffer); | ||
} | ||
else if (crypto.node) { | ||
return Uint8Array.from(crypto.node.createHash('sha256').update(message).digest()); | ||
} | ||
else { | ||
throw new Error("The environment doesn't have sha256 function"); | ||
} | ||
}, | ||
sha256, | ||
mod: math_js_1.mod, | ||
@@ -90,38 +99,6 @@ getDSTLabel() { | ||
}; | ||
function bytesToNumberBE(uint8a) { | ||
if (!(uint8a instanceof Uint8Array)) | ||
throw new Error('Expected Uint8Array'); | ||
return BigInt('0x' + bytesToHex(Uint8Array.from(uint8a))); | ||
} | ||
const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0')); | ||
function bytesToHex(uint8a) { | ||
let hex = ''; | ||
for (let i = 0; i < uint8a.length; i++) { | ||
hex += hexes[uint8a[i]]; | ||
} | ||
return hex; | ||
} | ||
function hexToBytes(hex) { | ||
if (typeof hex !== 'string') { | ||
throw new TypeError('hexToBytes: expected string, got ' + typeof hex); | ||
} | ||
if (hex.length % 2) | ||
throw new Error('hexToBytes: received invalid unpadded hex'); | ||
const array = new Uint8Array(hex.length / 2); | ||
for (let i = 0; i < array.length; i++) { | ||
const j = i * 2; | ||
const hexByte = hex.slice(j, j + 2); | ||
if (hexByte.length !== 2) | ||
throw new Error('Invalid byte sequence'); | ||
const byte = Number.parseInt(hexByte, 16); | ||
if (Number.isNaN(byte) || byte < 0) | ||
throw new Error('Invalid byte sequence'); | ||
array[i] = byte; | ||
} | ||
return array; | ||
} | ||
function numberTo32BytesBE(num) { | ||
const length = 32; | ||
const hex = num.toString(16).padStart(length * 2, '0'); | ||
return hexToBytes(hex); | ||
return (0, math_js_1.hexToBytes)(hex); | ||
} | ||
@@ -136,16 +113,4 @@ function toPaddedHex(num, padding) { | ||
function ensureBytes(hex) { | ||
return hex instanceof Uint8Array ? Uint8Array.from(hex) : hexToBytes(hex); | ||
return hex instanceof Uint8Array ? Uint8Array.from(hex) : (0, math_js_1.hexToBytes)(hex); | ||
} | ||
function concatBytes(...arrays) { | ||
if (arrays.length === 1) | ||
return arrays[0]; | ||
const length = arrays.reduce((a, arr) => a + arr.length, 0); | ||
const result = new Uint8Array(length); | ||
for (let i = 0, pad = 0; i < arrays.length; i++) { | ||
const arr = arrays[i]; | ||
result.set(arr, pad); | ||
pad += arr.length; | ||
} | ||
return result; | ||
} | ||
function stringToBytes(str) { | ||
@@ -184,5 +149,6 @@ const bytes = new Uint8Array(str.length); | ||
} | ||
async function expand_message_xmd(msg, DST, lenInBytes) { | ||
const H = exports.utils.sha256; | ||
const b_in_bytes = SHA256_DIGEST_SIZE; | ||
async function expand_message_xmd(msg, DST, lenInBytes, H = exports.utils.sha256) { | ||
if (DST.length > 255) | ||
DST = await H((0, math_js_1.concatBytes)(stringToBytes('H2C-OVERSIZE-DST-'), DST)); | ||
const b_in_bytes = H.outputLen; | ||
const r_in_bytes = b_in_bytes * 2; | ||
@@ -192,13 +158,13 @@ const ell = Math.ceil(lenInBytes / b_in_bytes); | ||
throw new Error('Invalid xmd length'); | ||
const DST_prime = concatBytes(DST, i2osp(DST.length, 1)); | ||
const DST_prime = (0, math_js_1.concatBytes)(DST, i2osp(DST.length, 1)); | ||
const Z_pad = i2osp(0, r_in_bytes); | ||
const l_i_b_str = i2osp(lenInBytes, 2); | ||
const b = new Array(ell); | ||
const b_0 = await H(concatBytes(Z_pad, msg, l_i_b_str, i2osp(0, 1), DST_prime)); | ||
b[0] = await H(concatBytes(b_0, i2osp(1, 1), DST_prime)); | ||
const b_0 = await H((0, math_js_1.concatBytes)(Z_pad, msg, l_i_b_str, i2osp(0, 1), DST_prime)); | ||
b[0] = await H((0, math_js_1.concatBytes)(b_0, i2osp(1, 1), DST_prime)); | ||
for (let i = 1; i <= ell; i++) { | ||
const args = [strxor(b_0, b[i - 1]), i2osp(i + 1, 1), DST_prime]; | ||
b[i] = await H(concatBytes(...args)); | ||
b[i] = await H((0, math_js_1.concatBytes)(...args)); | ||
} | ||
const pseudo_random_bytes = concatBytes(...b); | ||
const pseudo_random_bytes = (0, math_js_1.concatBytes)(...b); | ||
return pseudo_random_bytes.slice(0, lenInBytes); | ||
@@ -214,3 +180,3 @@ } | ||
if (htfOptions.expand) { | ||
pseudo_random_bytes = await expand_message_xmd(msg, DST, len_in_bytes); | ||
pseudo_random_bytes = await expand_message_xmd(msg, DST, len_in_bytes, htfOptions.hash); | ||
} | ||
@@ -222,3 +188,3 @@ const u = new Array(count); | ||
const elm_offset = L * (j + i * htfOptions.m); | ||
const tv = pseudo_random_bytes.slice(elm_offset, elm_offset + L); | ||
const tv = pseudo_random_bytes.subarray(elm_offset, elm_offset + L); | ||
e[j] = (0, math_js_1.mod)(os2ip(tv), htfOptions.p); | ||
@@ -233,3 +199,3 @@ } | ||
if (key instanceof Uint8Array && key.length === 32) | ||
int = bytesToNumberBE(key); | ||
int = (0, math_js_1.bytesToNumberBE)(key); | ||
else if (typeof key === 'string' && key.length === 64) | ||
@@ -264,3 +230,3 @@ int = BigInt(`0x${key}`); | ||
const { P } = math_js_1.CURVE; | ||
const compressedValue = bytesToNumberBE(bytes); | ||
const compressedValue = (0, math_js_1.bytesToNumberBE)(bytes); | ||
const bflag = (0, math_js_1.mod)(compressedValue, POW_2_383) / POW_2_382; | ||
@@ -283,4 +249,4 @@ if (bflag === 1n) { | ||
return PointG1.ZERO; | ||
const x = bytesToNumberBE(bytes.slice(0, PUBLIC_KEY_LENGTH)); | ||
const y = bytesToNumberBE(bytes.slice(PUBLIC_KEY_LENGTH)); | ||
const x = (0, math_js_1.bytesToNumberBE)(bytes.slice(0, PUBLIC_KEY_LENGTH)); | ||
const y = (0, math_js_1.bytesToNumberBE)(bytes.slice(PUBLIC_KEY_LENGTH)); | ||
point = new PointG1(new math_js_1.Fp(x), new math_js_1.Fp(y)); | ||
@@ -294,2 +260,21 @@ } | ||
} | ||
static async hashToCurve(msg, options) { | ||
msg = ensureBytes(msg); | ||
const [[u0], [u1]] = await hash_to_field(msg, 2, { m: 1, ...options }); | ||
const [x0, y0] = (0, math_js_1.map_to_curve_simple_swu_3mod4)(new math_js_1.Fp(u0)); | ||
const [x1, y1] = (0, math_js_1.map_to_curve_simple_swu_3mod4)(new math_js_1.Fp(u1)); | ||
const [x2, y2] = new PointG1(x0, y0).add(new PointG1(x1, y1)).toAffine(); | ||
const [x3, y3] = (0, math_js_1.isogenyMapG1)(x2, y2); | ||
return new PointG1(x3, y3).clearCofactor(); | ||
} | ||
static async encodeToCurve(msg, options) { | ||
msg = ensureBytes(msg); | ||
const u = await hash_to_field(msg, 1, { | ||
m: 1, | ||
...options, | ||
}); | ||
const [x0, y0] = (0, math_js_1.map_to_curve_simple_swu_3mod4)(new math_js_1.Fp(u[0][0])); | ||
const [x1, y1] = (0, math_js_1.isogenyMapG1)(x0, y0); | ||
return new PointG1(x1, y1).clearCofactor(); | ||
} | ||
static fromPrivateKey(privateKey) { | ||
@@ -299,3 +284,3 @@ return this.BASE.multiplyPrecomputed(normalizePrivKey(privateKey)); | ||
toRawBytes(isCompressed = false) { | ||
return hexToBytes(this.toHex(isCompressed)); | ||
return (0, math_js_1.hexToBytes)(this.toHex(isCompressed)); | ||
} | ||
@@ -384,11 +369,18 @@ toHex(isCompressed = false) { | ||
} | ||
static async hashToCurve(msg) { | ||
static async hashToCurve(msg, options) { | ||
msg = ensureBytes(msg); | ||
const u = await hash_to_field(msg, 2); | ||
const Q0 = new PointG2(...(0, math_js_1.isogenyMapG2)((0, math_js_1.map_to_curve_simple_swu_9mod16)(u[0]))); | ||
const Q1 = new PointG2(...(0, math_js_1.isogenyMapG2)((0, math_js_1.map_to_curve_simple_swu_9mod16)(u[1]))); | ||
const R = Q0.add(Q1); | ||
const P = R.clearCofactor(); | ||
return P; | ||
const u = await hash_to_field(msg, 2, options); | ||
const [x0, y0] = (0, math_js_1.map_to_curve_simple_swu_9mod16)(math_js_1.Fp2.fromBigTuple(u[0])); | ||
const [x1, y1] = (0, math_js_1.map_to_curve_simple_swu_9mod16)(math_js_1.Fp2.fromBigTuple(u[1])); | ||
const [x2, y2] = new PointG2(x0, y0).add(new PointG2(x1, y1)).toAffine(); | ||
const [x3, y3] = (0, math_js_1.isogenyMapG2)(x2, y2); | ||
return new PointG2(x3, y3).clearCofactor(); | ||
} | ||
static async encodeToCurve(msg, options) { | ||
msg = ensureBytes(msg); | ||
const u = await hash_to_field(msg, 1, options); | ||
const [x0, y0] = (0, math_js_1.map_to_curve_simple_swu_9mod16)(math_js_1.Fp2.fromBigTuple(u[0])); | ||
const [x1, y1] = (0, math_js_1.isogenyMapG2)(x0, y0); | ||
return new PointG2(x1, y1).clearCofactor(); | ||
} | ||
static fromSignature(hex) { | ||
@@ -400,4 +392,4 @@ hex = ensureBytes(hex); | ||
throw new Error('Invalid compressed signature length, must be 96 or 192'); | ||
const z1 = bytesToNumberBE(hex.slice(0, half)); | ||
const z2 = bytesToNumberBE(hex.slice(half)); | ||
const z1 = (0, math_js_1.bytesToNumberBE)(hex.slice(0, half)); | ||
const z2 = (0, math_js_1.bytesToNumberBE)(hex.slice(half)); | ||
const bflag1 = (0, math_js_1.mod)(z1, POW_2_383) / POW_2_382; | ||
@@ -443,4 +435,4 @@ if (bflag1 === 1n) | ||
} | ||
const x_1 = bytesToNumberBE(bytes.slice(0, PUBLIC_KEY_LENGTH)); | ||
const x_0 = bytesToNumberBE(bytes.slice(PUBLIC_KEY_LENGTH)); | ||
const x_1 = (0, math_js_1.bytesToNumberBE)(bytes.slice(0, PUBLIC_KEY_LENGTH)); | ||
const x_0 = (0, math_js_1.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)); | ||
@@ -459,6 +451,6 @@ const right = x.pow(3n).add(b); | ||
} | ||
const x1 = bytesToNumberBE(bytes.slice(0, PUBLIC_KEY_LENGTH)); | ||
const x0 = bytesToNumberBE(bytes.slice(PUBLIC_KEY_LENGTH, 2 * PUBLIC_KEY_LENGTH)); | ||
const y1 = bytesToNumberBE(bytes.slice(2 * PUBLIC_KEY_LENGTH, 3 * PUBLIC_KEY_LENGTH)); | ||
const y0 = bytesToNumberBE(bytes.slice(3 * PUBLIC_KEY_LENGTH)); | ||
const x1 = (0, math_js_1.bytesToNumberBE)(bytes.slice(0, PUBLIC_KEY_LENGTH)); | ||
const x0 = (0, math_js_1.bytesToNumberBE)(bytes.slice(PUBLIC_KEY_LENGTH, 2 * PUBLIC_KEY_LENGTH)); | ||
const y1 = (0, math_js_1.bytesToNumberBE)(bytes.slice(2 * PUBLIC_KEY_LENGTH, 3 * PUBLIC_KEY_LENGTH)); | ||
const y0 = (0, math_js_1.bytesToNumberBE)(bytes.slice(3 * PUBLIC_KEY_LENGTH)); | ||
point = new PointG2(math_js_1.Fp2.fromBigTuple([x0, x1]), math_js_1.Fp2.fromBigTuple([y0, y1])); | ||
@@ -479,3 +471,3 @@ } | ||
const h = toPaddedHex(sum, PUBLIC_KEY_LENGTH) + toPaddedHex(0n, PUBLIC_KEY_LENGTH); | ||
return hexToBytes(h); | ||
return (0, math_js_1.hexToBytes)(h); | ||
} | ||
@@ -487,6 +479,6 @@ const [{ re: x0, im: x1 }, { re: y0, im: y1 }] = this.toAffine().map((a) => a.reim()); | ||
const z2 = x0; | ||
return hexToBytes(toPaddedHex(z1, PUBLIC_KEY_LENGTH) + toPaddedHex(z2, PUBLIC_KEY_LENGTH)); | ||
return (0, math_js_1.hexToBytes)(toPaddedHex(z1, PUBLIC_KEY_LENGTH) + toPaddedHex(z2, PUBLIC_KEY_LENGTH)); | ||
} | ||
toRawBytes(isCompressed = false) { | ||
return hexToBytes(this.toHex(isCompressed)); | ||
return (0, math_js_1.hexToBytes)(this.toHex(isCompressed)); | ||
} | ||
@@ -493,0 +485,0 @@ toHex(isCompressed = false) { |
@@ -50,5 +50,11 @@ export declare const CURVE: { | ||
export declare function powMod(num: bigint, power: bigint, modulo: bigint): bigint; | ||
export declare function hexToBytes(hex: string): Uint8Array; | ||
export declare function numberToBytesBE(num: bigint, byteLength: number): Uint8Array; | ||
export declare function bytesToHex(uint8a: Uint8Array): string; | ||
export declare function bytesToNumberBE(bytes: Uint8Array): bigint; | ||
export declare function concatBytes(...arrays: Uint8Array[]): Uint8Array; | ||
export declare class Fp implements Field<Fp> { | ||
static readonly ORDER: bigint; | ||
static readonly MAX_BITS: number; | ||
static readonly BYTES_LEN: number; | ||
static readonly ZERO: Fp; | ||
@@ -70,2 +76,4 @@ static readonly ONE: Fp; | ||
toString(): string; | ||
static fromBytes(b: Uint8Array): Fp; | ||
toBytes(): Uint8Array; | ||
} | ||
@@ -98,2 +106,3 @@ export declare class Fr implements Field<Fr> { | ||
static readonly MAX_BITS: number; | ||
static readonly BYTES_LEN: number; | ||
static readonly ZERO: Fp2; | ||
@@ -123,2 +132,4 @@ static readonly ONE: Fp2; | ||
multiplyByB(): Fp2; | ||
static fromBytes(b: Uint8Array): Fp2; | ||
toBytes(): Uint8Array; | ||
} | ||
@@ -131,2 +142,3 @@ export declare class Fp6 implements Field<Fp6> { | ||
static readonly ONE: Fp6; | ||
static readonly BYTES_LEN: number; | ||
static fromBigSix(t: BigintSix): Fp6; | ||
@@ -152,2 +164,4 @@ constructor(c0: Fp2, c1: Fp2, c2: Fp2); | ||
frobeniusMap(power: number): Fp6; | ||
static fromBytes(b: Uint8Array): Fp6; | ||
toBytes(): Uint8Array; | ||
} | ||
@@ -159,2 +173,3 @@ export declare class Fp12 implements Field<Fp12> { | ||
static readonly ONE: Fp12; | ||
static readonly BYTES_LEN: number; | ||
static fromBigTwelve(t: BigintTwelve): Fp12; | ||
@@ -183,2 +198,4 @@ constructor(c0: Fp6, c1: Fp6); | ||
finalExponentiate(): Fp12; | ||
static fromBytes(b: Uint8Array): Fp12; | ||
toBytes(): Uint8Array; | ||
} | ||
@@ -220,4 +237,6 @@ declare type Constructor<T extends Field<T>> = { | ||
} | ||
export declare function map_to_curve_simple_swu_9mod16(t: bigint[] | Fp2): [Fp2, Fp2, Fp2]; | ||
export declare function isogenyMapG2(xyz: [Fp2, Fp2, Fp2]): [Fp2, Fp2, Fp2]; | ||
export declare function map_to_curve_simple_swu_9mod16(t: bigint[] | Fp2): [Fp2, Fp2]; | ||
export declare function map_to_curve_simple_swu_3mod4(u: Fp): [Fp, Fp]; | ||
export declare const isogenyMapG2: (x: Fp2, y: Fp2) => [Fp2, Fp2]; | ||
export declare const isogenyMapG1: (x: Fp, y: Fp) => [Fp, Fp]; | ||
export declare function calcPairingPrecomputes(x: Fp2, y: Fp2): [Fp2, Fp2, Fp2][]; | ||
@@ -224,0 +243,0 @@ export declare function millerLoop(ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]): Fp12; |
295
lib/math.js
"use strict"; | ||
var _a, _b; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.psi2 = exports.psi = exports.millerLoop = exports.calcPairingPrecomputes = exports.isogenyMapG2 = exports.map_to_curve_simple_swu_9mod16 = exports.ProjectivePoint = exports.Fp12 = exports.Fp6 = exports.Fp2 = exports.Fr = exports.Fp = exports.powMod = exports.mod = exports.CURVE = void 0; | ||
exports.psi2 = exports.psi = exports.millerLoop = exports.calcPairingPrecomputes = exports.isogenyMapG1 = exports.isogenyMapG2 = exports.map_to_curve_simple_swu_3mod4 = exports.map_to_curve_simple_swu_9mod16 = exports.ProjectivePoint = exports.Fp12 = exports.Fp6 = exports.Fp2 = exports.Fr = exports.Fp = exports.concatBytes = exports.bytesToNumberBE = exports.bytesToHex = exports.numberToBytesBE = exports.hexToBytes = exports.powMod = exports.mod = exports.CURVE = void 0; | ||
exports.CURVE = { | ||
@@ -95,2 +96,62 @@ P: 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn, | ||
} | ||
function hexToBytes(hex) { | ||
if (typeof hex !== 'string') { | ||
throw new TypeError('hexToBytes: expected string, got ' + typeof hex); | ||
} | ||
if (hex.length % 2) | ||
throw new Error('hexToBytes: received invalid unpadded hex'); | ||
const array = new Uint8Array(hex.length / 2); | ||
for (let i = 0; i < array.length; i++) { | ||
const j = i * 2; | ||
const hexByte = hex.slice(j, j + 2); | ||
if (hexByte.length !== 2) | ||
throw new Error('Invalid byte sequence'); | ||
const byte = Number.parseInt(hexByte, 16); | ||
if (Number.isNaN(byte) || byte < 0) | ||
throw new Error('Invalid byte sequence'); | ||
array[i] = byte; | ||
} | ||
return array; | ||
} | ||
exports.hexToBytes = hexToBytes; | ||
function numberToHex(num, byteLength) { | ||
if (!byteLength) | ||
throw new Error('byteLength target must be specified'); | ||
const hex = num.toString(16); | ||
const p1 = hex.length & 1 ? `0${hex}` : hex; | ||
return p1.padStart(byteLength * 2, '0'); | ||
} | ||
function numberToBytesBE(num, byteLength) { | ||
const res = hexToBytes(numberToHex(num, byteLength)); | ||
if (res.length !== byteLength) | ||
throw new Error('numberToBytesBE: wrong byteLength'); | ||
return res; | ||
} | ||
exports.numberToBytesBE = numberToBytesBE; | ||
const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0')); | ||
function bytesToHex(uint8a) { | ||
let hex = ''; | ||
for (let i = 0; i < uint8a.length; i++) { | ||
hex += hexes[uint8a[i]]; | ||
} | ||
return hex; | ||
} | ||
exports.bytesToHex = bytesToHex; | ||
function bytesToNumberBE(bytes) { | ||
return BigInt('0x' + bytesToHex(bytes)); | ||
} | ||
exports.bytesToNumberBE = bytesToNumberBE; | ||
function concatBytes(...arrays) { | ||
if (arrays.length === 1) | ||
return arrays[0]; | ||
const length = arrays.reduce((a, arr) => a + arr.length, 0); | ||
const result = new Uint8Array(length); | ||
for (let i = 0, pad = 0; i < arrays.length; i++) { | ||
const arr = arrays[i]; | ||
result.set(arr, pad); | ||
pad += arr.length; | ||
} | ||
return result; | ||
} | ||
exports.concatBytes = concatBytes; | ||
class Fp { | ||
@@ -144,6 +205,16 @@ constructor(value) { | ||
} | ||
static fromBytes(b) { | ||
if (b.length !== Fp.BYTES_LEN) | ||
throw new Error(`fromBytes wrong length=${b.length}`); | ||
return new Fp(bytesToNumberBE(b)); | ||
} | ||
toBytes() { | ||
return numberToBytesBE(this.value, Fp.BYTES_LEN); | ||
} | ||
} | ||
exports.Fp = Fp; | ||
_a = Fp; | ||
Fp.ORDER = exports.CURVE.P; | ||
Fp.MAX_BITS = bitLen(exports.CURVE.P); | ||
Fp.BYTES_LEN = Math.ceil(_a.MAX_BITS / 8); | ||
Fp.ZERO = new Fp(0n); | ||
@@ -260,3 +331,3 @@ Fp.ONE = new Fp(1n); | ||
static fromBigTuple(tuple) { | ||
const fps = tuple.map(n => new Fp(n)); | ||
const fps = tuple.map((n) => new Fp(n)); | ||
return new Fp2(...fps); | ||
@@ -359,6 +430,16 @@ } | ||
} | ||
static fromBytes(b) { | ||
if (b.length !== Fp2.BYTES_LEN) | ||
throw new Error(`fromBytes wrong length=${b.length}`); | ||
return new Fp2(Fp.fromBytes(b.subarray(0, Fp.BYTES_LEN)), Fp.fromBytes(b.subarray(Fp.BYTES_LEN))); | ||
} | ||
toBytes() { | ||
return concatBytes(this.c0.toBytes(), this.c1.toBytes()); | ||
} | ||
} | ||
exports.Fp2 = Fp2; | ||
_b = Fp2; | ||
Fp2.ORDER = exports.CURVE.P2; | ||
Fp2.MAX_BITS = bitLen(exports.CURVE.P2); | ||
Fp2.BYTES_LEN = Math.ceil(_b.MAX_BITS / 8); | ||
Fp2.ZERO = new Fp2(Fp.ZERO, Fp.ZERO); | ||
@@ -375,3 +456,3 @@ Fp2.ONE = new Fp2(Fp.ONE, Fp.ZERO); | ||
throw new Error('Invalid Fp6 usage'); | ||
const c = [t.slice(0, 2), t.slice(2, 4), t.slice(4, 6)].map(t => Fp2.fromBigTuple(t)); | ||
const c = [t.slice(0, 2), t.slice(2, 4), t.slice(4, 6)].map((t) => Fp2.fromBigTuple(t)); | ||
return new Fp6(...c); | ||
@@ -463,2 +544,10 @@ } | ||
} | ||
static fromBytes(b) { | ||
if (b.length !== Fp6.BYTES_LEN) | ||
throw new Error(`fromBytes wrong length=${b.length}`); | ||
return new Fp6(Fp2.fromBytes(b.subarray(0, Fp2.BYTES_LEN)), Fp2.fromBytes(b.subarray(Fp2.BYTES_LEN, 2 * Fp2.BYTES_LEN)), Fp2.fromBytes(b.subarray(2 * Fp2.BYTES_LEN))); | ||
} | ||
toBytes() { | ||
return concatBytes(this.c0.toBytes(), this.c1.toBytes(), this.c2.toBytes()); | ||
} | ||
} | ||
@@ -468,2 +557,3 @@ exports.Fp6 = Fp6; | ||
Fp6.ONE = new Fp6(Fp2.ONE, Fp2.ZERO, Fp2.ZERO); | ||
Fp6.BYTES_LEN = 3 * Fp2.BYTES_LEN; | ||
class Fp12 { | ||
@@ -594,2 +684,10 @@ constructor(c0, c1) { | ||
} | ||
static fromBytes(b) { | ||
if (b.length !== Fp12.BYTES_LEN) | ||
throw new Error(`fromBytes wrong length=${b.length}`); | ||
return new Fp12(Fp6.fromBytes(b.subarray(0, Fp6.BYTES_LEN)), Fp6.fromBytes(b.subarray(Fp6.BYTES_LEN))); | ||
} | ||
toBytes() { | ||
return concatBytes(this.c0.toBytes(), this.c1.toBytes()); | ||
} | ||
} | ||
@@ -599,2 +697,3 @@ exports.Fp12 = Fp12; | ||
Fp12.ONE = new Fp12(Fp6.ONE, Fp6.ZERO); | ||
Fp12.BYTES_LEN = 2 * Fp6.BYTES_LEN; | ||
class ProjectivePoint { | ||
@@ -812,3 +911,3 @@ constructor(x, y, z, C) { | ||
exports.ProjectivePoint = ProjectivePoint; | ||
function sgn0(x) { | ||
function sgn0_fp2(x) { | ||
const { re: x0, im: x1 } = x.reim(); | ||
@@ -820,2 +919,5 @@ const sign_0 = x0 % 2n; | ||
} | ||
function sgn0_m_eq_1(x) { | ||
return Boolean(x.value % 2n); | ||
} | ||
const P_MINUS_9_DIV_16 = (exports.CURVE.P ** 2n - 9n) / 16n; | ||
@@ -877,31 +979,55 @@ function sqrt_div_fp2(u, v) { | ||
y = y; | ||
if (sgn0(t) !== sgn0(y)) | ||
if (sgn0_fp2(t) !== sgn0_fp2(y)) | ||
y = y.negate(); | ||
y = y.multiply(denominator); | ||
return [numerator, y, denominator]; | ||
return [numerator.div(denominator), y]; | ||
} | ||
exports.map_to_curve_simple_swu_9mod16 = map_to_curve_simple_swu_9mod16; | ||
function isogenyMapG2(xyz) { | ||
const x = xyz[0], y = xyz[1], z = xyz[2]; | ||
const zz = z.multiply(z); | ||
const zzz = zz.multiply(z); | ||
const zPowers = [z, zz, zzz]; | ||
const mapped = [Fp2.ZERO, Fp2.ZERO, Fp2.ZERO, Fp2.ZERO]; | ||
for (let i = 0; i < ISOGENY_COEFFICIENTS.length; i++) { | ||
const k_i = ISOGENY_COEFFICIENTS[i]; | ||
mapped[i] = k_i.slice(-1)[0]; | ||
const arr = k_i.slice(0, -1).reverse(); | ||
for (let j = 0; j < arr.length; j++) { | ||
const k_i_j = arr[j]; | ||
mapped[i] = mapped[i].multiply(x).add(zPowers[j].multiply(k_i_j)); | ||
} | ||
function map_to_curve_simple_swu_3mod4(u) { | ||
const A = new Fp(0x144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1dn); | ||
const B = new Fp(0x12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0n); | ||
const Z = new Fp(11n); | ||
const c1 = (Fp.ORDER - 3n) / 4n; | ||
const c2 = Z.negate().pow(3n).sqrt(); | ||
const tv1 = u.square(); | ||
const tv3 = Z.multiply(tv1); | ||
let xDen = tv3.square().add(tv3); | ||
const xNum1 = xDen.add(Fp.ONE).multiply(B); | ||
const xNum2 = tv3.multiply(xNum1); | ||
xDen = A.negate().multiply(xDen); | ||
if (xDen.isZero()) | ||
xDen = A.multiply(Z); | ||
let tv2 = xDen.square(); | ||
const gxd = tv2.multiply(xDen); | ||
tv2 = A.multiply(tv2); | ||
let gx1 = xNum1.square().add(tv2).multiply(xNum1); | ||
tv2 = B.multiply(gxd); | ||
gx1 = gx1.add(tv2); | ||
tv2 = gx1.multiply(gxd); | ||
const tv4 = gxd.square().multiply(tv2); | ||
const y1 = tv4.pow(c1).multiply(tv2); | ||
const y2 = y1.multiply(c2).multiply(tv1).multiply(u); | ||
let xNum, yPos; | ||
if (y1.square().multiply(gxd).equals(gx1)) { | ||
xNum = xNum1; | ||
yPos = y1; | ||
} | ||
mapped[2] = mapped[2].multiply(y); | ||
mapped[3] = mapped[3].multiply(z); | ||
const z2 = mapped[1].multiply(mapped[3]); | ||
const x2 = mapped[0].multiply(mapped[3]); | ||
const y2 = mapped[1].multiply(mapped[2]); | ||
return [x2, y2, z2]; | ||
else { | ||
xNum = xNum2; | ||
yPos = y2; | ||
} | ||
const yNeg = yPos.negate(); | ||
const y = sgn0_m_eq_1(u) == sgn0_m_eq_1(yPos) ? yPos : yNeg; | ||
return [xNum.div(xDen), y]; | ||
} | ||
exports.map_to_curve_simple_swu_3mod4 = map_to_curve_simple_swu_3mod4; | ||
function isogenyMap(COEFF, x, y) { | ||
const [xNum, xDen, yNum, yDen] = COEFF.map((val) => val.reduce((acc, i) => acc.multiply(x).add(i))); | ||
x = xNum.div(xDen); | ||
y = y.multiply(yNum.div(yDen)); | ||
return [x, y]; | ||
} | ||
const isogenyMapG2 = (x, y) => isogenyMap(ISOGENY_COEFFICIENTS_G2, x, y); | ||
exports.isogenyMapG2 = isogenyMapG2; | ||
const isogenyMapG1 = (x, y) => isogenyMap(ISOGENY_COEFFICIENTS_G1, x, y); | ||
exports.isogenyMapG1 = isogenyMapG1; | ||
function calcPairingPrecomputes(x, y) { | ||
@@ -1092,11 +1218,7 @@ const Qx = x, Qy = y, Qz = Fp2.ONE; | ||
], | ||
].map(n => Fp2.fromBigTuple(n)); | ||
].map((n) => Fp2.fromBigTuple(n)); | ||
const xnum = [ | ||
[ | ||
0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6n, | ||
0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6n, | ||
], | ||
[ | ||
0x171d6541fa38ccfaed6dea691f5fb614cb14b4e7f4e810aa22d6108f142b85757098e38d0f671c7188e2aaaaaaaa5ed1n, | ||
0x0n, | ||
0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71an, | ||
], | ||
@@ -1108,26 +1230,26 @@ [ | ||
[ | ||
0x171d6541fa38ccfaed6dea691f5fb614cb14b4e7f4e810aa22d6108f142b85757098e38d0f671c7188e2aaaaaaaa5ed1n, | ||
0x0n, | ||
0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71an, | ||
], | ||
[ | ||
0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6n, | ||
0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6n, | ||
], | ||
].map((pair) => Fp2.fromBigTuple(pair)); | ||
const xden = [ | ||
[0x0n, 0x0n], | ||
[0x1n, 0x0n], | ||
[ | ||
0xcn, | ||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa9fn, | ||
], | ||
[ | ||
0x0n, | ||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa63n, | ||
], | ||
[ | ||
0xcn, | ||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa9fn, | ||
], | ||
[0x1n, 0x0n], | ||
[0x0n, 0x0n], | ||
].map((pair) => Fp2.fromBigTuple(pair)); | ||
const ynum = [ | ||
[ | ||
0x1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706n, | ||
0x1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706n, | ||
], | ||
[ | ||
0x124c9ad43b6cf79bfbf7043de3811ad0761b0f37a1e26286b0e977c69aa274524e79097a56dc4bd9e1b371c71c718b10n, | ||
0x0n, | ||
0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97ben, | ||
], | ||
@@ -1139,10 +1261,15 @@ [ | ||
[ | ||
0x124c9ad43b6cf79bfbf7043de3811ad0761b0f37a1e26286b0e977c69aa274524e79097a56dc4bd9e1b371c71c718b10n, | ||
0x0n, | ||
0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97ben, | ||
], | ||
[ | ||
0x1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706n, | ||
0x1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706n, | ||
], | ||
].map((pair) => Fp2.fromBigTuple(pair)); | ||
const yden = [ | ||
[0x1n, 0x0n], | ||
[ | ||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fbn, | ||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fbn, | ||
0x12n, | ||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa99n, | ||
], | ||
@@ -1154,7 +1281,71 @@ [ | ||
[ | ||
0x12n, | ||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa99n, | ||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fbn, | ||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fbn, | ||
], | ||
[0x1n, 0x0n], | ||
].map((pair) => Fp2.fromBigTuple(pair)); | ||
const ISOGENY_COEFFICIENTS = [xnum, xden, ynum, yden]; | ||
const ISOGENY_COEFFICIENTS_G2 = [xnum, xden, ynum, yden]; | ||
const ISOGENY_COEFFICIENTS_G1 = [ | ||
[ | ||
new Fp(0x06e08c248e260e70bd1e962381edee3d31d79d7e22c837bc23c0bf1bc24c6b68c24b1b80b64d391fa9c8ba2e8ba2d229n), | ||
new Fp(0x10321da079ce07e272d8ec09d2565b0dfa7dccdde6787f96d50af36003b14866f69b771f8c285decca67df3f1605fb7bn), | ||
new Fp(0x169b1f8e1bcfa7c42e0c37515d138f22dd2ecb803a0c5c99676314baf4bb1b7fa3190b2edc0327797f241067be390c9en), | ||
new Fp(0x080d3cf1f9a78fc47b90b33563be990dc43b756ce79f5574a2c596c928c5d1de4fa295f296b74e956d71986a8497e317n), | ||
new Fp(0x17b81e7701abdbe2e8743884d1117e53356de5ab275b4db1a682c62ef0f2753339b7c8f8c8f475af9ccb5618e3f0c88en), | ||
new Fp(0x0d6ed6553fe44d296a3726c38ae652bfb11586264f0f8ce19008e218f9c86b2a8da25128c1052ecaddd7f225a139ed84n), | ||
new Fp(0x1630c3250d7313ff01d1201bf7a74ab5db3cb17dd952799b9ed3ab9097e68f90a0870d2dcae73d19cd13c1c66f652983n), | ||
new Fp(0x0e99726a3199f4436642b4b3e4118e5499db995a1257fb3f086eeb65982fac18985a286f301e77c451154ce9ac8895d9n), | ||
new Fp(0x1778e7166fcc6db74e0609d307e55412d7f5e4656a8dbf25f1b33289f1b330835336e25ce3107193c5b388641d9b6861n), | ||
new Fp(0x0d54005db97678ec1d1048c5d10a9a1bce032473295983e56878e501ec68e25c958c3e3d2a09729fe0179f9dac9edcb0n), | ||
new Fp(0x17294ed3e943ab2f0588bab22147a81c7c17e75b2f6a8417f565e33c70d1e86b4838f2a6f318c356e834eef1b3cb83bbn), | ||
new Fp(0x11a05f2b1e833340b809101dd99815856b303e88a2d7005ff2627b56cdb4e2c85610c2d5f2e62d6eaeac1662734649b7n), | ||
], | ||
[ | ||
new Fp(0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001n), | ||
new Fp(0x095fc13ab9e92ad4476d6e3eb3a56680f682b4ee96f7d03776df533978f31c1593174e4b4b7865002d6384d168ecdd0an), | ||
new Fp(0x0a10ecf6ada54f825e920b3dafc7a3cce07f8d1d7161366b74100da67f39883503826692abba43704776ec3a79a1d641n), | ||
new Fp(0x14a7ac2a9d64a8b230b3f5b074cf01996e7f63c21bca68a81996e1cdf9822c580fa5b9489d11e2d311f7d99bbdcc5a5en), | ||
new Fp(0x0772caacf16936190f3e0c63e0596721570f5799af53a1894e2e073062aede9cea73b3538f0de06cec2574496ee84a3an), | ||
new Fp(0x0e7355f8e4e667b955390f7f0506c6e9395735e9ce9cad4d0a43bcef24b8982f7400d24bc4228f11c02df9a29f6304a5n), | ||
new Fp(0x13a8e162022914a80a6f1d5f43e7a07dffdfc759a12062bb8d6b44e833b306da9bd29ba81f35781d539d395b3532a21en), | ||
new Fp(0x03425581a58ae2fec83aafef7c40eb545b08243f16b1655154cca8abc28d6fd04976d5243eecf5c4130de8938dc62cd8n), | ||
new Fp(0x0b2962fe57a3225e8137e629bff2991f6f89416f5a718cd1fca64e00b11aceacd6a3d0967c94fedcfcc239ba5cb83e19n), | ||
new Fp(0x12561a5deb559c4348b4711298e536367041e8ca0cf0800c0126c2588c48bf5713daa8846cb026e9e5c8276ec82b3bffn), | ||
new Fp(0x08ca8d548cff19ae18b2e62f4bd3fa6f01d5ef4ba35b48ba9c9588617fc8ac62b558d681be343df8993cf9fa40d21b1cn), | ||
], | ||
[ | ||
new Fp(0x15e6be4e990f03ce4ea50b3b42df2eb5cb181d8f84965a3957add4fa95af01b2b665027efec01c7704b456be69c8b604n), | ||
new Fp(0x05c129645e44cf1102a159f748c4a3fc5e673d81d7e86568d9ab0f5d396a7ce46ba1049b6579afb7866b1e715475224bn), | ||
new Fp(0x0245a394ad1eca9b72fc00ae7be315dc757b3b080d4c158013e6632d3c40659cc6cf90ad1c232a6442d9d3f5db980133n), | ||
new Fp(0x0b182cac101b9399d155096004f53f447aa7b12a3426b08ec02710e807b4633f06c851c1919211f20d4c04f00b971ef8n), | ||
new Fp(0x18b46a908f36f6deb918c143fed2edcc523559b8aaf0c2462e6bfe7f911f643249d9cdf41b44d606ce07c8a4d0074d8en), | ||
new Fp(0x19713e47937cd1be0dfd0b8f1d43fb93cd2fcbcb6caf493fd1183e416389e61031bf3a5cce3fbafce813711ad011c132n), | ||
new Fp(0x0e1bba7a1186bdb5223abde7ada14a23c42a0ca7915af6fe06985e7ed1e4d43b9b3f7055dd4eba6f2bafaaebca731c30n), | ||
new Fp(0x09fc4018bd96684be88c9e221e4da1bb8f3abd16679dc26c1e8b6e6a1f20cabe69d65201c78607a360370e577bdba587n), | ||
new Fp(0x0987c8d5333ab86fde9926bd2ca6c674170a05bfe3bdd81ffd038da6c26c842642f64550fedfe935a15e4ca31870fb29n), | ||
new Fp(0x04ab0b9bcfac1bbcb2c977d027796b3ce75bb8ca2be184cb5231413c4d634f3747a87ac2460f415ec961f8855fe9d6f2n), | ||
new Fp(0x16603fca40634b6a2211e11db8f0a6a074a7d0d4afadb7bd76505c3d3ad5544e203f6326c95a807299b23ab13633a5f0n), | ||
new Fp(0x08cc03fdefe0ff135caf4fe2a21529c4195536fbe3ce50b879833fd221351adc2ee7f8dc099040a841b6daecf2e8fedbn), | ||
new Fp(0x01f86376e8981c217898751ad8746757d42aa7b90eeb791c09e4a3ec03251cf9de405aba9ec61deca6355c77b0e5f4cbn), | ||
new Fp(0x00cc786baa966e66f4a384c86a3b49942552e2d658a31ce2c344be4b91400da7d26d521628b00523b8dfe240c72de1f6n), | ||
new Fp(0x134996a104ee5811d51036d776fb46831223e96c254f383d0f906343eb67ad34d6c56711962fa8bfe097e75a2e41c696n), | ||
new Fp(0x090d97c81ba24ee0259d1f094980dcfa11ad138e48a869522b52af6c956543d3cd0c7aee9b3ba3c2be9845719707bb33n), | ||
], | ||
[ | ||
new Fp(0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001n), | ||
new Fp(0x0e0fa1d816ddc03e6b24255e0d7819c171c40f65e273b853324efcd6356caa205ca2f570f13497804415473a1d634b8fn), | ||
new Fp(0x02660400eb2e4f3b628bdd0d53cd76f2bf565b94e72927c1cb748df27942480e420517bd8714cc80d1fadc1326ed06f7n), | ||
new Fp(0x0ad6b9514c767fe3c3613144b45f1496543346d98adf02267d5ceef9a00d9b8693000763e3b90ac11e99b138573345ccn), | ||
new Fp(0x0accbb67481d033ff5852c1e48c50c477f94ff8aefce42d28c0f9a88cea7913516f968986f7ebbea9684b529e2561092n), | ||
new Fp(0x04d2f259eea405bd48f010a01ad2911d9c6dd039bb61a6290e591b36e636a5c871a5c29f4f83060400f8b49cba8f6aa8n), | ||
new Fp(0x167a55cda70a6e1cea820597d94a84903216f763e13d87bb5308592e7ea7d4fbc7385ea3d529b35e346ef48bb8913f55n), | ||
new Fp(0x1866c8ed336c61231a1be54fd1d74cc4f9fb0ce4c6af5920abc5750c4bf39b4852cfe2f7bb9248836b233d9d55535d4an), | ||
new Fp(0x16a3ef08be3ea7ea03bcddfabba6ff6ee5a4375efa1f4fd7feb34fd206357132b920f5b00801dee460ee415a15812ed9n), | ||
new Fp(0x166007c08a99db2fc3ba8734ace9824b5eecfdfa8d0cf8ef5dd365bc400a0051d5fa9c01a58b1fb93d1a1399126a775cn), | ||
new Fp(0x08d9e5297186db2d9fb266eaac783182b70152c65550d881c5ecd87b6f0f5a6449f38db9dfa9cce202c6477faaf9b7acn), | ||
new Fp(0x0be0e079545f43e4b00cc912f8228ddcc6d19c9f0f69bbb0542eda0fc9dec916a20b15dc0fd2ededda39142311a5001dn), | ||
new Fp(0x16b7d288798e5395f20d23bf89edb4d1d115c5dbddbcd30e123da489e726af41727364f2c28297ada8d26d98445f5416n), | ||
new Fp(0x058df3306640da276faaae7d6e8eb15778c4855551ae7f310c35a5dd279cd2eca6757cd636f96f891e2538b53dbf67f2n), | ||
new Fp(0x1962d75c2381201e1a0cbd6c43c348b885c84ff731c4d59ca4a10356f453e01f78a4260763529e3532f6102c2e49a03dn), | ||
new Fp(0x16112c4c3a9c98b252181140fad0eae9601a6de578980be6eec3232b5be72e7a07f3688ef60c206d01479253b03663c1n), | ||
], | ||
]; |
{ | ||
"name": "@noble/bls12-381", | ||
"version": "1.3.0", | ||
"version": "1.4.0", | ||
"description": "Fastest JS implementation of BLS12-381. Auditable, secure, 0-dependency aggregated signatures & pairings", | ||
@@ -13,3 +13,3 @@ "files": [ | ||
"test": "jest test/*.test.ts", | ||
"build": "tsc -d && tsc -p tsconfig.esm.json", | ||
"build": "tsc && tsc -p tsconfig.esm.json", | ||
"build:release": "rollup -c rollup.config.js", | ||
@@ -36,7 +36,9 @@ "bench": "node test/benchmark.js", | ||
"jest": "28.1.0", | ||
"micro-bmark": "0.1.3", | ||
"micro-bmark": "0.2.0", | ||
"prettier": "2.6.2", | ||
"rollup": "2.75.5", | ||
"ts-jest": "28.0.4", | ||
"typescript": "4.7.3" | ||
"typescript": "4.7.3", | ||
"@noble/hashes": "1.1.2", | ||
"micro-packed": "0.3.1" | ||
}, | ||
@@ -77,2 +79,2 @@ "keywords": [ | ||
] | ||
} | ||
} |
@@ -231,2 +231,12 @@ # 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) | ||
// for hashToCurve static method | ||
declare const htfDefaults: { | ||
DST: string; | ||
p: bigint; | ||
m: number; | ||
k: number; | ||
expand: boolean; | ||
hash: Hash; | ||
}; | ||
// projective point (xyz) at G1 | ||
@@ -239,2 +249,3 @@ class PointG1 extends ProjectivePoint<Fp> { | ||
static fromPrivateKey(privateKey: PrivateKey): PointG1; | ||
static hashToCurve(msg: Hex, options?: Partial<typeof htfDefaults>): Promise<PointG1>; | ||
toRawBytes(isCompressed?: boolean): Uint8Array; | ||
@@ -251,3 +262,3 @@ toHex(isCompressed?: boolean): string; | ||
static ZERO: PointG2; | ||
static hashToCurve(msg: Bytes): Promise<PointG2>; | ||
static hashToCurve(msg: Hex, options?: Partial<typeof htfDefaults>): Promise<PointG2>; | ||
static fromSignature(hex: Bytes): PointG2; | ||
@@ -272,23 +283,23 @@ static fromHex(bytes: Bytes): PointG2; | ||
Benchmarks measured with Apple M1: | ||
Benchmarks measured with Apple M2 on macOS 12.5 with node.js 18.8: | ||
``` | ||
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 | ||
getPublicKey x 818 ops/sec @ 1ms/op | ||
sign x 44 ops/sec @ 22ms/op | ||
verify x 34 ops/sec @ 29ms/op | ||
pairing x 84 ops/sec @ 11ms/op | ||
aggregatePublicKeys/8 x 117 ops/sec @ 8ms/op | ||
aggregateSignatures/8 x 45 ops/sec @ 21ms/op | ||
with compression / decompression disabled: | ||
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 | ||
sign/nc x 60 ops/sec @ 16ms/op | ||
verify/nc x 57 ops/sec @ 17ms/op ± 1.05% (min: 17ms, max: 19ms) | ||
aggregatePublicKeys/32 x 1,163 ops/sec @ 859μs/op | ||
aggregatePublicKeys/128 x 758 ops/sec @ 1ms/op | ||
aggregatePublicKeys/512 x 318 ops/sec @ 3ms/op | ||
aggregatePublicKeys/2048 x 96 ops/sec @ 10ms/op | ||
aggregateSignatures/32 x 516 ops/sec @ 1ms/op | ||
aggregateSignatures/128 x 269 ops/sec @ 3ms/op | ||
aggregateSignatures/512 x 93 ops/sec @ 10ms/op | ||
aggregateSignatures/2048 x 25 ops/sec @ 38ms/op | ||
``` | ||
@@ -306,3 +317,3 @@ | ||
We're using built-in JS `BigInt`, which is "unsuitable for use in cryptography" as [per official spec](https://github.com/tc39/proposal-bigint#cryptography). This means that the lib is potentially vulnerable to [timing attacks](https://en.wikipedia.org/wiki/Timing_attack). But, *JIT-compiler* and *Garbage Collector* make "constant time" extremely hard to achieve in a scripting language. Which means *any other JS library doesn't use constant-time bigints*. Including bn.js or anything else. Even statically typed Rust, a language without GC, [makes it harder to achieve constant-time](https://www.chosenplaintext.ca/open-source/rust-timing-shield/security) for some cases. If your goal is absolute security, don't use any JS lib — including bindings to native ones. Use low-level libraries & languages. | ||
We're using built-in JS `BigInt`, which is potentially vulnerable to [timing attacks](https://en.wikipedia.org/wiki/Timing_attack) as [per official spec](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#cryptography). But, *JIT-compiler* and *Garbage Collector* make "constant time" extremely hard to achieve in a scripting language. Which means *any other JS library doesn't use constant-time bigints*. Including bn.js or anything else. Even statically typed Rust, a language without GC, [makes it harder to achieve constant-time](https://www.chosenplaintext.ca/open-source/rust-timing-shield/security) for some cases. If your goal is absolute security, don't use any JS lib — including bindings to native ones. Use low-level libraries & languages. | ||
@@ -309,0 +320,0 @@ 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. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
179949
4220
329
13