@noble/curves 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +125 -191
- package/abstract/bls.d.ts +27 -10
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +58 -8
- package/abstract/bls.js.map +1 -1
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.js.map +1 -1
- package/abstract/hash-to-curve.d.ts +1 -1
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +8 -8
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +5 -7
- package/abstract/montgomery.js.map +1 -1
- package/abstract/poseidon.js.map +1 -1
- package/abstract/utils.d.ts +2 -1
- package/abstract/utils.d.ts.map +1 -1
- package/abstract/utils.js +55 -31
- package/abstract/utils.js.map +1 -1
- package/abstract/weierstrass.d.ts +23 -27
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +4 -4
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +137 -82
- package/bls12-381.js.map +1 -1
- package/bn254.d.ts +3 -2
- package/bn254.d.ts.map +1 -1
- package/bn254.js +3 -2
- package/bn254.js.map +1 -1
- package/ed25519.d.ts +4 -2
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +8 -2
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +4 -2
- package/ed448.d.ts.map +1 -1
- package/ed448.js +10 -1
- package/ed448.js.map +1 -1
- package/esm/abstract/bls.js +58 -8
- package/esm/abstract/bls.js.map +1 -1
- package/esm/abstract/curve.js.map +1 -1
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/hash-to-curve.js +9 -9
- package/esm/abstract/hash-to-curve.js.map +1 -1
- package/esm/abstract/modular.js.map +1 -1
- package/esm/abstract/montgomery.js +5 -7
- package/esm/abstract/montgomery.js.map +1 -1
- package/esm/abstract/poseidon.js.map +1 -1
- package/esm/abstract/utils.js +53 -30
- package/esm/abstract/utils.js.map +1 -1
- package/esm/abstract/weierstrass.js +4 -4
- package/esm/abstract/weierstrass.js.map +1 -1
- package/esm/bls12-381.js +138 -83
- package/esm/bls12-381.js.map +1 -1
- package/esm/bn254.js +3 -2
- package/esm/bn254.js.map +1 -1
- package/esm/ed25519.js +8 -2
- package/esm/ed25519.js.map +1 -1
- package/esm/ed448.js +10 -1
- package/esm/ed448.js.map +1 -1
- package/esm/jubjub.js.map +1 -1
- package/esm/p256.js +2 -2
- package/esm/p256.js.map +1 -1
- package/esm/p384.js +2 -2
- package/esm/p384.js.map +1 -1
- package/esm/p521.js +3 -3
- package/esm/p521.js.map +1 -1
- package/esm/secp256k1.js +6 -6
- package/esm/secp256k1.js.map +1 -1
- package/jubjub.js.map +1 -1
- package/p256.js +2 -2
- package/p256.js.map +1 -1
- package/p384.js +2 -2
- package/p384.js.map +1 -1
- package/p521.js +3 -3
- package/p521.js.map +1 -1
- package/package.json +5 -5
- package/secp256k1.js +6 -6
- package/secp256k1.js.map +1 -1
- package/src/abstract/bls.ts +117 -19
- package/src/abstract/hash-to-curve.ts +10 -9
- package/src/abstract/montgomery.ts +4 -6
- package/src/abstract/utils.ts +52 -26
- package/src/abstract/weierstrass.ts +16 -7
- package/src/bls12-381.ts +127 -69
- package/src/bn254.ts +3 -2
- package/src/ed25519.ts +10 -2
- package/src/ed448.ts +18 -3
package/esm/bls12-381.js
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
|
-
// bls12-381 pairing-friendly Barreto-Lynn-Scott elliptic curve construction
|
|
3
|
-
// - Construct zk-SNARKs at the
|
|
4
|
-
// -
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// The library uses G1 for public keys and G2 for signatures. Support for G1 signatures is planned.
|
|
8
|
-
// Compatible with Algorand, Chia, Dfinity, Ethereum, FIL, Zcash. Matches specs
|
|
9
|
-
// [pairing-curves-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
|
|
10
|
-
// [bls-sigs-04](https:/cfrg-hash-to/tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04),
|
|
11
|
-
// [hash-to-curve-12](https://tools.ietf.org/html/draft-irtf--curve-12).
|
|
2
|
+
// bls12-381 is pairing-friendly Barreto-Lynn-Scott elliptic curve construction allowing to:
|
|
3
|
+
// - Construct zk-SNARKs at the 120-bit security
|
|
4
|
+
// - Efficiently verify N aggregate signatures with 1 pairing and N ec additions:
|
|
5
|
+
// the Boneh-Lynn-Shacham signature scheme is orders of magnitude more efficient than Schnorr
|
|
12
6
|
//
|
|
13
7
|
// ### Summary
|
|
14
8
|
// 1. BLS Relies on Bilinear Pairing (expensive)
|
|
@@ -24,13 +18,22 @@
|
|
|
24
18
|
// - `S = pk x H(m)` - signing
|
|
25
19
|
// - `e(P, H(m)) == e(G, S)` - verification using pairings
|
|
26
20
|
// - `e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))` - signature aggregation
|
|
27
|
-
//
|
|
28
|
-
//
|
|
21
|
+
//
|
|
22
|
+
// ### Compatibility and notes
|
|
23
|
+
// 1. It is compatible with Algorand, Chia, Dfinity, Ethereum, Filecoin, ZEC
|
|
24
|
+
// Filecoin uses little endian byte arrays for private keys - make sure to reverse byte order.
|
|
25
|
+
// 2. Some projects use G2 for public keys and G1 for signatures. It's called "short signature"
|
|
26
|
+
// 3. Curve security level is about 120 bits as per Barbulescu-Duquesne 2017
|
|
27
|
+
// https://hal.science/hal-01534101/file/main.pdf
|
|
28
|
+
// 4. Compatible with specs:
|
|
29
|
+
// [cfrg-pairing-friendly-curves-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
|
|
30
|
+
// [cfrg-bls-signature-05](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-05),
|
|
31
|
+
// [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380).
|
|
29
32
|
import { sha256 } from '@noble/hashes/sha256';
|
|
30
33
|
import { randomBytes } from '@noble/hashes/utils';
|
|
31
34
|
import { bls } from './abstract/bls.js';
|
|
32
35
|
import * as mod from './abstract/modular.js';
|
|
33
|
-
import { concatBytes as concatB, ensureBytes, numberToBytesBE, bytesToNumberBE, bitLen,
|
|
36
|
+
import { concatBytes as concatB, ensureBytes, numberToBytesBE, bytesToNumberBE, bitLen, bitGet, bitMask, bytesToHex, } from './abstract/utils.js';
|
|
34
37
|
// Types
|
|
35
38
|
import { mapToCurveSimpleSWU, } from './abstract/weierstrass.js';
|
|
36
39
|
import { isogenyMap } from './abstract/hash-to-curve.js';
|
|
@@ -257,14 +260,14 @@ const Fp6Square = ({ c0, c1, c2 }) => {
|
|
|
257
260
|
let t3 = Fp2.mul(Fp2.mul(c1, c2), _2n); // 2 * c1 * c2
|
|
258
261
|
let t4 = Fp2.sqr(c2); // c2²
|
|
259
262
|
return {
|
|
260
|
-
c0: Fp2.add(Fp2.mulByNonresidue(t3), t0),
|
|
261
|
-
c1: Fp2.add(Fp2.mulByNonresidue(t4), t1),
|
|
263
|
+
c0: Fp2.add(Fp2.mulByNonresidue(t3), t0), // T3 * (u + 1) + T0
|
|
264
|
+
c1: Fp2.add(Fp2.mulByNonresidue(t4), t1), // T4 * (u + 1) + T1
|
|
262
265
|
// T1 + (c0 - c1 + c2)² + T3 - T0 - T4
|
|
263
266
|
c2: Fp2.sub(Fp2.sub(Fp2.add(Fp2.add(t1, Fp2.sqr(Fp2.add(Fp2.sub(c0, c1), c2))), t3), t0), t4),
|
|
264
267
|
};
|
|
265
268
|
};
|
|
266
269
|
const Fp6 = {
|
|
267
|
-
ORDER: Fp2.ORDER,
|
|
270
|
+
ORDER: Fp2.ORDER, // TODO: unused, but need to verify
|
|
268
271
|
BITS: 3 * Fp2.BITS,
|
|
269
272
|
BYTES: 3 * Fp2.BYTES,
|
|
270
273
|
MASK: bitMask(3 * Fp2.BITS),
|
|
@@ -424,7 +427,7 @@ const Fp12Multiply = ({ c0, c1 }, rhs) => {
|
|
|
424
427
|
let t1 = Fp6.mul(c0, r0); // c0 * r0
|
|
425
428
|
let t2 = Fp6.mul(c1, r1); // c1 * r1
|
|
426
429
|
return {
|
|
427
|
-
c0: Fp6.add(t1, Fp6.mulByNonresidue(t2)),
|
|
430
|
+
c0: Fp6.add(t1, Fp6.mulByNonresidue(t2)), // T1 + T2 * v
|
|
428
431
|
// (c0 + c1) * (r0 + r1) - (T1 + T2)
|
|
429
432
|
c1: Fp6.sub(Fp6.mul(Fp6.add(c0, c1), Fp6.add(r0, r1)), Fp6.add(t1, t2)),
|
|
430
433
|
};
|
|
@@ -441,12 +444,12 @@ function Fp4Square(a, b) {
|
|
|
441
444
|
const a2 = Fp2.sqr(a);
|
|
442
445
|
const b2 = Fp2.sqr(b);
|
|
443
446
|
return {
|
|
444
|
-
first: Fp2.add(Fp2.mulByNonresidue(b2), a2),
|
|
447
|
+
first: Fp2.add(Fp2.mulByNonresidue(b2), a2), // b² * Nonresidue + a²
|
|
445
448
|
second: Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(a, b)), a2), b2), // (a + b)² - a² - b²
|
|
446
449
|
};
|
|
447
450
|
}
|
|
448
451
|
const Fp12 = {
|
|
449
|
-
ORDER: Fp2.ORDER,
|
|
452
|
+
ORDER: Fp2.ORDER, // TODO: unused, but need to verify
|
|
450
453
|
BITS: 2 * Fp2.BITS,
|
|
451
454
|
BYTES: 2 * Fp2.BYTES,
|
|
452
455
|
MASK: bitMask(2 * Fp2.BITS),
|
|
@@ -521,7 +524,7 @@ const Fp12 = {
|
|
|
521
524
|
let t0 = Fp6.multiplyBy01(c0, o0, o1);
|
|
522
525
|
let t1 = Fp6.multiplyBy1(c1, o4);
|
|
523
526
|
return {
|
|
524
|
-
c0: Fp6.add(Fp6.mulByNonresidue(t1), t0),
|
|
527
|
+
c0: Fp6.add(Fp6.mulByNonresidue(t1), t0), // T1 * v + T0
|
|
525
528
|
// (c1 + c0) * [o0, o1+o4] - T0 - T1
|
|
526
529
|
c1: Fp6.sub(Fp6.sub(Fp6.multiplyBy01(Fp6.add(c1, c0), o0, Fp2.add(o1, o4)), t0), t1),
|
|
527
530
|
};
|
|
@@ -544,13 +547,13 @@ const Fp12 = {
|
|
|
544
547
|
let t9 = Fp2.mulByNonresidue(t8); // T8 * (u + 1)
|
|
545
548
|
return {
|
|
546
549
|
c0: Fp6.create({
|
|
547
|
-
c0: Fp2.add(Fp2.mul(Fp2.sub(t3, c0c0), _2n), t3),
|
|
548
|
-
c1: Fp2.add(Fp2.mul(Fp2.sub(t5, c0c1), _2n), t5),
|
|
550
|
+
c0: Fp2.add(Fp2.mul(Fp2.sub(t3, c0c0), _2n), t3), // 2 * (T3 - c0c0) + T3
|
|
551
|
+
c1: Fp2.add(Fp2.mul(Fp2.sub(t5, c0c1), _2n), t5), // 2 * (T5 - c0c1) + T5
|
|
549
552
|
c2: Fp2.add(Fp2.mul(Fp2.sub(t7, c0c2), _2n), t7),
|
|
550
|
-
}),
|
|
553
|
+
}), // 2 * (T7 - c0c2) + T7
|
|
551
554
|
c1: Fp6.create({
|
|
552
|
-
c0: Fp2.add(Fp2.mul(Fp2.add(t9, c1c0), _2n), t9),
|
|
553
|
-
c1: Fp2.add(Fp2.mul(Fp2.add(t4, c1c1), _2n), t4),
|
|
555
|
+
c0: Fp2.add(Fp2.mul(Fp2.add(t9, c1c0), _2n), t9), // 2 * (T9 + c1c0) + T9
|
|
556
|
+
c1: Fp2.add(Fp2.mul(Fp2.add(t4, c1c1), _2n), t4), // 2 * (T4 + c1c1) + T4
|
|
554
557
|
c2: Fp2.add(Fp2.mul(Fp2.add(t6, c1c2), _2n), t6),
|
|
555
558
|
}),
|
|
556
559
|
}; // 2 * (T6 + c1c2) + T6
|
|
@@ -776,8 +779,8 @@ const isogenyMapG1 = isogenyMap(Fp, [
|
|
|
776
779
|
].map((i) => i.map((j) => BigInt(j))));
|
|
777
780
|
// SWU Map - Fp2 to G2': y² = x³ + 240i * x + 1012 + 1012i
|
|
778
781
|
const G2_SWU = mapToCurveSimpleSWU(Fp2, {
|
|
779
|
-
A: Fp2.create({ c0: Fp.create(_0n), c1: Fp.create(BigInt(240)) }),
|
|
780
|
-
B: Fp2.create({ c0: Fp.create(BigInt(1012)), c1: Fp.create(BigInt(1012)) }),
|
|
782
|
+
A: Fp2.create({ c0: Fp.create(_0n), c1: Fp.create(BigInt(240)) }), // A' = 240 * I
|
|
783
|
+
B: Fp2.create({ c0: Fp.create(BigInt(1012)), c1: Fp.create(BigInt(1012)) }), // B' = 1012 * (1 + I)
|
|
781
784
|
Z: Fp2.create({ c0: Fp.create(BigInt(-2)), c1: Fp.create(BigInt(-1)) }), // Z: -(2 + I)
|
|
782
785
|
});
|
|
783
786
|
// Optimized SWU Map - Fp to G1
|
|
@@ -850,11 +853,39 @@ const htfDefaults = Object.freeze({
|
|
|
850
853
|
});
|
|
851
854
|
// Encoding utils
|
|
852
855
|
// Point on G1 curve: (x, y)
|
|
853
|
-
const C_BIT_POS = Fp.BITS; // C_bit, compression bit for serialization flag
|
|
854
|
-
const I_BIT_POS = Fp.BITS + 1; // I_bit, point-at-infinity bit for serialization flag
|
|
855
|
-
const S_BIT_POS = Fp.BITS + 2; // S_bit, sign bit for serialization flag
|
|
856
856
|
// Compressed point of infinity
|
|
857
|
-
const COMPRESSED_ZERO = Fp.toBytes(
|
|
857
|
+
const COMPRESSED_ZERO = setMask(Fp.toBytes(_0n), { infinity: true, compressed: true }); // set compressed & point-at-infinity bits
|
|
858
|
+
function parseMask(bytes) {
|
|
859
|
+
// Copy, so we can remove mask data. It will be removed also later, when Fp.create will call modulo.
|
|
860
|
+
bytes = bytes.slice();
|
|
861
|
+
const mask = bytes[0] & 224;
|
|
862
|
+
const compressed = !!((mask >> 7) & 1); // compression bit (0b1000_0000)
|
|
863
|
+
const infinity = !!((mask >> 6) & 1); // point at infinity bit (0b0100_0000)
|
|
864
|
+
const sort = !!((mask >> 5) & 1); // sort bit (0b0010_0000)
|
|
865
|
+
bytes[0] &= 31; // clear mask (zero first 3 bits)
|
|
866
|
+
return { compressed, infinity, sort, value: bytes };
|
|
867
|
+
}
|
|
868
|
+
function setMask(bytes, mask) {
|
|
869
|
+
if (bytes[0] & 224)
|
|
870
|
+
throw new Error('setMask: non-empty mask');
|
|
871
|
+
if (mask.compressed)
|
|
872
|
+
bytes[0] |= 128;
|
|
873
|
+
if (mask.infinity)
|
|
874
|
+
bytes[0] |= 64;
|
|
875
|
+
if (mask.sort)
|
|
876
|
+
bytes[0] |= 32;
|
|
877
|
+
return bytes;
|
|
878
|
+
}
|
|
879
|
+
function signatureG1ToRawBytes(point) {
|
|
880
|
+
point.assertValidity();
|
|
881
|
+
const isZero = point.equals(bls12_381.G1.ProjectivePoint.ZERO);
|
|
882
|
+
const { x, y } = point.toAffine();
|
|
883
|
+
if (isZero)
|
|
884
|
+
return COMPRESSED_ZERO.slice();
|
|
885
|
+
const P = Fp.ORDER;
|
|
886
|
+
const sort = Boolean((y * _2n) / P);
|
|
887
|
+
return setMask(numberToBytesBE(x, Fp.BYTES), { compressed: true, sort });
|
|
888
|
+
}
|
|
858
889
|
function signatureG2ToRawBytes(point) {
|
|
859
890
|
// NOTE: by some reasons it was missed in bls12-381, looks like bug
|
|
860
891
|
point.assertValidity();
|
|
@@ -865,10 +896,9 @@ function signatureG2ToRawBytes(point) {
|
|
|
865
896
|
const { re: x0, im: x1 } = Fp2.reim(x);
|
|
866
897
|
const { re: y0, im: y1 } = Fp2.reim(y);
|
|
867
898
|
const tmp = y1 > _0n ? y1 * _2n : y0 * _2n;
|
|
868
|
-
const
|
|
869
|
-
const z1 = bitSet(bitSet(x1, 381, aflag1), S_BIT_POS, true);
|
|
899
|
+
const sort = Boolean((tmp / Fp.ORDER) & _1n);
|
|
870
900
|
const z2 = x0;
|
|
871
|
-
return concatB(numberToBytesBE(
|
|
901
|
+
return concatB(setMask(numberToBytesBE(x1, len), { sort, compressed: true }), numberToBytesBE(z2, len));
|
|
872
902
|
}
|
|
873
903
|
// To verify curve parameters, see pairing-friendly-curves spec:
|
|
874
904
|
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-11
|
|
@@ -902,7 +932,7 @@ export const bls12_381 = bls({
|
|
|
902
932
|
Gy: BigInt('0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'),
|
|
903
933
|
a: Fp.ZERO,
|
|
904
934
|
b: _4n,
|
|
905
|
-
htfDefaults: { ...htfDefaults, m: 1 },
|
|
935
|
+
htfDefaults: { ...htfDefaults, m: 1, DST: 'BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_' },
|
|
906
936
|
wrapPrivateKey: true,
|
|
907
937
|
allowInfinityPoint: true,
|
|
908
938
|
// Checks is the point resides in prime-order subgroup.
|
|
@@ -940,31 +970,35 @@ export const bls12_381 = bls({
|
|
|
940
970
|
return isogenyMapG1(x, y);
|
|
941
971
|
},
|
|
942
972
|
fromBytes: (bytes) => {
|
|
943
|
-
|
|
944
|
-
if (
|
|
973
|
+
const { compressed, infinity, sort, value } = parseMask(bytes);
|
|
974
|
+
if (value.length === 48 && compressed) {
|
|
945
975
|
// TODO: Fp.bytes
|
|
946
976
|
const P = Fp.ORDER;
|
|
947
|
-
const compressedValue = bytesToNumberBE(
|
|
948
|
-
const bflag = bitGet(compressedValue, I_BIT_POS);
|
|
977
|
+
const compressedValue = bytesToNumberBE(value);
|
|
949
978
|
// Zero
|
|
950
|
-
if (bflag === _1n)
|
|
951
|
-
return { x: _0n, y: _0n };
|
|
952
979
|
const x = Fp.create(compressedValue & Fp.MASK);
|
|
980
|
+
if (infinity) {
|
|
981
|
+
if (x !== _0n)
|
|
982
|
+
throw new Error('G1: non-empty compressed point at infinity');
|
|
983
|
+
return { x: _0n, y: _0n };
|
|
984
|
+
}
|
|
953
985
|
const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381.params.G1b)); // y² = x³ + b
|
|
954
986
|
let y = Fp.sqrt(right);
|
|
955
987
|
if (!y)
|
|
956
988
|
throw new Error('Invalid compressed G1 point');
|
|
957
|
-
|
|
958
|
-
if ((y * _2n) / P !== aflag)
|
|
989
|
+
if ((y * _2n) / P !== BigInt(sort))
|
|
959
990
|
y = Fp.neg(y);
|
|
960
991
|
return { x: Fp.create(x), y: Fp.create(y) };
|
|
961
992
|
}
|
|
962
|
-
else if (
|
|
993
|
+
else if (value.length === 96 && !compressed) {
|
|
963
994
|
// Check if the infinity flag is set
|
|
964
|
-
|
|
995
|
+
const x = bytesToNumberBE(value.subarray(0, Fp.BYTES));
|
|
996
|
+
const y = bytesToNumberBE(value.subarray(Fp.BYTES));
|
|
997
|
+
if (infinity) {
|
|
998
|
+
if (x !== _0n || y !== _0n)
|
|
999
|
+
throw new Error('G1: non-empty point at infinity');
|
|
965
1000
|
return bls12_381.G1.ProjectivePoint.ZERO.toAffine();
|
|
966
|
-
|
|
967
|
-
const y = bytesToNumberBE(bytes.subarray(Fp.BYTES));
|
|
1001
|
+
}
|
|
968
1002
|
return { x: Fp.create(x), y: Fp.create(y) };
|
|
969
1003
|
}
|
|
970
1004
|
else {
|
|
@@ -978,10 +1012,8 @@ export const bls12_381 = bls({
|
|
|
978
1012
|
if (isZero)
|
|
979
1013
|
return COMPRESSED_ZERO.slice();
|
|
980
1014
|
const P = Fp.ORDER;
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
num = bitSet(num, S_BIT_POS, true);
|
|
984
|
-
return numberToBytesBE(num, Fp.BYTES);
|
|
1015
|
+
const sort = Boolean((y * _2n) / P);
|
|
1016
|
+
return setMask(numberToBytesBE(x, Fp.BYTES), { compressed: true, sort });
|
|
985
1017
|
}
|
|
986
1018
|
else {
|
|
987
1019
|
if (isZero) {
|
|
@@ -994,6 +1026,33 @@ export const bls12_381 = bls({
|
|
|
994
1026
|
}
|
|
995
1027
|
}
|
|
996
1028
|
},
|
|
1029
|
+
ShortSignature: {
|
|
1030
|
+
fromHex(hex) {
|
|
1031
|
+
const { infinity, sort, value } = parseMask(ensureBytes('signatureHex', hex, 48));
|
|
1032
|
+
const P = Fp.ORDER;
|
|
1033
|
+
const compressedValue = bytesToNumberBE(value);
|
|
1034
|
+
// Zero
|
|
1035
|
+
if (infinity)
|
|
1036
|
+
return bls12_381.G1.ProjectivePoint.ZERO;
|
|
1037
|
+
const x = Fp.create(compressedValue & Fp.MASK);
|
|
1038
|
+
const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381.params.G1b)); // y² = x³ + b
|
|
1039
|
+
let y = Fp.sqrt(right);
|
|
1040
|
+
if (!y)
|
|
1041
|
+
throw new Error('Invalid compressed G1 point');
|
|
1042
|
+
const aflag = BigInt(sort);
|
|
1043
|
+
if ((y * _2n) / P !== aflag)
|
|
1044
|
+
y = Fp.neg(y);
|
|
1045
|
+
const point = bls12_381.G1.ProjectivePoint.fromAffine({ x, y });
|
|
1046
|
+
point.assertValidity();
|
|
1047
|
+
return point;
|
|
1048
|
+
},
|
|
1049
|
+
toRawBytes(point) {
|
|
1050
|
+
return signatureG1ToRawBytes(point);
|
|
1051
|
+
},
|
|
1052
|
+
toHex(point) {
|
|
1053
|
+
return bytesToHex(signatureG1ToRawBytes(point));
|
|
1054
|
+
},
|
|
1055
|
+
},
|
|
997
1056
|
},
|
|
998
1057
|
// G2 is the order-q subgroup of E2(Fp²) : y² = x³+4(1+√−1),
|
|
999
1058
|
// where Fp2 is Fp[√−1]/(x2+1). #E2(Fp2 ) = h2q, where
|
|
@@ -1053,45 +1112,45 @@ export const bls12_381 = bls({
|
|
|
1053
1112
|
return Q; // [x²-x-1]P + [x-1]Ψ(P) + Ψ²(2P)
|
|
1054
1113
|
},
|
|
1055
1114
|
fromBytes: (bytes) => {
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1115
|
+
const { compressed, infinity, sort, value } = parseMask(bytes);
|
|
1116
|
+
if ((!compressed && !infinity && sort) || // 00100000
|
|
1117
|
+
(!compressed && infinity && sort) || // 01100000
|
|
1118
|
+
(sort && infinity && compressed) // 11100000
|
|
1119
|
+
) {
|
|
1120
|
+
throw new Error('Invalid encoding flag: ' + (bytes[0] & 224));
|
|
1060
1121
|
}
|
|
1061
|
-
const bitC = m_byte & 0x80; // compression bit
|
|
1062
|
-
const bitI = m_byte & 0x40; // point at infinity bit
|
|
1063
|
-
const bitS = m_byte & 0x20; // sign bit
|
|
1064
1122
|
const L = Fp.BYTES;
|
|
1065
1123
|
const slc = (b, from, to) => bytesToNumberBE(b.slice(from, to));
|
|
1066
|
-
if (
|
|
1124
|
+
if (value.length === 96 && compressed) {
|
|
1067
1125
|
const b = bls12_381.params.G2b;
|
|
1068
1126
|
const P = Fp.ORDER;
|
|
1069
|
-
|
|
1070
|
-
if (bitI) {
|
|
1127
|
+
if (infinity) {
|
|
1071
1128
|
// check that all bytes are 0
|
|
1072
|
-
if (
|
|
1129
|
+
if (value.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
|
|
1073
1130
|
throw new Error('Invalid compressed G2 point');
|
|
1074
1131
|
}
|
|
1075
1132
|
return { x: Fp2.ZERO, y: Fp2.ZERO };
|
|
1076
1133
|
}
|
|
1077
|
-
const x_1 = slc(
|
|
1078
|
-
const x_0 = slc(
|
|
1134
|
+
const x_1 = slc(value, 0, L);
|
|
1135
|
+
const x_0 = slc(value, L, 2 * L);
|
|
1079
1136
|
const x = Fp2.create({ c0: Fp.create(x_0), c1: Fp.create(x_1) });
|
|
1080
1137
|
const right = Fp2.add(Fp2.pow(x, _3n), b); // y² = x³ + 4 * (u+1) = x³ + b
|
|
1081
1138
|
let y = Fp2.sqrt(right);
|
|
1082
1139
|
const Y_bit = y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P ? _1n : _0n;
|
|
1083
|
-
y =
|
|
1140
|
+
y = sort && Y_bit > 0 ? y : Fp2.neg(y);
|
|
1084
1141
|
return { x, y };
|
|
1085
1142
|
}
|
|
1086
|
-
else if (
|
|
1087
|
-
|
|
1088
|
-
|
|
1143
|
+
else if (value.length === 192 && !compressed) {
|
|
1144
|
+
if (infinity) {
|
|
1145
|
+
if (value.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
|
|
1146
|
+
throw new Error('Invalid uncompressed G2 point');
|
|
1147
|
+
}
|
|
1089
1148
|
return { x: Fp2.ZERO, y: Fp2.ZERO };
|
|
1090
1149
|
}
|
|
1091
|
-
const x1 = slc(
|
|
1092
|
-
const x0 = slc(
|
|
1093
|
-
const y1 = slc(
|
|
1094
|
-
const y0 = slc(
|
|
1150
|
+
const x1 = slc(value, 0, L);
|
|
1151
|
+
const x0 = slc(value, L, 2 * L);
|
|
1152
|
+
const y1 = slc(value, 2 * L, 3 * L);
|
|
1153
|
+
const y0 = slc(value, 3 * L, 4 * L);
|
|
1095
1154
|
return { x: Fp2.fromBigTuple([x0, x1]), y: Fp2.fromBigTuple([y0, y1]) };
|
|
1096
1155
|
}
|
|
1097
1156
|
else {
|
|
@@ -1106,10 +1165,7 @@ export const bls12_381 = bls({
|
|
|
1106
1165
|
if (isZero)
|
|
1107
1166
|
return concatB(COMPRESSED_ZERO, numberToBytesBE(_0n, len));
|
|
1108
1167
|
const flag = Boolean(y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P);
|
|
1109
|
-
|
|
1110
|
-
let x_1 = bitSet(x.c1, C_BIT_POS, flag);
|
|
1111
|
-
x_1 = bitSet(x_1, S_BIT_POS, true);
|
|
1112
|
-
return concatB(numberToBytesBE(x_1, len), numberToBytesBE(x.c0, len));
|
|
1168
|
+
return concatB(setMask(numberToBytesBE(x.c1, len), { compressed: true, sort: flag }), numberToBytesBE(x.c0, len));
|
|
1113
1169
|
}
|
|
1114
1170
|
else {
|
|
1115
1171
|
if (isZero)
|
|
@@ -1122,16 +1178,15 @@ export const bls12_381 = bls({
|
|
|
1122
1178
|
Signature: {
|
|
1123
1179
|
// TODO: Optimize, it's very slow because of sqrt.
|
|
1124
1180
|
fromHex(hex) {
|
|
1125
|
-
|
|
1181
|
+
const { infinity, sort, value } = parseMask(ensureBytes('signatureHex', hex));
|
|
1126
1182
|
const P = Fp.ORDER;
|
|
1127
1183
|
const half = hex.length / 2;
|
|
1128
1184
|
if (half !== 48 && half !== 96)
|
|
1129
1185
|
throw new Error('Invalid compressed signature length, must be 96 or 192');
|
|
1130
|
-
const z1 = bytesToNumberBE(
|
|
1131
|
-
const z2 = bytesToNumberBE(
|
|
1186
|
+
const z1 = bytesToNumberBE(value.slice(0, half));
|
|
1187
|
+
const z2 = bytesToNumberBE(value.slice(half));
|
|
1132
1188
|
// Indicates the infinity point
|
|
1133
|
-
|
|
1134
|
-
if (bflag1 === _1n)
|
|
1189
|
+
if (infinity)
|
|
1135
1190
|
return bls12_381.G2.ProjectivePoint.ZERO;
|
|
1136
1191
|
const x1 = Fp.create(z1 & Fp.MASK);
|
|
1137
1192
|
const x2 = Fp.create(z2);
|
|
@@ -1144,7 +1199,7 @@ export const bls12_381 = bls({
|
|
|
1144
1199
|
// Choose the y whose leftmost bit of the imaginary part is equal to the a_flag1
|
|
1145
1200
|
// If y1 happens to be zero, then use the bit of y0
|
|
1146
1201
|
const { re: y0, im: y1 } = Fp2.reim(y);
|
|
1147
|
-
const aflag1 =
|
|
1202
|
+
const aflag1 = BigInt(sort);
|
|
1148
1203
|
const isGreater = y1 > _0n && (y1 * _2n) / P !== aflag1;
|
|
1149
1204
|
const isZero = y1 === _0n && (y0 * _2n) / P !== aflag1;
|
|
1150
1205
|
if (isGreater || isZero)
|
|
@@ -1162,7 +1217,7 @@ export const bls12_381 = bls({
|
|
|
1162
1217
|
},
|
|
1163
1218
|
},
|
|
1164
1219
|
params: {
|
|
1165
|
-
x: BLS_X,
|
|
1220
|
+
x: BLS_X, // The BLS parameter x for BLS12-381
|
|
1166
1221
|
r: Fr.ORDER, // order; z⁴ − z² + 1; CURVE.n from other curves
|
|
1167
1222
|
},
|
|
1168
1223
|
htfDefaults,
|