@noble/curves 1.1.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.
Files changed (101) hide show
  1. package/README.md +295 -258
  2. package/abstract/bls.d.ts +27 -10
  3. package/abstract/bls.d.ts.map +1 -1
  4. package/abstract/bls.js +60 -10
  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 +2 -2
  9. package/abstract/hash-to-curve.d.ts.map +1 -1
  10. package/abstract/hash-to-curve.js +22 -16
  11. package/abstract/hash-to-curve.js.map +1 -1
  12. package/abstract/modular.d.ts +51 -11
  13. package/abstract/modular.d.ts.map +1 -1
  14. package/abstract/modular.js +79 -21
  15. package/abstract/modular.js.map +1 -1
  16. package/abstract/montgomery.d.ts.map +1 -1
  17. package/abstract/montgomery.js +5 -7
  18. package/abstract/montgomery.js.map +1 -1
  19. package/abstract/poseidon.d.ts.map +1 -1
  20. package/abstract/poseidon.js +39 -41
  21. package/abstract/poseidon.js.map +1 -1
  22. package/abstract/utils.d.ts +3 -1
  23. package/abstract/utils.d.ts.map +1 -1
  24. package/abstract/utils.js +56 -31
  25. package/abstract/utils.js.map +1 -1
  26. package/abstract/weierstrass.d.ts +25 -28
  27. package/abstract/weierstrass.d.ts.map +1 -1
  28. package/abstract/weierstrass.js +17 -15
  29. package/abstract/weierstrass.js.map +1 -1
  30. package/bls12-381.d.ts.map +1 -1
  31. package/bls12-381.js +142 -88
  32. package/bls12-381.js.map +1 -1
  33. package/bn254.d.ts +3 -2
  34. package/bn254.d.ts.map +1 -1
  35. package/bn254.js +3 -2
  36. package/bn254.js.map +1 -1
  37. package/ed25519.d.ts +5 -2
  38. package/ed25519.d.ts.map +1 -1
  39. package/ed25519.js +17 -8
  40. package/ed25519.js.map +1 -1
  41. package/ed448.d.ts +53 -2
  42. package/ed448.d.ts.map +1 -1
  43. package/ed448.js +216 -29
  44. package/ed448.js.map +1 -1
  45. package/esm/abstract/bls.js +61 -11
  46. package/esm/abstract/bls.js.map +1 -1
  47. package/esm/abstract/curve.js.map +1 -1
  48. package/esm/abstract/edwards.js.map +1 -1
  49. package/esm/abstract/hash-to-curve.js +23 -17
  50. package/esm/abstract/hash-to-curve.js.map +1 -1
  51. package/esm/abstract/modular.js +75 -20
  52. package/esm/abstract/modular.js.map +1 -1
  53. package/esm/abstract/montgomery.js +5 -7
  54. package/esm/abstract/montgomery.js.map +1 -1
  55. package/esm/abstract/poseidon.js +39 -41
  56. package/esm/abstract/poseidon.js.map +1 -1
  57. package/esm/abstract/utils.js +54 -30
  58. package/esm/abstract/utils.js.map +1 -1
  59. package/esm/abstract/weierstrass.js +17 -15
  60. package/esm/abstract/weierstrass.js.map +1 -1
  61. package/esm/bls12-381.js +143 -89
  62. package/esm/bls12-381.js.map +1 -1
  63. package/esm/bn254.js +3 -2
  64. package/esm/bn254.js.map +1 -1
  65. package/esm/ed25519.js +17 -8
  66. package/esm/ed25519.js.map +1 -1
  67. package/esm/ed448.js +218 -32
  68. package/esm/ed448.js.map +1 -1
  69. package/esm/jubjub.js +1 -1
  70. package/esm/jubjub.js.map +1 -1
  71. package/esm/p256.js +2 -2
  72. package/esm/p256.js.map +1 -1
  73. package/esm/p384.js +2 -2
  74. package/esm/p384.js.map +1 -1
  75. package/esm/p521.js +3 -3
  76. package/esm/p521.js.map +1 -1
  77. package/esm/package.json +1 -4
  78. package/esm/secp256k1.js +6 -6
  79. package/esm/secp256k1.js.map +1 -1
  80. package/jubjub.js.map +1 -1
  81. package/p256.js +2 -2
  82. package/p256.js.map +1 -1
  83. package/p384.js +2 -2
  84. package/p384.js.map +1 -1
  85. package/p521.js +3 -3
  86. package/p521.js.map +1 -1
  87. package/package.json +7 -6
  88. package/secp256k1.js +6 -6
  89. package/secp256k1.js.map +1 -1
  90. package/src/abstract/bls.ts +120 -22
  91. package/src/abstract/hash-to-curve.ts +24 -17
  92. package/src/abstract/modular.ts +81 -22
  93. package/src/abstract/montgomery.ts +4 -6
  94. package/src/abstract/poseidon.ts +39 -40
  95. package/src/abstract/utils.ts +55 -26
  96. package/src/abstract/weierstrass.ts +29 -18
  97. package/src/bls12-381.ts +132 -75
  98. package/src/bn254.ts +3 -2
  99. package/src/ed25519.ts +19 -8
  100. package/src/ed448.ts +267 -34
  101. package/src/jubjub.ts +1 -1
