@noble/curves 1.2.0 → 1.4.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.
Files changed (92) hide show
  1. package/README.md +143 -194
  2. package/abstract/bls.d.ts +29 -12
  3. package/abstract/bls.d.ts.map +1 -1
  4. package/abstract/bls.js +58 -8
  5. package/abstract/bls.js.map +1 -1
  6. package/abstract/curve.js.map +1 -1
  7. package/abstract/edwards.js.map +1 -1
  8. package/abstract/hash-to-curve.d.ts +1 -1
  9. package/abstract/hash-to-curve.d.ts.map +1 -1
  10. package/abstract/hash-to-curve.js +10 -21
  11. package/abstract/hash-to-curve.js.map +1 -1
  12. package/abstract/modular.js.map +1 -1
  13. package/abstract/montgomery.d.ts.map +1 -1
  14. package/abstract/montgomery.js +5 -7
  15. package/abstract/montgomery.js.map +1 -1
  16. package/abstract/poseidon.js.map +1 -1
  17. package/abstract/utils.d.ts +4 -2
  18. package/abstract/utils.d.ts.map +1 -1
  19. package/abstract/utils.js +61 -36
  20. package/abstract/utils.js.map +1 -1
  21. package/abstract/weierstrass.d.ts +24 -28
  22. package/abstract/weierstrass.d.ts.map +1 -1
  23. package/abstract/weierstrass.js +13 -7
  24. package/abstract/weierstrass.js.map +1 -1
  25. package/bls12-381.d.ts.map +1 -1
  26. package/bls12-381.js +138 -83
  27. package/bls12-381.js.map +1 -1
  28. package/bn254.d.ts +3 -2
  29. package/bn254.d.ts.map +1 -1
  30. package/bn254.js +3 -2
  31. package/bn254.js.map +1 -1
  32. package/ed25519.d.ts +4 -2
  33. package/ed25519.d.ts.map +1 -1
  34. package/ed25519.js +8 -2
  35. package/ed25519.js.map +1 -1
  36. package/ed448.d.ts +4 -2
  37. package/ed448.d.ts.map +1 -1
  38. package/ed448.js +10 -1
  39. package/ed448.js.map +1 -1
  40. package/esm/abstract/bls.js +58 -8
  41. package/esm/abstract/bls.js.map +1 -1
  42. package/esm/abstract/curve.js.map +1 -1
  43. package/esm/abstract/edwards.js.map +1 -1
  44. package/esm/abstract/hash-to-curve.js +11 -22
  45. package/esm/abstract/hash-to-curve.js.map +1 -1
  46. package/esm/abstract/modular.js.map +1 -1
  47. package/esm/abstract/montgomery.js +5 -7
  48. package/esm/abstract/montgomery.js.map +1 -1
  49. package/esm/abstract/poseidon.js.map +1 -1
  50. package/esm/abstract/utils.js +58 -35
  51. package/esm/abstract/utils.js.map +1 -1
  52. package/esm/abstract/weierstrass.js +13 -7
  53. package/esm/abstract/weierstrass.js.map +1 -1
  54. package/esm/bls12-381.js +139 -84
  55. package/esm/bls12-381.js.map +1 -1
  56. package/esm/bn254.js +3 -2
  57. package/esm/bn254.js.map +1 -1
  58. package/esm/ed25519.js +8 -2
  59. package/esm/ed25519.js.map +1 -1
  60. package/esm/ed448.js +10 -1
  61. package/esm/ed448.js.map +1 -1
  62. package/esm/index.js +1 -1
  63. package/esm/index.js.map +1 -1
  64. package/esm/jubjub.js.map +1 -1
  65. package/esm/p256.js +2 -2
  66. package/esm/p256.js.map +1 -1
  67. package/esm/p384.js +2 -2
  68. package/esm/p384.js.map +1 -1
  69. package/esm/p521.js +3 -3
  70. package/esm/p521.js.map +1 -1
  71. package/esm/secp256k1.js +6 -6
  72. package/esm/secp256k1.js.map +1 -1
  73. package/jubjub.js.map +1 -1
  74. package/p256.js +2 -2
  75. package/p256.js.map +1 -1
  76. package/p384.js +2 -2
  77. package/p384.js.map +1 -1
  78. package/p521.js +3 -3
  79. package/p521.js.map +1 -1
  80. package/package.json +7 -7
  81. package/secp256k1.js +6 -6
  82. package/secp256k1.js.map +1 -1
  83. package/src/abstract/bls.ts +119 -21
  84. package/src/abstract/hash-to-curve.ts +12 -20
  85. package/src/abstract/montgomery.ts +4 -6
  86. package/src/abstract/utils.ts +57 -28
  87. package/src/abstract/weierstrass.ts +25 -10
  88. package/src/bls12-381.ts +128 -70
  89. package/src/bn254.ts +3 -2
  90. package/src/ed25519.ts +10 -2
  91. package/src/ed448.ts +18 -3
  92. package/src/package.json +3 -0
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 allows to:
3
- // - Construct zk-SNARKs at the 128-bit security
4
- // - Use threshold signatures, which allows a user to sign lots of messages with one signature and
5
- // verify them swiftly in a batch, using Boneh-Lynn-Shacham signature scheme.
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
- // Filecoin uses little endian byte arrays for private keys -
28
- // so ensure to reverse byte order if you'll use it with FIL.
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, bitSet, bitGet, bitMask, bytesToHex, } from './abstract/utils.js';
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(bitSet(bitSet(_0n, I_BIT_POS, true), S_BIT_POS, true)); // set compressed & point-at-infinity bits
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 aflag1 = Boolean((tmp / Fp.ORDER) & _1n);
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(z1, len), numberToBytesBE(z2, len));
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
- bytes = bytes.slice();
944
- if (bytes.length === 48) {
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(bytes);
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
- const aflag = bitGet(compressedValue, C_BIT_POS);
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 (bytes.length === 96) {
993
+ else if (value.length === 96 && !compressed) {
963
994
  // Check if the infinity flag is set
964
- if ((bytes[0] & (1 << 6)) !== 0)
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
- const x = bytesToNumberBE(bytes.subarray(0, Fp.BYTES));
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
- let num;
982
- num = bitSet(x, C_BIT_POS, Boolean((y * _2n) / P)); // set aflag
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
- bytes = bytes.slice();
1057
- const m_byte = bytes[0] & 0xe0;
1058
- if (m_byte === 0x20 || m_byte === 0x60 || m_byte === 0xe0) {
1059
- throw new Error('Invalid encoding flag: ' + m_byte);
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 (bytes.length === 96 && bitC) {
1124
+ if (value.length === 96 && compressed) {
1067
1125
  const b = bls12_381.params.G2b;
1068
1126
  const P = Fp.ORDER;
1069
- bytes[0] = bytes[0] & 0x1f; // clear flags
1070
- if (bitI) {
1127
+ if (infinity) {
1071
1128
  // check that all bytes are 0
1072
- if (bytes.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
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(bytes, 0, L);
1078
- const x_0 = slc(bytes, L, 2 * L);
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 = bitS > 0 && Y_bit > 0 ? y : Fp2.neg(y);
1140
+ y = sort && Y_bit > 0 ? y : Fp2.neg(y);
1084
1141
  return { x, y };
1085
1142
  }
1086
- else if (bytes.length === 192 && !bitC) {
1087
- // Check if the infinity flag is set
1088
- if ((bytes[0] & (1 << 6)) !== 0) {
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(bytes, 0, L);
1092
- const x0 = slc(bytes, L, 2 * L);
1093
- const y1 = slc(bytes, 2 * L, 3 * L);
1094
- const y0 = slc(bytes, 3 * L, 4 * L);
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
- // set compressed & sign bits (looks like different offsets than for G1/Fp?)
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
- hex = ensureBytes('signatureHex', hex);
1181
+ const { infinity, sort, value } = parseMask(ensureBytes('signatureHex', hex));
1126
1182
  const P = Fp.ORDER;
1127
- const half = hex.length / 2;
1183
+ const half = value.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(hex.slice(0, half));
1131
- const z2 = bytesToNumberBE(hex.slice(half));
1186
+ const z1 = bytesToNumberBE(value.slice(0, half));
1187
+ const z2 = bytesToNumberBE(value.slice(half));
1132
1188
  // Indicates the infinity point
1133
- const bflag1 = bitGet(z1, I_BIT_POS);
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 = bitGet(z1, 381);
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,