bls: get rid of bigint literals. gh-22

This commit is contained in:
Paul Miller 2023-03-28 17:01:42 +00:00
parent 618508d32c
commit 4244f97d38
No known key found for this signature in database
GPG Key ID: 697079DA6878B89B
2 changed files with 198 additions and 113 deletions

4
package-lock.json generated

@ -1,12 +1,12 @@
{ {
"name": "@noble/curves", "name": "@noble/curves",
"version": "0.8.3", "version": "0.9.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@noble/curves", "name": "@noble/curves",
"version": "0.8.3", "version": "0.9.0",
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",

@ -69,16 +69,23 @@ import {
} from './abstract/weierstrass.js'; } from './abstract/weierstrass.js';
import { isogenyMap } from './abstract/hash-to-curve.js'; import { isogenyMap } from './abstract/hash-to-curve.js';
// Be friendly to bad ECMAScript parsers by not using bigint literals
// prettier-ignore
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n = BigInt(4);
const _8n = BigInt(8),
_16n = BigInt(16);
// CURVE FIELDS // CURVE FIELDS
// Finite field over p. // Finite field over p.
const Fp = const Fp = mod.Field(
mod.Field( BigInt(
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'
); )
);
type Fp = bigint; type Fp = bigint;
// Finite field over r. // Finite field over r.
// This particular field is not used anywhere in bls12-381, but it is still useful. // This particular field is not used anywhere in bls12-381, but it is still useful.
const Fr = mod.Field(0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001n); const Fr = mod.Field(BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001'));
// Fp₂ over complex plane // Fp₂ over complex plane
type BigintTuple = [bigint, bigint]; type BigintTuple = [bigint, bigint];
@ -121,8 +128,9 @@ type Fp2Utils = {
// h2q // h2q
// NOTE: ORDER was wrong! // NOTE: ORDER was wrong!
const FP2_ORDER = const FP2_ORDER =
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn ** BigInt(
2n; '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'
) ** _2n;
const Fp2: mod.IField<Fp2> & Fp2Utils = { const Fp2: mod.IField<Fp2> & Fp2Utils = {
ORDER: FP2_ORDER, ORDER: FP2_ORDER,
@ -175,7 +183,7 @@ const Fp2: mod.IField<Fp2> & Fp2Utils = {
// https://github.com/zkcrypto/bls12_381/blob/080eaa74ec0e394377caa1ba302c8c121df08b07/src/fp2.rs#L250 // https://github.com/zkcrypto/bls12_381/blob/080eaa74ec0e394377caa1ba302c8c121df08b07/src/fp2.rs#L250
// https://github.com/supranational/blst/blob/aae0c7d70b799ac269ff5edf29d8191dbd357876/src/exp2.c#L1 // https://github.com/supranational/blst/blob/aae0c7d70b799ac269ff5edf29d8191dbd357876/src/exp2.c#L1
// Inspired by https://github.com/dalek-cryptography/curve25519-dalek/blob/17698df9d4c834204f83a3574143abacb4fc81a5/src/field.rs#L99 // Inspired by https://github.com/dalek-cryptography/curve25519-dalek/blob/17698df9d4c834204f83a3574143abacb4fc81a5/src/field.rs#L99
const candidateSqrt = Fp2.pow(num, (Fp2.ORDER + 8n) / 16n); const candidateSqrt = Fp2.pow(num, (Fp2.ORDER + _8n) / _16n);
const check = Fp2.div(Fp2.sqr(candidateSqrt), num); // candidateSqrt.square().div(this); const check = Fp2.div(Fp2.sqr(candidateSqrt), num); // candidateSqrt.square().div(this);
const R = FP2_ROOTS_OF_UNITY; const R = FP2_ROOTS_OF_UNITY;
const divisor = [R[0], R[2], R[4], R[6]].find((r) => Fp2.eql(r, check)); const divisor = [R[0], R[2], R[4], R[6]].find((r) => Fp2.eql(r, check));
@ -193,10 +201,10 @@ const Fp2: mod.IField<Fp2> & Fp2Utils = {
// Same as sgn0_fp2 in draft-irtf-cfrg-hash-to-curve-16 // Same as sgn0_fp2 in draft-irtf-cfrg-hash-to-curve-16
isOdd: (x: Fp2) => { isOdd: (x: Fp2) => {
const { re: x0, im: x1 } = Fp2.reim(x); const { re: x0, im: x1 } = Fp2.reim(x);
const sign_0 = x0 % 2n; const sign_0 = x0 % _2n;
const zero_0 = x0 === 0n; const zero_0 = x0 === _0n;
const sign_1 = x1 % 2n; const sign_1 = x1 % _2n;
return BigInt(sign_0 || (zero_0 && sign_1)) == 1n; return BigInt(sign_0 || (zero_0 && sign_1)) == _1n;
}, },
// Bytes util // Bytes util
fromBytes(b: Uint8Array): Fp2 { fromBytes(b: Uint8Array): Fp2 {
@ -216,8 +224,8 @@ const Fp2: mod.IField<Fp2> & Fp2Utils = {
// multiply by u + 1 // multiply by u + 1
mulByNonresidue: ({ c0, c1 }) => ({ c0: Fp.sub(c0, c1), c1: Fp.add(c0, c1) }), mulByNonresidue: ({ c0, c1 }) => ({ c0: Fp.sub(c0, c1), c1: Fp.add(c0, c1) }),
multiplyByB: ({ c0, c1 }) => { multiplyByB: ({ c0, c1 }) => {
let t0 = Fp.mul(c0, 4n); // 4 * c0 let t0 = Fp.mul(c0, _4n); // 4 * c0
let t1 = Fp.mul(c1, 4n); // 4 * c1 let t1 = Fp.mul(c1, _4n); // 4 * c1
// (T0-T1) + (T0+T1)*i // (T0-T1) + (T0+T1)*i
return { c0: Fp.sub(t0, t1), c1: Fp.add(t0, t1) }; return { c0: Fp.sub(t0, t1), c1: Fp.add(t0, t1) };
}, },
@ -234,33 +242,36 @@ const Fp2: mod.IField<Fp2> & Fp2Utils = {
// Finite extension field over irreducible polynominal. // Finite extension field over irreducible polynominal.
// Fp(u) / (u² - β) where β = -1 // Fp(u) / (u² - β) where β = -1
const FP2_FROBENIUS_COEFFICIENTS = [ const FP2_FROBENIUS_COEFFICIENTS = [
0x1n, BigInt('0x1'),
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaan, BigInt(
'0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa'
),
].map((item) => Fp.create(item)); ].map((item) => Fp.create(item));
// For Fp2 roots of unity. // For Fp2 roots of unity.
const rv1 = const rv1 = BigInt(
0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09n; '0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09'
);
// const ev1 = // const ev1 =
// 0x699be3b8c6870965e5bf892ad5d2cc7b0e85a117402dfd83b7f4a947e02d978498255a2aaec0ac627b5afbdf1bf1c90n; // BigInt('0x699be3b8c6870965e5bf892ad5d2cc7b0e85a117402dfd83b7f4a947e02d978498255a2aaec0ac627b5afbdf1bf1c90');
// const ev2 = // const ev2 =
// 0x8157cd83046453f5dd0972b6e3949e4288020b5b8a9cc99ca07e27089a2ce2436d965026adad3ef7baba37f2183e9b5n; // BigInt('0x8157cd83046453f5dd0972b6e3949e4288020b5b8a9cc99ca07e27089a2ce2436d965026adad3ef7baba37f2183e9b5');
// const ev3 = // const ev3 =
// 0xab1c2ffdd6c253ca155231eb3e71ba044fd562f6f72bc5bad5ec46a0b7a3b0247cf08ce6c6317f40edbc653a72dee17n; // BigInt('0xab1c2ffdd6c253ca155231eb3e71ba044fd562f6f72bc5bad5ec46a0b7a3b0247cf08ce6c6317f40edbc653a72dee17');
// const ev4 = // const ev4 =
// 0xaa404866706722864480885d68ad0ccac1967c7544b447873cc37e0181271e006df72162a3d3e0287bf597fbf7f8fc1n; // BigInt('0xaa404866706722864480885d68ad0ccac1967c7544b447873cc37e0181271e006df72162a3d3e0287bf597fbf7f8fc1');
// Eighth roots of unity, used for computing square roots in Fp2. // Eighth roots of unity, used for computing square roots in Fp2.
// To verify or re-calculate: // To verify or re-calculate:
// Array(8).fill(new Fp2([1n, 1n])).map((fp2, k) => fp2.pow(Fp2.ORDER * BigInt(k) / 8n)) // Array(8).fill(new Fp2([1n, 1n])).map((fp2, k) => fp2.pow(Fp2.ORDER * BigInt(k) / 8n))
const FP2_ROOTS_OF_UNITY = [ const FP2_ROOTS_OF_UNITY = [
[1n, 0n], [_1n, _0n],
[rv1, -rv1], [rv1, -rv1],
[0n, 1n], [_0n, _1n],
[rv1, rv1], [rv1, rv1],
[-1n, 0n], [-_1n, _0n],
[-rv1, rv1], [-rv1, rv1],
[0n, -1n], [_0n, -_1n],
[-rv1, -rv1], [-rv1, -rv1],
].map((pair) => Fp2.fromBigTuple(pair)); ].map((pair) => Fp2.fromBigTuple(pair));
// eta values, used for computing sqrt(g(X1(t))) // eta values, used for computing sqrt(g(X1(t)))
@ -314,8 +325,8 @@ const Fp6Multiply = ({ c0, c1, c2 }: Fp6, rhs: Fp6 | bigint) => {
}; };
const Fp6Square = ({ c0, c1, c2 }: Fp6) => { const Fp6Square = ({ c0, c1, c2 }: Fp6) => {
let t0 = Fp2.sqr(c0); // c0² let t0 = Fp2.sqr(c0); // c0²
let t1 = Fp2.mul(Fp2.mul(c0, c1), 2n); // 2 * c0 * c1 let t1 = Fp2.mul(Fp2.mul(c0, c1), _2n); // 2 * c0 * c1
let t3 = Fp2.mul(Fp2.mul(c1, c2), 2n); // 2 * c1 * c2 let t3 = Fp2.mul(Fp2.mul(c1, c2), _2n); // 2 * c1 * c2
let t4 = Fp2.sqr(c2); // c2² let t4 = Fp2.sqr(c2); // c2²
return { return {
c0: Fp2.add(Fp2.mulByNonresidue(t3), t0), // T3 * (u + 1) + T0 c0: Fp2.add(Fp2.mulByNonresidue(t3), t0), // T3 * (u + 1) + T0
@ -440,46 +451,64 @@ const Fp6: mod.IField<Fp6> & Fp6Utils = {
}; };
const FP6_FROBENIUS_COEFFICIENTS_1 = [ const FP6_FROBENIUS_COEFFICIENTS_1 = [
[0x1n, 0x0n], [BigInt('0x1'), BigInt('0x0')],
[ [
0x0n, BigInt('0x0'),
0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaacn, BigInt(
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
),
], ],
[ [
0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffen, BigInt(
0x0n, '0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
),
BigInt('0x0'),
], ],
[0x0n, 0x1n], [BigInt('0x0'), BigInt('0x1')],
[ [
0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaacn, BigInt(
0x0n, '0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
),
BigInt('0x0'),
], ],
[ [
0x0n, BigInt('0x0'),
0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffen, BigInt(
'0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
),
], ],
].map((pair) => Fp2.fromBigTuple(pair)); ].map((pair) => Fp2.fromBigTuple(pair));
const FP6_FROBENIUS_COEFFICIENTS_2 = [ const FP6_FROBENIUS_COEFFICIENTS_2 = [
[0x1n, 0x0n], [BigInt('0x1'), BigInt('0x0')],
[ [
0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaadn, BigInt(
0x0n, '0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad'
),
BigInt('0x0'),
], ],
[ [
0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaacn, BigInt(
0x0n, '0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
),
BigInt('0x0'),
], ],
[ [
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaan, BigInt(
0x0n, '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa'
),
BigInt('0x0'),
], ],
[ [
0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffen, BigInt(
0x0n, '0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
),
BigInt('0x0'),
], ],
[ [
0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffffn, BigInt(
0x0n, '0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffff'
),
BigInt('0x0'),
], ],
].map((pair) => Fp2.fromBigTuple(pair)); ].map((pair) => Fp2.fromBigTuple(pair));
@ -488,7 +517,7 @@ const FP6_FROBENIUS_COEFFICIENTS_2 = [
// Fp₆(w) / (w² - γ) where γ = v // Fp₆(w) / (w² - γ) where γ = v
type Fp12 = { c0: Fp6; c1: Fp6 }; type Fp12 = { c0: Fp6; c1: Fp6 };
// The BLS parameter x for BLS12-381 // The BLS parameter x for BLS12-381
const BLS_X = 0xd201000000010000n; const BLS_X = BigInt('0xd201000000010000');
const BLS_X_LEN = bitLen(BLS_X); const BLS_X_LEN = bitLen(BLS_X);
// prettier-ignore // prettier-ignore
@ -646,14 +675,14 @@ const Fp12: mod.IField<Fp12> & Fp12Utils = {
let t9 = Fp2.mulByNonresidue(t8); // T8 * (u + 1) let t9 = Fp2.mulByNonresidue(t8); // T8 * (u + 1)
return { return {
c0: Fp6.create({ c0: Fp6.create({
c0: Fp2.add(Fp2.mul(Fp2.sub(t3, c0c0), 2n), t3), // 2 * (T3 - c0c0) + T3 c0: Fp2.add(Fp2.mul(Fp2.sub(t3, c0c0), _2n), t3), // 2 * (T3 - c0c0) + T3
c1: Fp2.add(Fp2.mul(Fp2.sub(t5, c0c1), 2n), t5), // 2 * (T5 - c0c1) + T5 c1: Fp2.add(Fp2.mul(Fp2.sub(t5, c0c1), _2n), t5), // 2 * (T5 - c0c1) + T5
c2: Fp2.add(Fp2.mul(Fp2.sub(t7, c0c2), 2n), t7), c2: Fp2.add(Fp2.mul(Fp2.sub(t7, c0c2), _2n), t7),
}), // 2 * (T7 - c0c2) + T7 }), // 2 * (T7 - c0c2) + T7
c1: Fp6.create({ c1: Fp6.create({
c0: Fp2.add(Fp2.mul(Fp2.add(t9, c1c0), 2n), t9), // 2 * (T9 + c1c0) + T9 c0: Fp2.add(Fp2.mul(Fp2.add(t9, c1c0), _2n), t9), // 2 * (T9 + c1c0) + T9
c1: Fp2.add(Fp2.mul(Fp2.add(t4, c1c1), 2n), t4), // 2 * (T4 + c1c1) + T4 c1: Fp2.add(Fp2.mul(Fp2.add(t4, c1c1), _2n), t4), // 2 * (T4 + c1c1) + T4
c2: Fp2.add(Fp2.mul(Fp2.add(t6, c1c2), 2n), t6), c2: Fp2.add(Fp2.mul(Fp2.add(t6, c1c2), _2n), t6),
}), }),
}; // 2 * (T6 + c1c2) + T6 }; // 2 * (T6 + c1c2) + T6
}, },
@ -688,50 +717,84 @@ const Fp12: mod.IField<Fp12> & Fp12Utils = {
}, },
}; };
const FP12_FROBENIUS_COEFFICIENTS = [ const FP12_FROBENIUS_COEFFICIENTS = [
[0x1n, 0x0n], [BigInt('0x1'), BigInt('0x0')],
[ [
0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8n, BigInt(
0x00fc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3n, '0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8'
),
BigInt(
'0x00fc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3'
),
], ],
[ [
0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffffn, BigInt(
0x0n, '0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffff'
),
BigInt('0x0'),
], ],
[ [
0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2n, BigInt(
0x06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09n, '0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2'
),
BigInt(
'0x06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09'
),
], ],
[ [
0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffen, BigInt(
0x0n, '0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
),
BigInt('0x0'),
], ],
[ [
0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995n, BigInt(
0x05b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116n, '0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995'
),
BigInt(
'0x05b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116'
),
], ],
[ [
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaan, BigInt(
0x0n, '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa'
),
BigInt('0x0'),
], ],
[ [
0x00fc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3n, BigInt(
0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8n, '0x00fc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3'
),
BigInt(
'0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8'
),
], ],
[ [
0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaacn, BigInt(
0x0n, '0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
),
BigInt('0x0'),
], ],
[ [
0x06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09n, BigInt(
0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2n, '0x06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09'
),
BigInt(
'0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2'
),
], ],
[ [
0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaadn, BigInt(
0x0n, '0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad'
),
BigInt('0x0'),
], ],
[ [
0x05b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116n, BigInt(
0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995n, '0x05b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116'
),
BigInt(
'0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995'
),
], ],
].map((n) => Fp2.fromBigTuple(n)); ].map((n) => Fp2.fromBigTuple(n));
// END OF CURVE FIELDS // END OF CURVE FIELDS
@ -887,17 +950,21 @@ const isogenyMapG1 = isogenyMap(
// SWU Map - Fp2 to G2': y² = x³ + 240i * x + 1012 + 1012i // SWU Map - Fp2 to G2': y² = x³ + 240i * x + 1012 + 1012i
const G2_SWU = mapToCurveSimpleSWU(Fp2, { const G2_SWU = mapToCurveSimpleSWU(Fp2, {
A: Fp2.create({ c0: Fp.create(0n), c1: Fp.create(240n) }), // A' = 240 * I A: Fp2.create({ c0: Fp.create(_0n), c1: Fp.create(240n) }), // A' = 240 * I
B: Fp2.create({ c0: Fp.create(1012n), c1: Fp.create(1012n) }), // B' = 1012 * (1 + I) B: Fp2.create({ c0: Fp.create(1012n), c1: Fp.create(1012n) }), // B' = 1012 * (1 + I)
Z: Fp2.create({ c0: Fp.create(-2n), c1: Fp.create(-1n) }), // Z: -(2 + I) Z: Fp2.create({ c0: Fp.create(-2n), c1: Fp.create(-1n) }), // Z: -(2 + I)
}); });
// Optimized SWU Map - Fp to G1 // Optimized SWU Map - Fp to G1
const G1_SWU = mapToCurveSimpleSWU(Fp, { const G1_SWU = mapToCurveSimpleSWU(Fp, {
A: Fp.create( A: Fp.create(
0x144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1dn BigInt(
'0x144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1d'
)
), ),
B: Fp.create( B: Fp.create(
0x12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0n BigInt(
'0x12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0'
)
), ),
Z: Fp.create(11n), Z: Fp.create(11n),
}); });
@ -922,8 +989,9 @@ function G2psi(c: ProjConstructor<Fp2>, P: ProjPointType<Fp2>) {
} }
// Ψ²(P) endomorphism // Ψ²(P) endomorphism
// 1 / F2(2)^((p-1)/3) in GF(p²) // 1 / F2(2)^((p-1)/3) in GF(p²)
const PSI2_C1 = const PSI2_C1 = BigInt(
0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaacn; '0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
);
function psi2(x: Fp2, y: Fp2): [Fp2, Fp2] { function psi2(x: Fp2, y: Fp2): [Fp2, Fp2] {
return [Fp2.mul(x, PSI2_C1), Fp2.neg(y)]; return [Fp2.mul(x, PSI2_C1), Fp2.neg(y)];
@ -1000,14 +1068,18 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
G1: { G1: {
Fp, Fp,
// cofactor; (z - 1)²/3 // cofactor; (z - 1)²/3
h: 0x396c8c005555e1568c00aaab0000aaabn, h: BigInt('0x396c8c005555e1568c00aaab0000aaab'),
// generator's coordinates // generator's coordinates
// x = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507 // x = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507
// y = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569 // y = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569
Gx: 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bbn, Gx: BigInt(
Gy: 0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1n, '0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb'
),
Gy: BigInt(
'0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'
),
a: Fp.ZERO, a: Fp.ZERO,
b: 4n, b: _4n,
htfDefaults: { ...htfDefaults, m: 1 }, htfDefaults: { ...htfDefaults, m: 1 },
wrapPrivateKey: true, wrapPrivateKey: true,
allowInfinityPoint: true, allowInfinityPoint: true,
@ -1017,8 +1089,9 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
// https://eprint.iacr.org/2021/1130.pdf // https://eprint.iacr.org/2021/1130.pdf
isTorsionFree: (c, point): boolean => { isTorsionFree: (c, point): boolean => {
// φ endomorphism // φ endomorphism
const cubicRootOfUnityModP = const cubicRootOfUnityModP = BigInt(
0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffen; '0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
);
const phi = new c(Fp.mul(point.px, cubicRootOfUnityModP), point.py, point.pz); const phi = new c(Fp.mul(point.px, cubicRootOfUnityModP), point.py, point.pz);
// todo: unroll // todo: unroll
@ -1028,7 +1101,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
// https://eprint.iacr.org/2019/814.pdf // https://eprint.iacr.org/2019/814.pdf
// (z² 1)/3 // (z² 1)/3
// const c1 = 0x396c8c005555e1560000000055555555n; // const c1 = BigInt('0x396c8c005555e1560000000055555555');
// const P = this; // const P = this;
// const S = P.sigma(); // const S = P.sigma();
// const Q = S.double(); // const Q = S.double();
@ -1054,13 +1127,13 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
const compressedValue = bytesToNumberBE(bytes); const compressedValue = bytesToNumberBE(bytes);
const bflag = bitGet(compressedValue, I_BIT_POS); const bflag = bitGet(compressedValue, I_BIT_POS);
// Zero // Zero
if (bflag === 1n) return { x: 0n, y: 0n }; if (bflag === _1n) return { x: _0n, y: _0n };
const x = Fp.create(compressedValue & Fp.MASK); const x = Fp.create(compressedValue & Fp.MASK);
const right = Fp.add(Fp.pow(x, 3n), Fp.create(bls12_381.CURVE.G1.b)); // y² = x³ + b const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381.CURVE.G1.b)); // y² = x³ + b
let y = Fp.sqrt(right); let y = Fp.sqrt(right);
if (!y) throw new Error('Invalid compressed G1 point'); if (!y) throw new Error('Invalid compressed G1 point');
const aflag = bitGet(compressedValue, C_BIT_POS); const aflag = bitGet(compressedValue, C_BIT_POS);
if ((y * 2n) / P !== aflag) y = Fp.neg(y); if ((y * _2n) / P !== aflag) y = Fp.neg(y);
return { x: Fp.create(x), y: Fp.create(y) }; return { x: Fp.create(x), y: Fp.create(y) };
} else if (bytes.length === 96) { } else if (bytes.length === 96) {
// Check if the infinity flag is set // Check if the infinity flag is set
@ -1079,7 +1152,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
if (isZero) return COMPRESSED_ZERO.slice(); if (isZero) return COMPRESSED_ZERO.slice();
const P = Fp.ORDER; const P = Fp.ORDER;
let num; let num;
num = bitSet(x, C_BIT_POS, Boolean((y * 2n) / P)); // set aflag num = bitSet(x, C_BIT_POS, Boolean((y * _2n) / P)); // set aflag
num = bitSet(num, S_BIT_POS, true); num = bitSet(num, S_BIT_POS, true);
return numberToBytesBE(num, Fp.BYTES); return numberToBytesBE(num, Fp.BYTES);
} else { } else {
@ -1100,21 +1173,33 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
G2: { G2: {
Fp: Fp2, Fp: Fp2,
// cofactor // cofactor
h: 0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5n, h: BigInt(
'0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5'
),
Gx: Fp2.fromBigTuple([ Gx: Fp2.fromBigTuple([
0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8n, BigInt(
0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7en, '0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8'
),
BigInt(
'0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e'
),
]), ]),
// y = // y =
// 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582, // 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582,
// 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905 // 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905
Gy: Fp2.fromBigTuple([ Gy: Fp2.fromBigTuple([
0x0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801n, BigInt(
0x0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79ben, '0x0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801'
),
BigInt(
'0x0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be'
),
]), ]),
a: Fp2.ZERO, a: Fp2.ZERO,
b: Fp2.fromBigTuple([4n, 4n]), b: Fp2.fromBigTuple([4n, _4n]),
hEff: 0xbc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551n, hEff: BigInt(
'0xbc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551'
),
htfDefaults: { ...htfDefaults }, htfDefaults: { ...htfDefaults },
wrapPrivateKey: true, wrapPrivateKey: true,
allowInfinityPoint: true, allowInfinityPoint: true,
@ -1175,9 +1260,9 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
const x_1 = slc(bytes, 0, L); const x_1 = slc(bytes, 0, L);
const x_0 = slc(bytes, L, 2 * L); const x_0 = slc(bytes, L, 2 * L);
const x = Fp2.create({ c0: Fp.create(x_0), c1: Fp.create(x_1) }); const x = Fp2.create({ c0: Fp.create(x_0), c1: Fp.create(x_1) });
const right = Fp2.add(Fp2.pow(x, 3n), b); // y² = x³ + 4 * (u+1) = x³ + b const right = Fp2.add(Fp2.pow(x, _3n), b); // y² = x³ + 4 * (u+1) = x³ + b
let y = Fp2.sqrt(right); let y = Fp2.sqrt(right);
const Y_bit = y.c1 === 0n ? (y.c0 * 2n) / P : (y.c1 * 2n) / P ? 1n : 0n; const Y_bit = y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P ? _1n : _0n;
y = bitS > 0 && Y_bit > 0 ? y : Fp2.neg(y); y = bitS > 0 && Y_bit > 0 ? y : Fp2.neg(y);
return { x, y }; return { x, y };
} else if (bytes.length === 192 && !bitC) { } else if (bytes.length === 192 && !bitC) {
@ -1200,7 +1285,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
if (isCompressed) { if (isCompressed) {
const P = Fp.ORDER; const P = Fp.ORDER;
if (isZero) return concatB(COMPRESSED_ZERO, numberToBytesBE(0n, Fp.BYTES)); if (isZero) return concatB(COMPRESSED_ZERO, numberToBytesBE(0n, Fp.BYTES));
const flag = Boolean(y.c1 === 0n ? (y.c0 * 2n) / P : (y.c1 * 2n) / P); const flag = Boolean(y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P);
// set compressed & sign bits (looks like different offsets than for G1/Fp?) // set compressed & sign bits (looks like different offsets than for G1/Fp?)
let x_1 = bitSet(x.c1, C_BIT_POS, flag); let x_1 = bitSet(x.c1, C_BIT_POS, flag);
x_1 = bitSet(x_1, S_BIT_POS, true); x_1 = bitSet(x_1, S_BIT_POS, true);
@ -1229,12 +1314,12 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
const z2 = bytesToNumberBE(hex.slice(half)); const z2 = bytesToNumberBE(hex.slice(half));
// Indicates the infinity point // Indicates the infinity point
const bflag1 = bitGet(z1, I_BIT_POS); const bflag1 = bitGet(z1, I_BIT_POS);
if (bflag1 === 1n) return bls12_381.G2.ProjectivePoint.ZERO; if (bflag1 === _1n) return bls12_381.G2.ProjectivePoint.ZERO;
const x1 = Fp.create(z1 & Fp.MASK); const x1 = Fp.create(z1 & Fp.MASK);
const x2 = Fp.create(z2); const x2 = Fp.create(z2);
const x = Fp2.create({ c0: x2, c1: x1 }); const x = Fp2.create({ c0: x2, c1: x1 });
const y2 = Fp2.add(Fp2.pow(x, 3n), bls12_381.CURVE.G2.b); // y² = x³ + 4 const y2 = Fp2.add(Fp2.pow(x, _3n), bls12_381.CURVE.G2.b); // y² = x³ + 4
// The slow part // The slow part
let y = Fp2.sqrt(y2); let y = Fp2.sqrt(y2);
if (!y) throw new Error('Failed to find a square root'); if (!y) throw new Error('Failed to find a square root');
@ -1243,8 +1328,8 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
// If y1 happens to be zero, then use the bit of y0 // If y1 happens to be zero, then use the bit of y0
const { re: y0, im: y1 } = Fp2.reim(y); const { re: y0, im: y1 } = Fp2.reim(y);
const aflag1 = bitGet(z1, 381); const aflag1 = bitGet(z1, 381);
const isGreater = y1 > 0n && (y1 * 2n) / P !== aflag1; const isGreater = y1 > _0n && (y1 * _2n) / P !== aflag1;
const isZero = y1 === 0n && (y0 * 2n) / P !== aflag1; const isZero = y1 === _0n && (y0 * _2n) / P !== aflag1;
if (isGreater || isZero) y = Fp2.neg(y); if (isGreater || isZero) y = Fp2.neg(y);
const point = bls12_381.G2.ProjectivePoint.fromAffine({ x, y }); const point = bls12_381.G2.ProjectivePoint.fromAffine({ x, y });
point.assertValidity(); point.assertValidity();
@ -1258,8 +1343,8 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
const a = point.toAffine(); const a = point.toAffine();
const { re: x0, im: x1 } = Fp2.reim(a.x); const { re: x0, im: x1 } = Fp2.reim(a.x);
const { re: y0, im: y1 } = Fp2.reim(a.y); const { re: y0, im: y1 } = Fp2.reim(a.y);
const tmp = y1 > 0n ? y1 * 2n : y0 * 2n; const tmp = y1 > _0n ? y1 * _2n : y0 * _2n;
const aflag1 = Boolean((tmp / Fp.ORDER) & 1n); const aflag1 = Boolean((tmp / Fp.ORDER) & _1n);
const z1 = bitSet(bitSet(x1, 381, aflag1), S_BIT_POS, true); const z1 = bitSet(bitSet(x1, 381, aflag1), S_BIT_POS, true);
const z2 = x0; const z2 = x0;
return concatB(numberToBytesBE(z1, Fp.BYTES), numberToBytesBE(z2, Fp.BYTES)); return concatB(numberToBytesBE(z1, Fp.BYTES), numberToBytesBE(z2, Fp.BYTES));