package/bls12-381.js CHANGED
@@ -2,16 +2,10 @@
2
2
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.bls12_381 = void 0;
5
- // bls12-381 pairing-friendly Barreto-Lynn-Scott elliptic curve construction allows to:
6
- // - Construct zk-SNARKs at the 128-bit security
7
- // - Use threshold signatures, which allows a user to sign lots of messages with one signature and
8
- // verify them swiftly in a batch, using Boneh-Lynn-Shacham signature scheme.
9
- //
10
- // The library uses G1 for public keys and G2 for signatures. Support for G1 signatures is planned.
11
- // Compatible with Algorand, Chia, Dfinity, Ethereum, FIL, Zcash. Matches specs
12
- // [pairing-curves-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
13
- // [bls-sigs-04](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04),
14
- // [hash-to-curve-12](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-12).
5
+ // bls12-381 is pairing-friendly Barreto-Lynn-Scott elliptic curve construction allowing to:
6
+ // - Construct zk-SNARKs at the 120-bit security
7
+ // - Efficiently verify N aggregate signatures with 1 pairing and N ec additions:
8
+ // the Boneh-Lynn-Shacham signature scheme is orders of magnitude more efficient than Schnorr
15
9
  //
16
10
  // ### Summary
17
11
  // 1. BLS Relies on Bilinear Pairing (expensive)
@@ -27,8 +21,17 @@ exports.bls12_381 = void 0;
27
21
  // - `S = pk x H(m)` - signing
28
22
  // - `e(P, H(m)) == e(G, S)` - verification using pairings
29
23
  // - `e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))` - signature aggregation
30
- // Filecoin uses little endian byte arrays for private keys -
31
- // so ensure to reverse byte order if you'll use it with FIL.
24
+ //
25
+ // ### Compatibility and notes
26
+ // 1. It is compatible with Algorand, Chia, Dfinity, Ethereum, Filecoin, ZEC
27
+ // Filecoin uses little endian byte arrays for private keys - make sure to reverse byte order.
28
+ // 2. Some projects use G2 for public keys and G1 for signatures. It's called "short signature"
29
+ // 3. Curve security level is about 120 bits as per Barbulescu-Duquesne 2017
30
+ // https://hal.science/hal-01534101/file/main.pdf
31
+ // 4. Compatible with specs:
32
+ // [cfrg-pairing-friendly-curves-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
33
+ // [cfrg-bls-signature-05](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-05),
34
+ // [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380).
32
35
  const sha256_1 = require("@noble/hashes/sha256");
33
36
  const utils_1 = require("@noble/hashes/utils");
34
37
  const bls_js_1 = require("./abstract/bls.js");
@@ -151,7 +154,7 @@ const Fp2 = {
151
154
  return x1;
152
155
  return x2;
153
156
  },
154
- // Same as sgn0_fp2 in draft-irtf-cfrg-hash-to-curve-16
157
+ // Same as sgn0_m_eq_2 in RFC 9380
155
158
  isOdd: (x) => {
156
159
  const { re: x0, im: x1 } = Fp2.reim(x);
157
160
  const sign_0 = x0 % _2n;
@@ -260,14 +263,14 @@ const Fp6Square = ({ c0, c1, c2 }) => {
260
263
  let t3 = Fp2.mul(Fp2.mul(c1, c2), _2n); // 2 * c1 * c2
261
264
  let t4 = Fp2.sqr(c2); // c2²
262
265
  return {
263
- c0: Fp2.add(Fp2.mulByNonresidue(t3), t0),
264
- c1: Fp2.add(Fp2.mulByNonresidue(t4), t1),
266
+ c0: Fp2.add(Fp2.mulByNonresidue(t3), t0), // T3 * (u + 1) + T0
267
+ c1: Fp2.add(Fp2.mulByNonresidue(t4), t1), // T4 * (u + 1) + T1
265
268
  // T1 + (c0 - c1 + c2)² + T3 - T0 - T4
266
269
  c2: Fp2.sub(Fp2.sub(Fp2.add(Fp2.add(t1, Fp2.sqr(Fp2.add(Fp2.sub(c0, c1), c2))), t3), t0), t4),
267
270
  };
268
271
  };
269
272
  const Fp6 = {
270
- ORDER: Fp2.ORDER,
273
+ ORDER: Fp2.ORDER, // TODO: unused, but need to verify
271
274
  BITS: 3 * Fp2.BITS,
272
275
  BYTES: 3 * Fp2.BYTES,
273
276
  MASK: (0, utils_js_1.bitMask)(3 * Fp2.BITS),
@@ -427,7 +430,7 @@ const Fp12Multiply = ({ c0, c1 }, rhs) => {
427
430
  let t1 = Fp6.mul(c0, r0); // c0 * r0
428
431
  let t2 = Fp6.mul(c1, r1); // c1 * r1
429
432
  return {
430
- c0: Fp6.add(t1, Fp6.mulByNonresidue(t2)),
433
+ c0: Fp6.add(t1, Fp6.mulByNonresidue(t2)), // T1 + T2 * v
431
434
  // (c0 + c1) * (r0 + r1) - (T1 + T2)
432
435
  c1: Fp6.sub(Fp6.mul(Fp6.add(c0, c1), Fp6.add(r0, r1)), Fp6.add(t1, t2)),
433
436
  };
@@ -444,12 +447,12 @@ function Fp4Square(a, b) {
444
447
  const a2 = Fp2.sqr(a);
445
448
  const b2 = Fp2.sqr(b);
446
449
  return {
447
- first: Fp2.add(Fp2.mulByNonresidue(b2), a2),
450
+ first: Fp2.add(Fp2.mulByNonresidue(b2), a2), // b² * Nonresidue + a²
448
451
  second: Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(a, b)), a2), b2), // (a + b)² - a² - b²
449
452
  };
450
453
  }
451
454
  const Fp12 = {
452
- ORDER: Fp2.ORDER,
455
+ ORDER: Fp2.ORDER, // TODO: unused, but need to verify
453
456
  BITS: 2 * Fp2.BITS,
454
457
  BYTES: 2 * Fp2.BYTES,
455
458
  MASK: (0, utils_js_1.bitMask)(2 * Fp2.BITS),
@@ -524,7 +527,7 @@ const Fp12 = {
524
527
  let t0 = Fp6.multiplyBy01(c0, o0, o1);
525
528
  let t1 = Fp6.multiplyBy1(c1, o4);
526
529
  return {
527
- c0: Fp6.add(Fp6.mulByNonresidue(t1), t0),
530
+ c0: Fp6.add(Fp6.mulByNonresidue(t1), t0), // T1 * v + T0
528
531
  // (c1 + c0) * [o0, o1+o4] - T0 - T1
529
532
  c1: Fp6.sub(Fp6.sub(Fp6.multiplyBy01(Fp6.add(c1, c0), o0, Fp2.add(o1, o4)), t0), t1),
530
533
  };
@@ -547,13 +550,13 @@ const Fp12 = {
547
550
  let t9 = Fp2.mulByNonresidue(t8); // T8 * (u + 1)
548
551
  return {
549
552
  c0: Fp6.create({
550
- c0: Fp2.add(Fp2.mul(Fp2.sub(t3, c0c0), _2n), t3),
551
- c1: Fp2.add(Fp2.mul(Fp2.sub(t5, c0c1), _2n), t5),
553
+ c0: Fp2.add(Fp2.mul(Fp2.sub(t3, c0c0), _2n), t3), // 2 * (T3 - c0c0) + T3
554
+ c1: Fp2.add(Fp2.mul(Fp2.sub(t5, c0c1), _2n), t5), // 2 * (T5 - c0c1) + T5
552
555
  c2: Fp2.add(Fp2.mul(Fp2.sub(t7, c0c2), _2n), t7),
553
- }),
556
+ }), // 2 * (T7 - c0c2) + T7
554
557
  c1: Fp6.create({
555
- c0: Fp2.add(Fp2.mul(Fp2.add(t9, c1c0), _2n), t9),
556
- c1: Fp2.add(Fp2.mul(Fp2.add(t4, c1c1), _2n), t4),
558
+ c0: Fp2.add(Fp2.mul(Fp2.add(t9, c1c0), _2n), t9), // 2 * (T9 + c1c0) + T9
559
+ c1: Fp2.add(Fp2.mul(Fp2.add(t4, c1c1), _2n), t4), // 2 * (T4 + c1c1) + T4
557
560
  c2: Fp2.add(Fp2.mul(Fp2.add(t6, c1c2), _2n), t6),
558
561
  }),
559
562
  }; // 2 * (T6 + c1c2) + T6
@@ -638,8 +641,7 @@ const FP12_FROBENIUS_COEFFICIENTS = [
638
641
  ].map((n) => Fp2.fromBigTuple(n));
639
642
  // END OF CURVE FIELDS
640
643
  // HashToCurve
641
- // 3-isogeny map from E' to E
642
- // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-E.3
644
+ // 3-isogeny map from E' to E https://www.rfc-editor.org/rfc/rfc9380#appendix-E.3
643
645
  const isogenyMapG2 = (0, hash_to_curve_js_1.isogenyMap)(Fp2, [
644
646
  // xNum
645
647
  [
@@ -780,8 +782,8 @@ const isogenyMapG1 = (0, hash_to_curve_js_1.isogenyMap)(Fp, [
780
782
  ].map((i) => i.map((j) => BigInt(j))));
781
783
  // SWU Map - Fp2 to G2': y² = x³ + 240i * x + 1012 + 1012i
782
784
  const G2_SWU = (0, weierstrass_js_1.mapToCurveSimpleSWU)(Fp2, {
783
- A: Fp2.create({ c0: Fp.create(_0n), c1: Fp.create(BigInt(240)) }),
784
- B: Fp2.create({ c0: Fp.create(BigInt(1012)), c1: Fp.create(BigInt(1012)) }),
785
+ A: Fp2.create({ c0: Fp.create(_0n), c1: Fp.create(BigInt(240)) }), // A' = 240 * I
786
+ B: Fp2.create({ c0: Fp.create(BigInt(1012)), c1: Fp.create(BigInt(1012)) }), // B' = 1012 * (1 + I)
785
787
  Z: Fp2.create({ c0: Fp.create(BigInt(-2)), c1: Fp.create(BigInt(-1)) }), // Z: -(2 + I)
786
788
  });
787
789
  // Optimized SWU Map - Fp to G1
@@ -823,7 +825,7 @@ function G2psi2(c, P) {
823
825
  //
824
826
  // Parameter definitions are in section 5.3 of the spec unless otherwise noted.
825
827
  // Parameter values come from section 8.8.2 of the spec.
826
- // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-8.8.2
828
+ // https://www.rfc-editor.org/rfc/rfc9380#section-8.8.2
827
829
  //
828
830
  // Base field F is GF(p^m)
829
831
  // p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
@@ -854,11 +856,39 @@ const htfDefaults = Object.freeze({
854
856
  });
855
857
  // Encoding utils
856
858
  // Point on G1 curve: (x, y)
857
- const C_BIT_POS = Fp.BITS; // C_bit, compression bit for serialization flag
858
- const I_BIT_POS = Fp.BITS + 1; // I_bit, point-at-infinity bit for serialization flag
859
- const S_BIT_POS = Fp.BITS + 2; // S_bit, sign bit for serialization flag
860
859
  // Compressed point of infinity
861
- const COMPRESSED_ZERO = Fp.toBytes((0, utils_js_1.bitSet)((0, utils_js_1.bitSet)(_0n, I_BIT_POS, true), S_BIT_POS, true)); // set compressed & point-at-infinity bits
860
+ const COMPRESSED_ZERO = setMask(Fp.toBytes(_0n), { infinity: true, compressed: true }); // set compressed & point-at-infinity bits
861
+ function parseMask(bytes) {
862
+ // Copy, so we can remove mask data. It will be removed also later, when Fp.create will call modulo.
863
+ bytes = bytes.slice();
864
+ const mask = bytes[0] & 224;
865
+ const compressed = !!((mask >> 7) & 1); // compression bit (0b1000_0000)
866
+ const infinity = !!((mask >> 6) & 1); // point at infinity bit (0b0100_0000)
867
+ const sort = !!((mask >> 5) & 1); // sort bit (0b0010_0000)
868
+ bytes[0] &= 31; // clear mask (zero first 3 bits)
869
+ return { compressed, infinity, sort, value: bytes };
870
+ }
871
+ function setMask(bytes, mask) {
872
+ if (bytes[0] & 224)
873
+ throw new Error('setMask: non-empty mask');
874
+ if (mask.compressed)
875
+ bytes[0] |= 128;
876
+ if (mask.infinity)
877
+ bytes[0] |= 64;
878
+ if (mask.sort)
879
+ bytes[0] |= 32;
880
+ return bytes;
881
+ }
882
+ function signatureG1ToRawBytes(point) {
883
+ point.assertValidity();
884
+ const isZero = point.equals(exports.bls12_381.G1.ProjectivePoint.ZERO);
885
+ const { x, y } = point.toAffine();
886
+ if (isZero)
887
+ return COMPRESSED_ZERO.slice();
888
+ const P = Fp.ORDER;
889
+ const sort = Boolean((y * _2n) / P);
890
+ return setMask((0, utils_js_1.numberToBytesBE)(x, Fp.BYTES), { compressed: true, sort });
891
+ }
862
892
  function signatureG2ToRawBytes(point) {
863
893
  // NOTE: by some reasons it was missed in bls12-381, looks like bug
864
894
  point.assertValidity();
@@ -869,13 +899,12 @@ function signatureG2ToRawBytes(point) {
869
899
  const { re: x0, im: x1 } = Fp2.reim(x);
870
900
  const { re: y0, im: y1 } = Fp2.reim(y);
871
901
  const tmp = y1 > _0n ? y1 * _2n : y0 * _2n;
872
- const aflag1 = Boolean((tmp / Fp.ORDER) & _1n);
873
- const z1 = (0, utils_js_1.bitSet)((0, utils_js_1.bitSet)(x1, 381, aflag1), S_BIT_POS, true);
902
+ const sort = Boolean((tmp / Fp.ORDER) & _1n);
874
903
  const z2 = x0;
875
- return (0, utils_js_1.concatBytes)((0, utils_js_1.numberToBytesBE)(z1, len), (0, utils_js_1.numberToBytesBE)(z2, len));
904
+ return (0, utils_js_1.concatBytes)(setMask((0, utils_js_1.numberToBytesBE)(x1, len), { sort, compressed: true }), (0, utils_js_1.numberToBytesBE)(z2, len));
876
905
  }
877
906
  // To verify curve parameters, see pairing-friendly-curves spec:
878
- // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-09
907
+ // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-11
879
908
  // Basic math is done over finite fields over p.
880
909
  // More complicated math is done over polynominal extension fields.
881
910
  // To simplify calculations in Fp12, we construct extension tower:
@@ -906,7 +935,7 @@ exports.bls12_381 = (0, bls_js_1.bls)({
906
935
  Gy: BigInt('0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'),
907
936
  a: Fp.ZERO,
908
937
  b: _4n,
909
- htfDefaults: { ...htfDefaults, m: 1 },
938
+ htfDefaults: { ...htfDefaults, m: 1, DST: 'BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_' },
910
939
  wrapPrivateKey: true,
911
940
  allowInfinityPoint: true,
912
941
  // Checks is the point resides in prime-order subgroup.
@@ -935,7 +964,7 @@ exports.bls12_381 = (0, bls_js_1.bls)({
935
964
  },
936
965
  // Clear cofactor of G1
937
966
  // https://eprint.iacr.org/2019/403
938
- clearCofactor: (c, point) => {
967
+ clearCofactor: (_c, point) => {
939
968
  // return this.multiplyUnsafe(CURVE.h);
940
969
  return point.multiplyUnsafe(exports.bls12_381.params.x).add(point); // x*P + P
941
970
  },
@@ -944,31 +973,35 @@ exports.bls12_381 = (0, bls_js_1.bls)({
944
973
  return isogenyMapG1(x, y);
945
974
  },
946
975
  fromBytes: (bytes) => {
947
- bytes = bytes.slice();
948
- if (bytes.length === 48) {
976
+ const { compressed, infinity, sort, value } = parseMask(bytes);
977
+ if (value.length === 48 && compressed) {
949
978
  // TODO: Fp.bytes
950
979
  const P = Fp.ORDER;
951
- const compressedValue = (0, utils_js_1.bytesToNumberBE)(bytes);
952
- const bflag = (0, utils_js_1.bitGet)(compressedValue, I_BIT_POS);
980
+ const compressedValue = (0, utils_js_1.bytesToNumberBE)(value);
953
981
  // Zero
954
- if (bflag === _1n)
955
- return { x: _0n, y: _0n };
956
982
  const x = Fp.create(compressedValue & Fp.MASK);
983
+ if (infinity) {
984
+ if (x !== _0n)
985
+ throw new Error('G1: non-empty compressed point at infinity');
986
+ return { x: _0n, y: _0n };
987
+ }
957
988
  const right = Fp.add(Fp.pow(x, _3n), Fp.create(exports.bls12_381.params.G1b)); // y² = x³ + b
958
989
  let y = Fp.sqrt(right);
959
990
  if (!y)
960
991
  throw new Error('Invalid compressed G1 point');
961
- const aflag = (0, utils_js_1.bitGet)(compressedValue, C_BIT_POS);
962
- if ((y * _2n) / P !== aflag)
992
+ if ((y * _2n) / P !== BigInt(sort))
963
993
  y = Fp.neg(y);
964
994
  return { x: Fp.create(x), y: Fp.create(y) };
965
995
  }
966
- else if (bytes.length === 96) {
996
+ else if (value.length === 96 && !compressed) {
967
997
  // Check if the infinity flag is set
968
- if ((bytes[0] & (1 << 6)) !== 0)
998
+ const x = (0, utils_js_1.bytesToNumberBE)(value.subarray(0, Fp.BYTES));
999
+ const y = (0, utils_js_1.bytesToNumberBE)(value.subarray(Fp.BYTES));
1000
+ if (infinity) {
1001
+ if (x !== _0n || y !== _0n)
1002
+ throw new Error('G1: non-empty point at infinity');
969
1003
  return exports.bls12_381.G1.ProjectivePoint.ZERO.toAffine();
970
- const x = (0, utils_js_1.bytesToNumberBE)(bytes.subarray(0, Fp.BYTES));
971
- const y = (0, utils_js_1.bytesToNumberBE)(bytes.subarray(Fp.BYTES));
1004
+ }
972
1005
  return { x: Fp.create(x), y: Fp.create(y) };
973
1006
  }
974
1007
  else {
@@ -982,10 +1015,8 @@ exports.bls12_381 = (0, bls_js_1.bls)({
982
1015
  if (isZero)
983
1016
  return COMPRESSED_ZERO.slice();
984
1017
  const P = Fp.ORDER;
985
- let num;
986
- num = (0, utils_js_1.bitSet)(x, C_BIT_POS, Boolean((y * _2n) / P)); // set aflag
987
- num = (0, utils_js_1.bitSet)(num, S_BIT_POS, true);
988
- return (0, utils_js_1.numberToBytesBE)(num, Fp.BYTES);
1018
+ const sort = Boolean((y * _2n) / P);
1019
+ return setMask((0, utils_js_1.numberToBytesBE)(x, Fp.BYTES), { compressed: true, sort });
989
1020
  }
990
1021
  else {
991
1022
  if (isZero) {
@@ -998,6 +1029,33 @@ exports.bls12_381 = (0, bls_js_1.bls)({
998
1029
  }
999
1030
  }
1000
1031
  },
1032
+ ShortSignature: {
1033
+ fromHex(hex) {
1034
+ const { infinity, sort, value } = parseMask((0, utils_js_1.ensureBytes)('signatureHex', hex, 48));
1035
+ const P = Fp.ORDER;
1036
+ const compressedValue = (0, utils_js_1.bytesToNumberBE)(value);
1037
+ // Zero
1038
+ if (infinity)
1039
+ return exports.bls12_381.G1.ProjectivePoint.ZERO;
1040
+ const x = Fp.create(compressedValue & Fp.MASK);
1041
+ const right = Fp.add(Fp.pow(x, _3n), Fp.create(exports.bls12_381.params.G1b)); // y² = x³ + b
1042
+ let y = Fp.sqrt(right);
1043
+ if (!y)
1044
+ throw new Error('Invalid compressed G1 point');
1045
+ const aflag = BigInt(sort);
1046
+ if ((y * _2n) / P !== aflag)
1047
+ y = Fp.neg(y);
1048
+ const point = exports.bls12_381.G1.ProjectivePoint.fromAffine({ x, y });
1049
+ point.assertValidity();
1050
+ return point;
1051
+ },
1052
+ toRawBytes(point) {
1053
+ return signatureG1ToRawBytes(point);
1054
+ },
1055
+ toHex(point) {
1056
+ return (0, utils_js_1.bytesToHex)(signatureG1ToRawBytes(point));
1057
+ },
1058
+ },
1001
1059
  },
1002
1060
  // G2 is the order-q subgroup of E2(Fp²) : y² = x³+4(1+√−1),
1003
1061
  // where Fp2 is Fp[√−1]/(x2+1). #E2(Fp2 ) = h2q, where
@@ -1057,45 +1115,45 @@ exports.bls12_381 = (0, bls_js_1.bls)({
1057
1115
  return Q; // [x²-x-1]P + [x-1]Ψ(P) + Ψ²(2P)
1058
1116
  },
1059
1117
  fromBytes: (bytes) => {
1060
- bytes = bytes.slice();
1061
- const m_byte = bytes[0] & 0xe0;
1062
- if (m_byte === 0x20 || m_byte === 0x60 || m_byte === 0xe0) {
1063
- throw new Error('Invalid encoding flag: ' + m_byte);
1118
+ const { compressed, infinity, sort, value } = parseMask(bytes);
1119
+ if ((!compressed && !infinity && sort) || // 00100000
1120
+ (!compressed && infinity && sort) || // 01100000
1121
+ (sort && infinity && compressed) // 11100000
1122
+ ) {
1123
+ throw new Error('Invalid encoding flag: ' + (bytes[0] & 224));
1064
1124
  }
1065
- const bitC = m_byte & 0x80; // compression bit
1066
- const bitI = m_byte & 0x40; // point at infinity bit
1067
- const bitS = m_byte & 0x20; // sign bit
1068
1125
  const L = Fp.BYTES;
1069
1126
  const slc = (b, from, to) => (0, utils_js_1.bytesToNumberBE)(b.slice(from, to));
1070
- if (bytes.length === 96 && bitC) {
1127
+ if (value.length === 96 && compressed) {
1071
1128
  const b = exports.bls12_381.params.G2b;
1072
1129
  const P = Fp.ORDER;
1073
- bytes[0] = bytes[0] & 0x1f; // clear flags
1074
- if (bitI) {
1130
+ if (infinity) {
1075
1131
  // check that all bytes are 0
1076
- if (bytes.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
1132
+ if (value.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
1077
1133
  throw new Error('Invalid compressed G2 point');
1078
1134
  }
1079
1135
  return { x: Fp2.ZERO, y: Fp2.ZERO };
1080
1136
  }
1081
- const x_1 = slc(bytes, 0, L);
1082
- const x_0 = slc(bytes, L, 2 * L);
1137
+ const x_1 = slc(value, 0, L);
1138
+ const x_0 = slc(value, L, 2 * L);
1083
1139
  const x = Fp2.create({ c0: Fp.create(x_0), c1: Fp.create(x_1) });
1084
1140
  const right = Fp2.add(Fp2.pow(x, _3n), b); // y² = x³ + 4 * (u+1) = x³ + b
1085
1141
  let y = Fp2.sqrt(right);
1086
1142
  const Y_bit = y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P ? _1n : _0n;
1087
- y = bitS > 0 && Y_bit > 0 ? y : Fp2.neg(y);
1143
+ y = sort && Y_bit > 0 ? y : Fp2.neg(y);
1088
1144
  return { x, y };
1089
1145
  }
1090
- else if (bytes.length === 192 && !bitC) {
1091
- // Check if the infinity flag is set
1092
- if ((bytes[0] & (1 << 6)) !== 0) {
1146
+ else if (value.length === 192 && !compressed) {
1147
+ if (infinity) {
1148
+ if (value.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
1149
+ throw new Error('Invalid uncompressed G2 point');
1150
+ }
1093
1151
  return { x: Fp2.ZERO, y: Fp2.ZERO };
1094
1152
  }
1095
- const x1 = slc(bytes, 0, L);
1096
- const x0 = slc(bytes, L, 2 * L);
1097
- const y1 = slc(bytes, 2 * L, 3 * L);
1098
- const y0 = slc(bytes, 3 * L, 4 * L);
1153
+ const x1 = slc(value, 0, L);
1154
+ const x0 = slc(value, L, 2 * L);
1155
+ const y1 = slc(value, 2 * L, 3 * L);
1156
+ const y0 = slc(value, 3 * L, 4 * L);
1099
1157
  return { x: Fp2.fromBigTuple([x0, x1]), y: Fp2.fromBigTuple([y0, y1]) };
1100
1158
  }
1101
1159
  else {
@@ -1110,10 +1168,7 @@ exports.bls12_381 = (0, bls_js_1.bls)({
1110
1168
  if (isZero)
1111
1169
  return (0, utils_js_1.concatBytes)(COMPRESSED_ZERO, (0, utils_js_1.numberToBytesBE)(_0n, len));
1112
1170
  const flag = Boolean(y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P);
1113
- // set compressed & sign bits (looks like different offsets than for G1/Fp?)
1114
- let x_1 = (0, utils_js_1.bitSet)(x.c1, C_BIT_POS, flag);
1115
- x_1 = (0, utils_js_1.bitSet)(x_1, S_BIT_POS, true);
1116
- return (0, utils_js_1.concatBytes)((0, utils_js_1.numberToBytesBE)(x_1, len), (0, utils_js_1.numberToBytesBE)(x.c0, len));
1171
+ return (0, utils_js_1.concatBytes)(setMask((0, utils_js_1.numberToBytesBE)(x.c1, len), { compressed: true, sort: flag }), (0, utils_js_1.numberToBytesBE)(x.c0, len));
1117
1172
  }
1118
1173
  else {
1119
1174
  if (isZero)
@@ -1126,16 +1181,15 @@ exports.bls12_381 = (0, bls_js_1.bls)({
1126
1181
  Signature: {
1127
1182
  // TODO: Optimize, it's very slow because of sqrt.
1128
1183
  fromHex(hex) {
1129
- hex = (0, utils_js_1.ensureBytes)('signatureHex', hex);
1184
+ const { infinity, sort, value } = parseMask((0, utils_js_1.ensureBytes)('signatureHex', hex));
1130
1185
  const P = Fp.ORDER;
1131
1186
  const half = hex.length / 2;
1132
1187
  if (half !== 48 && half !== 96)
1133
1188
  throw new Error('Invalid compressed signature length, must be 96 or 192');
1134
- const z1 = (0, utils_js_1.bytesToNumberBE)(hex.slice(0, half));
1135
- const z2 = (0, utils_js_1.bytesToNumberBE)(hex.slice(half));
1189
+ const z1 = (0, utils_js_1.bytesToNumberBE)(value.slice(0, half));
1190
+ const z2 = (0, utils_js_1.bytesToNumberBE)(value.slice(half));
1136
1191
  // Indicates the infinity point
1137
- const bflag1 = (0, utils_js_1.bitGet)(z1, I_BIT_POS);
1138
- if (bflag1 === _1n)
1192
+ if (infinity)
1139
1193
  return exports.bls12_381.G2.ProjectivePoint.ZERO;
1140
1194
  const x1 = Fp.create(z1 & Fp.MASK);
1141
1195
  const x2 = Fp.create(z2);
@@ -1148,7 +1202,7 @@ exports.bls12_381 = (0, bls_js_1.bls)({
1148
1202
  // Choose the y whose leftmost bit of the imaginary part is equal to the a_flag1
1149
1203
  // If y1 happens to be zero, then use the bit of y0
1150
1204
  const { re: y0, im: y1 } = Fp2.reim(y);
1151
- const aflag1 = (0, utils_js_1.bitGet)(z1, 381);
1205
+ const aflag1 = BigInt(sort);
1152
1206
  const isGreater = y1 > _0n && (y1 * _2n) / P !== aflag1;
1153
1207
  const isZero = y1 === _0n && (y0 * _2n) / P !== aflag1;
1154
1208
  if (isGreater || isZero)
@@ -1166,7 +1220,7 @@ exports.bls12_381 = (0, bls_js_1.bls)({
1166
1220
  },
1167
1221
  },
1168
1222
  params: {
1169
- x: BLS_X,
1223
+ x: BLS_X, // The BLS parameter x for BLS12-381
1170
1224
  r: Fr.ORDER, // order; z⁴ − z² + 1; CURVE.n from other curves
1171
1225
  },
1172
1226
  htfDefaults,