@noble/curves 1.9.1 → 1.9.3

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 (223) hide show
  1. package/README.md +238 -227
  2. package/_shortw_utils.d.ts +8 -5
  3. package/_shortw_utils.d.ts.map +1 -1
  4. package/_shortw_utils.js +3 -8
  5. package/_shortw_utils.js.map +1 -1
  6. package/abstract/bls.d.ts +123 -62
  7. package/abstract/bls.d.ts.map +1 -1
  8. package/abstract/bls.js +219 -163
  9. package/abstract/bls.js.map +1 -1
  10. package/abstract/curve.d.ts +142 -21
  11. package/abstract/curve.d.ts.map +1 -1
  12. package/abstract/curve.js +224 -143
  13. package/abstract/curve.js.map +1 -1
  14. package/abstract/edwards.d.ts +190 -49
  15. package/abstract/edwards.d.ts.map +1 -1
  16. package/abstract/edwards.js +322 -136
  17. package/abstract/edwards.js.map +1 -1
  18. package/abstract/fft.d.ts +12 -10
  19. package/abstract/fft.d.ts.map +1 -1
  20. package/abstract/fft.js +12 -13
  21. package/abstract/fft.js.map +1 -1
  22. package/abstract/hash-to-curve.d.ts +31 -13
  23. package/abstract/hash-to-curve.d.ts.map +1 -1
  24. package/abstract/hash-to-curve.js +34 -19
  25. package/abstract/hash-to-curve.js.map +1 -1
  26. package/abstract/modular.d.ts +31 -13
  27. package/abstract/modular.d.ts.map +1 -1
  28. package/abstract/modular.js +125 -52
  29. package/abstract/modular.js.map +1 -1
  30. package/abstract/montgomery.d.ts +18 -5
  31. package/abstract/montgomery.d.ts.map +1 -1
  32. package/abstract/montgomery.js +23 -6
  33. package/abstract/montgomery.js.map +1 -1
  34. package/abstract/poseidon.d.ts +5 -13
  35. package/abstract/poseidon.d.ts.map +1 -1
  36. package/abstract/poseidon.js +12 -7
  37. package/abstract/poseidon.js.map +1 -1
  38. package/abstract/tower.d.ts +23 -49
  39. package/abstract/tower.d.ts.map +1 -1
  40. package/abstract/tower.js +9 -3
  41. package/abstract/tower.js.map +1 -1
  42. package/abstract/utils.d.ts +1 -115
  43. package/abstract/utils.d.ts.map +1 -1
  44. package/abstract/utils.js +17 -371
  45. package/abstract/utils.js.map +1 -1
  46. package/abstract/weierstrass.d.ts +206 -124
  47. package/abstract/weierstrass.d.ts.map +1 -1
  48. package/abstract/weierstrass.js +747 -604
  49. package/abstract/weierstrass.js.map +1 -1
  50. package/bls12-381.d.ts +2 -0
  51. package/bls12-381.d.ts.map +1 -1
  52. package/bls12-381.js +504 -466
  53. package/bls12-381.js.map +1 -1
  54. package/bn254.d.ts +2 -0
  55. package/bn254.d.ts.map +1 -1
  56. package/bn254.js +44 -32
  57. package/bn254.js.map +1 -1
  58. package/ed25519.d.ts +55 -66
  59. package/ed25519.d.ts.map +1 -1
  60. package/ed25519.js +172 -186
  61. package/ed25519.js.map +1 -1
  62. package/ed448.d.ts +60 -57
  63. package/ed448.d.ts.map +1 -1
  64. package/ed448.js +172 -166
  65. package/ed448.js.map +1 -1
  66. package/esm/_shortw_utils.d.ts +8 -5
  67. package/esm/_shortw_utils.d.ts.map +1 -1
  68. package/esm/_shortw_utils.js +3 -8
  69. package/esm/_shortw_utils.js.map +1 -1
  70. package/esm/abstract/bls.d.ts +123 -62
  71. package/esm/abstract/bls.d.ts.map +1 -1
  72. package/esm/abstract/bls.js +220 -164
  73. package/esm/abstract/bls.js.map +1 -1
  74. package/esm/abstract/curve.d.ts +142 -21
  75. package/esm/abstract/curve.d.ts.map +1 -1
  76. package/esm/abstract/curve.js +219 -143
  77. package/esm/abstract/curve.js.map +1 -1
  78. package/esm/abstract/edwards.d.ts +190 -49
  79. package/esm/abstract/edwards.d.ts.map +1 -1
  80. package/esm/abstract/edwards.js +320 -138
  81. package/esm/abstract/edwards.js.map +1 -1
  82. package/esm/abstract/fft.d.ts +12 -10
  83. package/esm/abstract/fft.d.ts.map +1 -1
  84. package/esm/abstract/fft.js +10 -11
  85. package/esm/abstract/fft.js.map +1 -1
  86. package/esm/abstract/hash-to-curve.d.ts +31 -13
  87. package/esm/abstract/hash-to-curve.d.ts.map +1 -1
  88. package/esm/abstract/hash-to-curve.js +33 -19
  89. package/esm/abstract/hash-to-curve.js.map +1 -1
  90. package/esm/abstract/modular.d.ts +31 -13
  91. package/esm/abstract/modular.d.ts.map +1 -1
  92. package/esm/abstract/modular.js +124 -51
  93. package/esm/abstract/modular.js.map +1 -1
  94. package/esm/abstract/montgomery.d.ts +18 -5
  95. package/esm/abstract/montgomery.d.ts.map +1 -1
  96. package/esm/abstract/montgomery.js +23 -6
  97. package/esm/abstract/montgomery.js.map +1 -1
  98. package/esm/abstract/poseidon.d.ts +5 -13
  99. package/esm/abstract/poseidon.d.ts.map +1 -1
  100. package/esm/abstract/poseidon.js +12 -7
  101. package/esm/abstract/poseidon.js.map +1 -1
  102. package/esm/abstract/tower.d.ts +23 -49
  103. package/esm/abstract/tower.d.ts.map +1 -1
  104. package/esm/abstract/tower.js +9 -3
  105. package/esm/abstract/tower.js.map +1 -1
  106. package/esm/abstract/utils.d.ts +1 -115
  107. package/esm/abstract/utils.d.ts.map +1 -1
  108. package/esm/abstract/utils.js +3 -344
  109. package/esm/abstract/utils.js.map +1 -1
  110. package/esm/abstract/weierstrass.d.ts +206 -124
  111. package/esm/abstract/weierstrass.d.ts.map +1 -1
  112. package/esm/abstract/weierstrass.js +743 -605
  113. package/esm/abstract/weierstrass.js.map +1 -1
  114. package/esm/bls12-381.d.ts +2 -0
  115. package/esm/bls12-381.d.ts.map +1 -1
  116. package/esm/bls12-381.js +503 -465
  117. package/esm/bls12-381.js.map +1 -1
  118. package/esm/bn254.d.ts +2 -0
  119. package/esm/bn254.d.ts.map +1 -1
  120. package/esm/bn254.js +41 -29
  121. package/esm/bn254.js.map +1 -1
  122. package/esm/ed25519.d.ts +55 -66
  123. package/esm/ed25519.d.ts.map +1 -1
  124. package/esm/ed25519.js +170 -183
  125. package/esm/ed25519.js.map +1 -1
  126. package/esm/ed448.d.ts +60 -57
  127. package/esm/ed448.d.ts.map +1 -1
  128. package/esm/ed448.js +169 -162
  129. package/esm/ed448.js.map +1 -1
  130. package/esm/index.js +7 -9
  131. package/esm/index.js.map +1 -1
  132. package/esm/jubjub.d.ts +3 -3
  133. package/esm/jubjub.d.ts.map +1 -1
  134. package/esm/jubjub.js +3 -3
  135. package/esm/jubjub.js.map +1 -1
  136. package/esm/misc.d.ts +3 -5
  137. package/esm/misc.d.ts.map +1 -1
  138. package/esm/misc.js +31 -29
  139. package/esm/misc.js.map +1 -1
  140. package/esm/nist.d.ts +7 -22
  141. package/esm/nist.d.ts.map +1 -1
  142. package/esm/nist.js +106 -101
  143. package/esm/nist.js.map +1 -1
  144. package/esm/p256.d.ts +7 -3
  145. package/esm/p256.d.ts.map +1 -1
  146. package/esm/p256.js +4 -0
  147. package/esm/p256.js.map +1 -1
  148. package/esm/p384.d.ts +7 -4
  149. package/esm/p384.d.ts.map +1 -1
  150. package/esm/p384.js +4 -1
  151. package/esm/p384.js.map +1 -1
  152. package/esm/p521.d.ts +7 -3
  153. package/esm/p521.d.ts.map +1 -1
  154. package/esm/p521.js +4 -0
  155. package/esm/p521.js.map +1 -1
  156. package/esm/secp256k1.d.ts +38 -21
  157. package/esm/secp256k1.d.ts.map +1 -1
  158. package/esm/secp256k1.js +112 -104
  159. package/esm/secp256k1.js.map +1 -1
  160. package/esm/utils.d.ts +96 -0
  161. package/esm/utils.d.ts.map +1 -0
  162. package/esm/utils.js +279 -0
  163. package/esm/utils.js.map +1 -0
  164. package/index.js +7 -9
  165. package/index.js.map +1 -1
  166. package/jubjub.d.ts +3 -3
  167. package/jubjub.d.ts.map +1 -1
  168. package/jubjub.js +3 -3
  169. package/jubjub.js.map +1 -1
  170. package/misc.d.ts +3 -5
  171. package/misc.d.ts.map +1 -1
  172. package/misc.js +35 -33
  173. package/misc.js.map +1 -1
  174. package/nist.d.ts +7 -22
  175. package/nist.d.ts.map +1 -1
  176. package/nist.js +106 -101
  177. package/nist.js.map +1 -1
  178. package/p256.d.ts +7 -3
  179. package/p256.d.ts.map +1 -1
  180. package/p256.js +4 -0
  181. package/p256.js.map +1 -1
  182. package/p384.d.ts +7 -4
  183. package/p384.d.ts.map +1 -1
  184. package/p384.js +4 -1
  185. package/p384.js.map +1 -1
  186. package/p521.d.ts +7 -3
  187. package/p521.d.ts.map +1 -1
  188. package/p521.js +4 -0
  189. package/p521.js.map +1 -1
  190. package/package.json +17 -6
  191. package/secp256k1.d.ts +38 -21
  192. package/secp256k1.d.ts.map +1 -1
  193. package/secp256k1.js +112 -104
  194. package/secp256k1.js.map +1 -1
  195. package/src/_shortw_utils.ts +6 -15
  196. package/src/abstract/bls.ts +428 -251
  197. package/src/abstract/curve.ts +307 -149
  198. package/src/abstract/edwards.ts +555 -203
  199. package/src/abstract/fft.ts +30 -19
  200. package/src/abstract/hash-to-curve.ts +75 -34
  201. package/src/abstract/modular.ts +131 -59
  202. package/src/abstract/montgomery.ts +44 -15
  203. package/src/abstract/poseidon.ts +22 -18
  204. package/src/abstract/tower.ts +40 -71
  205. package/src/abstract/utils.ts +3 -378
  206. package/src/abstract/weierstrass.ts +1086 -746
  207. package/src/bls12-381.ts +549 -490
  208. package/src/bn254.ts +47 -35
  209. package/src/ed25519.ts +214 -216
  210. package/src/ed448.ts +251 -220
  211. package/src/index.ts +7 -9
  212. package/src/jubjub.ts +3 -3
  213. package/src/misc.ts +41 -40
  214. package/src/nist.ts +161 -126
  215. package/src/p256.ts +7 -3
  216. package/src/p384.ts +7 -5
  217. package/src/p521.ts +7 -3
  218. package/src/secp256k1.ts +145 -115
  219. package/src/utils.ts +328 -0
  220. package/utils.d.ts +96 -0
  221. package/utils.d.ts.map +1 -0
  222. package/utils.js +313 -0
  223. package/utils.js.map +1 -0
package/esm/bls12-381.js CHANGED
@@ -1,69 +1,86 @@
1
1
  /**
2
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
3
+
4
+ * Construct zk-SNARKs at the ~120-bit security, as per [Barbulescu-Duquesne 2017](https://hal.science/hal-01534101/file/main.pdf)
5
+ * Efficiently verify N aggregate signatures with 1 pairing and N ec additions:
6
+ the Boneh-Lynn-Shacham signature scheme is orders of magnitude more efficient than Schnorr
7
+
8
+ BLS can mean 2 different things:
9
+
10
+ * Barreto-Lynn-Scott: BLS12, a Pairing Friendly Elliptic Curve
11
+ * Boneh-Lynn-Shacham: A Signature Scheme.
12
+
13
+ ### Summary
14
+
15
+ 1. BLS Relies on expensive bilinear pairing
16
+ 2. Secret Keys: 32 bytes
17
+ 3. Public Keys: 48 OR 96 bytes - big-endian x coordinate of point on G1 OR G2 curve
18
+ 4. Signatures: 96 OR 48 bytes - big-endian x coordinate of point on G2 OR G1 curve
19
+ 5. The 12 stands for the Embedding degree.
20
+
21
+ Modes of operation:
22
+
23
+ * Long signatures: 48-byte keys + 96-byte sigs (G1 keys + G2 sigs).
24
+ * Short signatures: 96-byte keys + 48-byte sigs (G2 keys + G1 sigs).
25
+
26
+ ### Formulas
27
+
28
+ - `P = pk x G` - public keys
29
+ - `S = pk x H(m)` - signing, uses hash-to-curve on m
30
+ - `e(P, H(m)) == e(G, S)` - verification using pairings
31
+ - `e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))` - signature aggregation
32
+
33
+ ### Curves
34
+
35
+ G1 is ordinary elliptic curve. G2 is extension field curve, think "over complex numbers".
36
+
37
+ - G1: y² = x³ + 4
38
+ - G2: y² = x³ + 4(u + 1) where u = √−1; r-order subgroup of E'(Fp²), M-type twist
39
+
40
+ ### Towers
41
+
42
+ Pairing G1 + G2 produces element in Fp₁₂, 12-degree polynomial.
43
+ Fp₁₂ is usually implemented using tower of lower-degree polynomials for speed.
44
+
45
+ - Fp₁₂ = Fp₆² => Fp₂³
46
+ - Fp(u) / (u² - β) where β = -1
47
+ - Fp₂(v) / (v³ - ξ) where ξ = u + 1
48
+ - Fp₆(w) / (w² - γ) where γ = v
49
+ - Fp²[u] = Fp/u²+1
50
+ - Fp⁶[v] = Fp²/v³-1-u
51
+ - Fp¹²[w] = Fp⁶/w²-v
52
+
53
+ ### Params
54
+
55
+ * Embedding degree (k): 12
56
+ * Seed is sometimes named x or t
57
+ * t = -15132376222941642752
58
+ * p = (t-1)² * (t⁴-t²+1)/3 + t
59
+ * r = t⁴-t²+1
60
+ * Ate loop size: X
61
+
62
+ To verify curve parameters, see
63
+ [pairing-friendly-curves spec](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-11).
64
+ Basic math is done over finite fields over p.
65
+ More complicated math is done over polynominal extension fields.
66
+
67
+ ### Compatibility and notes
68
+ 1. It is compatible with Algorand, Chia, Dfinity, Ethereum, Filecoin, ZEC.
69
+ Filecoin uses little endian byte arrays for secret keys - make sure to reverse byte order.
70
+ 2. Make sure to correctly select mode: "long signature" or "short signature".
71
+ 3. Compatible with specs:
72
+ RFC 9380,
73
+ [cfrg-pairing-friendly-curves-11](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-11),
74
+ [cfrg-bls-signature-05](https://datatracker.ietf.org/doc/draft-irtf-cfrg-bls-signature/).
75
+
6
76
  *
7
- * ### Summary
8
- * 1. BLS Relies on Bilinear Pairing (expensive)
9
- * 2. Private Keys: 32 bytes
10
- * 3. Public Keys: 48 bytes: 381 bit affine x coordinate, encoded into 48 big-endian bytes.
11
- * 4. Signatures: 96 bytes: two 381 bit integers (affine x coordinate), encoded into two 48 big-endian byte arrays.
12
- * - The signature is a point on the G2 subgroup, which is defined over a finite field
13
- * with elements twice as big as the G1 curve (G2 is over Fp2 rather than Fp. Fp2 is analogous to the
14
- * complex numbers).
15
- * - We also support reversed 96-byte pubkeys & 48-byte short signatures.
16
- * 5. The 12 stands for the Embedding degree.
17
- *
18
- * ### Formulas
19
- * - `P = pk x G` - public keys
20
- * - `S = pk x H(m)` - signing
21
- * - `e(P, H(m)) == e(G, S)` - verification using pairings
22
- * - `e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))` - signature aggregation
23
- *
24
- * ### Compatibility and notes
25
- * 1. It is compatible with Algorand, Chia, Dfinity, Ethereum, Filecoin, ZEC.
26
- * Filecoin uses little endian byte arrays for private keys - make sure to reverse byte order.
27
- * 2. Some projects use G2 for public keys and G1 for signatures. It's called "short signature".
28
- * 3. Curve security level is about 120 bits as per [Barbulescu-Duquesne 2017](https://hal.science/hal-01534101/file/main.pdf)
29
- * 4. Compatible with specs:
30
- * [cfrg-pairing-friendly-curves-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
31
- * [cfrg-bls-signature-05](https://www.rfc-editor.org/rfc/draft-irtf-cfrg-bls-signature-05),
32
- * RFC 9380.
33
- *
34
- * ### Params
35
- * To verify curve parameters, see
36
- * [pairing-friendly-curves spec](https://www.rfc-editor.org/rfc/draft-irtf-cfrg-pairing-friendly-curves-11).
37
- * Basic math is done over finite fields over p.
38
- * More complicated math is done over polynominal extension fields.
39
- * To simplify calculations in Fp12, we construct extension tower:
40
- *
41
- * Embedding degree (k): 12
42
- * Seed (X): -15132376222941642752
43
- * Fr: (x⁴-x²+1)
44
- * Fp: ((x-1)² ⋅ r(x)/3+x)
45
- * (E/Fp): Y²=X³+4
46
- * (Eₜ/Fp²): Y² = X³+4(u+1) (M-type twist)
47
- * Ate loop size: X
48
- *
49
- * ### Towers
50
- * - Fp₁₂ = Fp₆² => Fp₂³
51
- * - Fp(u) / (u² - β) where β = -1
52
- * - Fp₂(v) / (v³ - ξ) where ξ = u + 1
53
- * - Fp₆(w) / (w² - γ) where γ = v
54
- * - Fp²[u] = Fp/u²+1
55
- * - Fp⁶[v] = Fp²/v³-1-u
56
- * - Fp¹²[w] = Fp⁶/w²-v
57
- *
58
- * @todo construct bls & bn fp/fr from seed.
59
77
  * @module
60
78
  */
61
79
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
62
- import { sha256 } from '@noble/hashes/sha2';
63
- import { randomBytes } from '@noble/hashes/utils';
80
+ import { sha256 } from '@noble/hashes/sha2.js';
64
81
  import { bls } from "./abstract/bls.js";
65
82
  import { Field } from "./abstract/modular.js";
66
- import { bitGet, bitLen, bytesToHex, bytesToNumberBE, concatBytes as concatB, ensureBytes, numberToBytesBE, } from "./abstract/utils.js";
83
+ import { abytes, bitGet, bitLen, bytesToHex, bytesToNumberBE, concatBytes, ensureBytes, numberToBytesBE, } from "./utils.js";
67
84
  // Types
68
85
  import { isogenyMap } from "./abstract/hash-to-curve.js";
69
86
  import { psiFrobenius, tower12 } from "./abstract/tower.js";
@@ -71,13 +88,40 @@ import { mapToCurveSimpleSWU, } from "./abstract/weierstrass.js";
71
88
  // Be friendly to bad ECMAScript parsers by not using bigint literals
72
89
  // prettier-ignore
73
90
  const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n = BigInt(4);
91
+ // To verify math:
92
+ // https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11
74
93
  // The BLS parameter x (seed) for BLS12-381. NOTE: it is negative!
94
+ // x = -2^63 - 2^62 - 2^60 - 2^57 - 2^48 - 2^16
75
95
  const BLS_X = BigInt('0xd201000000010000');
96
+ // t = x (called differently in different places)
97
+ // const t = -BLS_X;
76
98
  const BLS_X_LEN = bitLen(BLS_X);
99
+ // a=0, b=4
100
+ // P is characteristic of field Fp, in which curve calculations are done.
101
+ // p = (t-1)² * (t⁴-t²+1)/3 + t
102
+ // bls12_381_Fp = (t-1n)**2n * (t**4n - t**2n + 1n) / 3n + t
103
+ // r*h is curve order, amount of points on curve,
104
+ // where r is order of prime subgroup and h is cofactor.
105
+ // r = t⁴-t²+1
106
+ // r = (t**4n - t**2n + 1n)
107
+ // cofactor h of G1: (t - 1)²/3
108
+ // cofactorG1 = (t-1n)**2n/3n
109
+ // x = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507
110
+ // y = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569
111
+ const bls12_381_CURVE_G1 = {
112
+ p: BigInt('0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'),
113
+ n: BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001'),
114
+ h: BigInt('0x396c8c005555e1568c00aaab0000aaab'),
115
+ a: _0n,
116
+ b: _4n,
117
+ Gx: BigInt('0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb'),
118
+ Gy: BigInt('0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'),
119
+ };
77
120
  // CURVE FIELDS
121
+ export const bls12_381_Fr = Field(bls12_381_CURVE_G1.n, { modOnDecode: true });
78
122
  const { Fp, Fp2, Fp6, Fp4Square, Fp12 } = tower12({
79
123
  // Order of Fp
80
- ORDER: BigInt('0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'),
124
+ ORDER: bls12_381_CURVE_G1.p,
81
125
  // Finite extension field over irreducible polynominal.
82
126
  // Fp(u) / (u² - β) where β = -1
83
127
  FP2_NONRESIDUE: [_1n, _1n],
@@ -143,11 +187,395 @@ const { Fp, Fp2, Fp6, Fp4Square, Fp12 } = tower12({
143
187
  return Fp12.mul(Fp12.mul(Fp12.mul(t2_t5_pow_q2, t4_t1_pow_q3), t6_t1c_pow_q1), t7_t3c_t1);
144
188
  },
145
189
  });
146
- // Finite field over r.
147
- // This particular field is not used anywhere in bls12-381, but it is still useful.
148
- const Fr = Field(BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001'));
149
- // END OF CURVE FIELDS
150
- // HashToCurve
190
+ // GLV endomorphism Ψ(P), for fast cofactor clearing
191
+ const { G2psi, G2psi2 } = psiFrobenius(Fp, Fp2, Fp2.div(Fp2.ONE, Fp2.NONRESIDUE)); // 1/(u+1)
192
+ /**
193
+ * Default hash_to_field / hash-to-curve for BLS.
194
+ * m: 1 for G1, 2 for G2
195
+ * k: target security level in bits
196
+ * hash: any function, e.g. BBS+ uses BLAKE2: see [github](https://github.com/hyperledger/aries-framework-go/issues/2247).
197
+ * Parameter values come from [section 8.8.2 of RFC 9380](https://www.rfc-editor.org/rfc/rfc9380#section-8.8.2).
198
+ */
199
+ const htfDefaults = Object.freeze({
200
+ DST: 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_',
201
+ encodeDST: 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_',
202
+ p: Fp.ORDER,
203
+ m: 2,
204
+ k: 128,
205
+ expand: 'xmd',
206
+ hash: sha256,
207
+ });
208
+ // a=0, b=4
209
+ // cofactor h of G2
210
+ // (t^8 - 4t^7 + 5t^6 - 4t^4 + 6t^3 - 4t^2 - 4t + 13)/9
211
+ // cofactorG2 = (t**8n - 4n*t**7n + 5n*t**6n - 4n*t**4n + 6n*t**3n - 4n*t**2n - 4n*t+13n)/9n
212
+ // x = 3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758*u + 352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160
213
+ // y = 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582*u + 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905
214
+ const bls12_381_CURVE_G2 = {
215
+ p: Fp2.ORDER,
216
+ n: bls12_381_CURVE_G1.n,
217
+ h: BigInt('0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5'),
218
+ a: Fp2.ZERO,
219
+ b: Fp2.fromBigTuple([_4n, _4n]),
220
+ Gx: Fp2.fromBigTuple([
221
+ BigInt('0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8'),
222
+ BigInt('0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e'),
223
+ ]),
224
+ Gy: Fp2.fromBigTuple([
225
+ BigInt('0x0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801'),
226
+ BigInt('0x0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be'),
227
+ ]),
228
+ };
229
+ // Encoding utils
230
+ // Compressed point of infinity
231
+ // Set compressed & point-at-infinity bits
232
+ const COMPZERO = setMask(Fp.toBytes(_0n), { infinity: true, compressed: true });
233
+ function parseMask(bytes) {
234
+ // Copy, so we can remove mask data. It will be removed also later, when Fp.create will call modulo.
235
+ bytes = bytes.slice();
236
+ const mask = bytes[0] & 224;
237
+ const compressed = !!((mask >> 7) & 1); // compression bit (0b1000_0000)
238
+ const infinity = !!((mask >> 6) & 1); // point at infinity bit (0b0100_0000)
239
+ const sort = !!((mask >> 5) & 1); // sort bit (0b0010_0000)
240
+ bytes[0] &= 31; // clear mask (zero first 3 bits)
241
+ return { compressed, infinity, sort, value: bytes };
242
+ }
243
+ function setMask(bytes, mask) {
244
+ if (bytes[0] & 224)
245
+ throw new Error('setMask: non-empty mask');
246
+ if (mask.compressed)
247
+ bytes[0] |= 128;
248
+ if (mask.infinity)
249
+ bytes[0] |= 64;
250
+ if (mask.sort)
251
+ bytes[0] |= 32;
252
+ return bytes;
253
+ }
254
+ function pointG1ToBytes(_c, point, isComp) {
255
+ const { BYTES: L, ORDER: P } = Fp;
256
+ const is0 = point.is0();
257
+ const { x, y } = point.toAffine();
258
+ if (isComp) {
259
+ if (is0)
260
+ return COMPZERO.slice();
261
+ const sort = Boolean((y * _2n) / P);
262
+ return setMask(numberToBytesBE(x, L), { compressed: true, sort });
263
+ }
264
+ else {
265
+ if (is0) {
266
+ return concatBytes(Uint8Array.of(0x40), new Uint8Array(2 * L - 1));
267
+ }
268
+ else {
269
+ return concatBytes(numberToBytesBE(x, L), numberToBytesBE(y, L));
270
+ }
271
+ }
272
+ }
273
+ function signatureG1ToBytes(point) {
274
+ point.assertValidity();
275
+ const { BYTES: L, ORDER: P } = Fp;
276
+ const { x, y } = point.toAffine();
277
+ if (point.is0())
278
+ return COMPZERO.slice();
279
+ const sort = Boolean((y * _2n) / P);
280
+ return setMask(numberToBytesBE(x, L), { compressed: true, sort });
281
+ }
282
+ function pointG1FromBytes(bytes) {
283
+ const { compressed, infinity, sort, value } = parseMask(bytes);
284
+ const { BYTES: L, ORDER: P } = Fp;
285
+ if (value.length === 48 && compressed) {
286
+ const compressedValue = bytesToNumberBE(value);
287
+ // Zero
288
+ const x = Fp.create(compressedValue & Fp.MASK);
289
+ if (infinity) {
290
+ if (x !== _0n)
291
+ throw new Error('invalid G1 point: non-empty, at infinity, with compression');
292
+ return { x: _0n, y: _0n };
293
+ }
294
+ const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381_CURVE_G1.b)); // y² = x³ + b
295
+ let y = Fp.sqrt(right);
296
+ if (!y)
297
+ throw new Error('invalid G1 point: compressed point');
298
+ if ((y * _2n) / P !== BigInt(sort))
299
+ y = Fp.neg(y);
300
+ return { x: Fp.create(x), y: Fp.create(y) };
301
+ }
302
+ else if (value.length === 96 && !compressed) {
303
+ // Check if the infinity flag is set
304
+ const x = bytesToNumberBE(value.subarray(0, L));
305
+ const y = bytesToNumberBE(value.subarray(L));
306
+ if (infinity) {
307
+ if (x !== _0n || y !== _0n)
308
+ throw new Error('G1: non-empty point at infinity');
309
+ return bls12_381.G1.Point.ZERO.toAffine();
310
+ }
311
+ return { x: Fp.create(x), y: Fp.create(y) };
312
+ }
313
+ else {
314
+ throw new Error('invalid G1 point: expected 48/96 bytes');
315
+ }
316
+ }
317
+ function signatureG1FromBytes(hex) {
318
+ const { infinity, sort, value } = parseMask(ensureBytes('signatureHex', hex, 48));
319
+ const P = Fp.ORDER;
320
+ const Point = bls12_381.G1.Point;
321
+ const compressedValue = bytesToNumberBE(value);
322
+ // Zero
323
+ if (infinity)
324
+ return Point.ZERO;
325
+ const x = Fp.create(compressedValue & Fp.MASK);
326
+ const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381_CURVE_G1.b)); // y² = x³ + b
327
+ let y = Fp.sqrt(right);
328
+ if (!y)
329
+ throw new Error('invalid G1 point: compressed');
330
+ const aflag = BigInt(sort);
331
+ if ((y * _2n) / P !== aflag)
332
+ y = Fp.neg(y);
333
+ const point = Point.fromAffine({ x, y });
334
+ point.assertValidity();
335
+ return point;
336
+ }
337
+ function pointG2ToBytes(_c, point, isComp) {
338
+ const { BYTES: L, ORDER: P } = Fp;
339
+ const is0 = point.is0();
340
+ const { x, y } = point.toAffine();
341
+ if (isComp) {
342
+ if (is0)
343
+ return concatBytes(COMPZERO, numberToBytesBE(_0n, L));
344
+ const flag = Boolean(y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P);
345
+ return concatBytes(setMask(numberToBytesBE(x.c1, L), { compressed: true, sort: flag }), numberToBytesBE(x.c0, L));
346
+ }
347
+ else {
348
+ if (is0)
349
+ return concatBytes(Uint8Array.of(0x40), new Uint8Array(4 * L - 1));
350
+ const { re: x0, im: x1 } = Fp2.reim(x);
351
+ const { re: y0, im: y1 } = Fp2.reim(y);
352
+ return concatBytes(numberToBytesBE(x1, L), numberToBytesBE(x0, L), numberToBytesBE(y1, L), numberToBytesBE(y0, L));
353
+ }
354
+ }
355
+ function signatureG2ToBytes(point) {
356
+ point.assertValidity();
357
+ const { BYTES: L } = Fp;
358
+ if (point.is0())
359
+ return concatBytes(COMPZERO, numberToBytesBE(_0n, L));
360
+ const { x, y } = point.toAffine();
361
+ const { re: x0, im: x1 } = Fp2.reim(x);
362
+ const { re: y0, im: y1 } = Fp2.reim(y);
363
+ const tmp = y1 > _0n ? y1 * _2n : y0 * _2n;
364
+ const sort = Boolean((tmp / Fp.ORDER) & _1n);
365
+ const z2 = x0;
366
+ return concatBytes(setMask(numberToBytesBE(x1, L), { sort, compressed: true }), numberToBytesBE(z2, L));
367
+ }
368
+ function pointG2FromBytes(bytes) {
369
+ const { BYTES: L, ORDER: P } = Fp;
370
+ const { compressed, infinity, sort, value } = parseMask(bytes);
371
+ if ((!compressed && !infinity && sort) || // 00100000
372
+ (!compressed && infinity && sort) || // 01100000
373
+ (sort && infinity && compressed) // 11100000
374
+ ) {
375
+ throw new Error('invalid encoding flag: ' + (bytes[0] & 224));
376
+ }
377
+ const slc = (b, from, to) => bytesToNumberBE(b.slice(from, to));
378
+ if (value.length === 96 && compressed) {
379
+ if (infinity) {
380
+ // check that all bytes are 0
381
+ if (value.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
382
+ throw new Error('invalid G2 point: compressed');
383
+ }
384
+ return { x: Fp2.ZERO, y: Fp2.ZERO };
385
+ }
386
+ const x_1 = slc(value, 0, L);
387
+ const x_0 = slc(value, L, 2 * L);
388
+ const x = Fp2.create({ c0: Fp.create(x_0), c1: Fp.create(x_1) });
389
+ const right = Fp2.add(Fp2.pow(x, _3n), bls12_381_CURVE_G2.b); // y² = x³ + 4 * (u+1) = x³ + b
390
+ let y = Fp2.sqrt(right);
391
+ const Y_bit = y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P ? _1n : _0n;
392
+ y = sort && Y_bit > 0 ? y : Fp2.neg(y);
393
+ return { x, y };
394
+ }
395
+ else if (value.length === 192 && !compressed) {
396
+ if (infinity) {
397
+ if (value.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
398
+ throw new Error('invalid G2 point: uncompressed');
399
+ }
400
+ return { x: Fp2.ZERO, y: Fp2.ZERO };
401
+ }
402
+ const x1 = slc(value, 0 * L, 1 * L);
403
+ const x0 = slc(value, 1 * L, 2 * L);
404
+ const y1 = slc(value, 2 * L, 3 * L);
405
+ const y0 = slc(value, 3 * L, 4 * L);
406
+ return { x: Fp2.fromBigTuple([x0, x1]), y: Fp2.fromBigTuple([y0, y1]) };
407
+ }
408
+ else {
409
+ throw new Error('invalid G2 point: expected 96/192 bytes');
410
+ }
411
+ }
412
+ function signatureG2FromBytes(hex) {
413
+ const { ORDER: P } = Fp;
414
+ // TODO: Optimize, it's very slow because of sqrt.
415
+ const { infinity, sort, value } = parseMask(ensureBytes('signatureHex', hex));
416
+ const Point = bls12_381.G2.Point;
417
+ const half = value.length / 2;
418
+ if (half !== 48 && half !== 96)
419
+ throw new Error('invalid compressed signature length, expected 96/192 bytes');
420
+ const z1 = bytesToNumberBE(value.slice(0, half));
421
+ const z2 = bytesToNumberBE(value.slice(half));
422
+ // Indicates the infinity point
423
+ if (infinity)
424
+ return Point.ZERO;
425
+ const x1 = Fp.create(z1 & Fp.MASK);
426
+ const x2 = Fp.create(z2);
427
+ const x = Fp2.create({ c0: x2, c1: x1 });
428
+ const y2 = Fp2.add(Fp2.pow(x, _3n), bls12_381_CURVE_G2.b); // y² = x³ + 4
429
+ // The slow part
430
+ let y = Fp2.sqrt(y2);
431
+ if (!y)
432
+ throw new Error('Failed to find a square root');
433
+ // Choose the y whose leftmost bit of the imaginary part is equal to the a_flag1
434
+ // If y1 happens to be zero, then use the bit of y0
435
+ const { re: y0, im: y1 } = Fp2.reim(y);
436
+ const aflag1 = BigInt(sort);
437
+ const isGreater = y1 > _0n && (y1 * _2n) / P !== aflag1;
438
+ const is0 = y1 === _0n && (y0 * _2n) / P !== aflag1;
439
+ if (isGreater || is0)
440
+ y = Fp2.neg(y);
441
+ const point = Point.fromAffine({ x, y });
442
+ point.assertValidity();
443
+ return point;
444
+ }
445
+ /**
446
+ * bls12-381 pairing-friendly curve.
447
+ * @example
448
+ * import { bls12_381 as bls } from '@noble/curves/bls12-381';
449
+ * // G1 keys, G2 signatures
450
+ * const privateKey = '67d53f170b908cabb9eb326c3c337762d59289a8fec79f7bc9254b584b73265c';
451
+ * const message = '64726e3da8';
452
+ * const publicKey = bls.getPublicKey(privateKey);
453
+ * const signature = bls.sign(message, privateKey);
454
+ * const isValid = bls.verify(signature, message, publicKey);
455
+ */
456
+ export const bls12_381 = bls({
457
+ // Fields
458
+ fields: {
459
+ Fp,
460
+ Fp2,
461
+ Fp6,
462
+ Fp12,
463
+ Fr: bls12_381_Fr,
464
+ },
465
+ // G1: y² = x³ + 4
466
+ G1: {
467
+ ...bls12_381_CURVE_G1,
468
+ Fp,
469
+ htfDefaults: { ...htfDefaults, m: 1, DST: 'BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_' },
470
+ wrapPrivateKey: true,
471
+ allowInfinityPoint: true,
472
+ // Checks is the point resides in prime-order subgroup.
473
+ // point.isTorsionFree() should return true for valid points
474
+ // It returns false for shitty points.
475
+ // https://eprint.iacr.org/2021/1130.pdf
476
+ isTorsionFree: (c, point) => {
477
+ // GLV endomorphism ψ(P)
478
+ const beta = BigInt('0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe');
479
+ const phi = new c(Fp.mul(point.X, beta), point.Y, point.Z);
480
+ // TODO: unroll
481
+ const xP = point.multiplyUnsafe(BLS_X).negate(); // [x]P
482
+ const u2P = xP.multiplyUnsafe(BLS_X); // [u2]P
483
+ return u2P.equals(phi);
484
+ },
485
+ // Clear cofactor of G1
486
+ // https://eprint.iacr.org/2019/403
487
+ clearCofactor: (_c, point) => {
488
+ // return this.multiplyUnsafe(CURVE.h);
489
+ return point.multiplyUnsafe(BLS_X).add(point); // x*P + P
490
+ },
491
+ mapToCurve: mapToG1,
492
+ fromBytes: pointG1FromBytes,
493
+ toBytes: pointG1ToBytes,
494
+ ShortSignature: {
495
+ fromBytes(bytes) {
496
+ abytes(bytes);
497
+ return signatureG1FromBytes(bytes);
498
+ },
499
+ fromHex(hex) {
500
+ return signatureG1FromBytes(hex);
501
+ },
502
+ toBytes(point) {
503
+ return signatureG1ToBytes(point);
504
+ },
505
+ toRawBytes(point) {
506
+ return signatureG1ToBytes(point);
507
+ },
508
+ toHex(point) {
509
+ return bytesToHex(signatureG1ToBytes(point));
510
+ },
511
+ },
512
+ },
513
+ G2: {
514
+ ...bls12_381_CURVE_G2,
515
+ Fp: Fp2,
516
+ // https://datatracker.ietf.org/doc/html/rfc9380#name-clearing-the-cofactor
517
+ // https://datatracker.ietf.org/doc/html/rfc9380#name-cofactor-clearing-for-bls12
518
+ hEff: BigInt('0xbc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551'),
519
+ htfDefaults: { ...htfDefaults },
520
+ wrapPrivateKey: true,
521
+ allowInfinityPoint: true,
522
+ mapToCurve: mapToG2,
523
+ // Checks is the point resides in prime-order subgroup.
524
+ // point.isTorsionFree() should return true for valid points
525
+ // It returns false for shitty points.
526
+ // https://eprint.iacr.org/2021/1130.pdf
527
+ // Older version: https://eprint.iacr.org/2019/814.pdf
528
+ isTorsionFree: (c, P) => {
529
+ return P.multiplyUnsafe(BLS_X).negate().equals(G2psi(c, P)); // ψ(P) == [u](P)
530
+ },
531
+ // Maps the point into the prime-order subgroup G2.
532
+ // clear_cofactor_bls12381_g2 from RFC 9380.
533
+ // https://eprint.iacr.org/2017/419.pdf
534
+ // prettier-ignore
535
+ clearCofactor: (c, P) => {
536
+ const x = BLS_X;
537
+ let t1 = P.multiplyUnsafe(x).negate(); // [-x]P
538
+ let t2 = G2psi(c, P); // Ψ(P)
539
+ let t3 = P.double(); // 2P
540
+ t3 = G2psi2(c, t3); // Ψ²(2P)
541
+ t3 = t3.subtract(t2); // Ψ²(2P) - Ψ(P)
542
+ t2 = t1.add(t2); // [-x]P + Ψ(P)
543
+ t2 = t2.multiplyUnsafe(x).negate(); // [x²]P - [x]Ψ(P)
544
+ t3 = t3.add(t2); // Ψ²(2P) - Ψ(P) + [x²]P - [x]Ψ(P)
545
+ t3 = t3.subtract(t1); // Ψ²(2P) - Ψ(P) + [x²]P - [x]Ψ(P) + [x]P
546
+ const Q = t3.subtract(P); // Ψ²(2P) - Ψ(P) + [x²]P - [x]Ψ(P) + [x]P - 1P
547
+ return Q; // [x²-x-1]P + [x-1]Ψ(P) + Ψ²(2P)
548
+ },
549
+ fromBytes: pointG2FromBytes,
550
+ toBytes: pointG2ToBytes,
551
+ Signature: {
552
+ fromBytes(bytes) {
553
+ abytes(bytes);
554
+ return signatureG2FromBytes(bytes);
555
+ },
556
+ fromHex(hex) {
557
+ return signatureG2FromBytes(hex);
558
+ },
559
+ toBytes(point) {
560
+ return signatureG2ToBytes(point);
561
+ },
562
+ toRawBytes(point) {
563
+ return signatureG2ToBytes(point);
564
+ },
565
+ toHex(point) {
566
+ return bytesToHex(signatureG2ToBytes(point));
567
+ },
568
+ },
569
+ },
570
+ params: {
571
+ ateLoopSize: BLS_X, // The BLS parameter x for BLS12-381
572
+ r: bls12_381_CURVE_G1.n, // order; z⁴ − z² + 1; CURVE.n from other curves
573
+ xNegative: true,
574
+ twistType: 'multiplicative',
575
+ },
576
+ htfDefaults,
577
+ hash: sha256,
578
+ });
151
579
  // 3-isogeny map from E' to E https://www.rfc-editor.org/rfc/rfc9380#appendix-E.3
152
580
  const isogenyMapG2 = isogenyMap(Fp2, [
153
581
  // xNum
@@ -287,414 +715,24 @@ const isogenyMapG1 = isogenyMap(Fp, [
287
715
  '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001', // LAST 1
288
716
  ],
289
717
  ].map((i) => i.map((j) => BigInt(j))));
290
- // SWU Map - Fp2 to G2': y² = x³ + 240i * x + 1012 + 1012i
291
- const G2_SWU = mapToCurveSimpleSWU(Fp2, {
292
- A: Fp2.create({ c0: Fp.create(_0n), c1: Fp.create(BigInt(240)) }), // A' = 240 * I
293
- B: Fp2.create({ c0: Fp.create(BigInt(1012)), c1: Fp.create(BigInt(1012)) }), // B' = 1012 * (1 + I)
294
- Z: Fp2.create({ c0: Fp.create(BigInt(-2)), c1: Fp.create(BigInt(-1)) }), // Z: -(2 + I)
295
- });
296
718
  // Optimized SWU Map - Fp to G1
297
719
  const G1_SWU = mapToCurveSimpleSWU(Fp, {
298
720
  A: Fp.create(BigInt('0x144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1d')),
299
721
  B: Fp.create(BigInt('0x12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0')),
300
722
  Z: Fp.create(BigInt(11)),
301
723
  });
302
- // GLV endomorphism Ψ(P), for fast cofactor clearing
303
- const { G2psi, G2psi2 } = psiFrobenius(Fp, Fp2, Fp2.div(Fp2.ONE, Fp2.NONRESIDUE)); // 1/(u+1)
304
- // Default hash_to_field options are for hash to G2.
305
- //
306
- // Parameter definitions are in section 5.3 of the spec unless otherwise noted.
307
- // Parameter values come from section 8.8.2 of the spec.
308
- // https://www.rfc-editor.org/rfc/rfc9380#section-8.8.2
309
- //
310
- // Base field F is GF(p^m)
311
- // p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
312
- // m = 2 (or 1 for G1 see section 8.8.1)
313
- // k = 128
314
- const htfDefaults = Object.freeze({
315
- // DST: a domain separation tag
316
- // defined in section 2.2.5
317
- // Use utils.getDSTLabel(), utils.setDSTLabel(value)
318
- DST: 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_',
319
- encodeDST: 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_',
320
- // p: the characteristic of F
321
- // where F is a finite field of characteristic p and order q = p^m
322
- p: Fp.ORDER,
323
- // m: the extension degree of F, m >= 1
324
- // where F is a finite field of characteristic p and order q = p^m
325
- m: 2,
326
- // k: the target security level for the suite in bits
327
- // defined in section 5.1
328
- k: 128,
329
- // option to use a message that has already been processed by
330
- // expand_message_xmd
331
- expand: 'xmd',
332
- // Hash functions for: expand_message_xmd is appropriate for use with a
333
- // wide range of hash functions, including SHA-2, SHA-3, BLAKE2, and others.
334
- // BBS+ uses blake2: https://github.com/hyperledger/aries-framework-go/issues/2247
335
- hash: sha256,
724
+ // SWU Map - Fp2 to G2': y² = x³ + 240i * x + 1012 + 1012i
725
+ const G2_SWU = mapToCurveSimpleSWU(Fp2, {
726
+ A: Fp2.create({ c0: Fp.create(_0n), c1: Fp.create(BigInt(240)) }), // A' = 240 * I
727
+ B: Fp2.create({ c0: Fp.create(BigInt(1012)), c1: Fp.create(BigInt(1012)) }), // B' = 1012 * (1 + I)
728
+ Z: Fp2.create({ c0: Fp.create(BigInt(-2)), c1: Fp.create(BigInt(-1)) }), // Z: -(2 + I)
336
729
  });
337
- // Encoding utils
338
- // Point on G1 curve: (x, y)
339
- // Compressed point of infinity
340
- const COMPRESSED_ZERO = setMask(Fp.toBytes(_0n), { infinity: true, compressed: true }); // set compressed & point-at-infinity bits
341
- function parseMask(bytes) {
342
- // Copy, so we can remove mask data. It will be removed also later, when Fp.create will call modulo.
343
- bytes = bytes.slice();
344
- const mask = bytes[0] & 224;
345
- const compressed = !!((mask >> 7) & 1); // compression bit (0b1000_0000)
346
- const infinity = !!((mask >> 6) & 1); // point at infinity bit (0b0100_0000)
347
- const sort = !!((mask >> 5) & 1); // sort bit (0b0010_0000)
348
- bytes[0] &= 31; // clear mask (zero first 3 bits)
349
- return { compressed, infinity, sort, value: bytes };
350
- }
351
- function setMask(bytes, mask) {
352
- if (bytes[0] & 224)
353
- throw new Error('setMask: non-empty mask');
354
- if (mask.compressed)
355
- bytes[0] |= 128;
356
- if (mask.infinity)
357
- bytes[0] |= 64;
358
- if (mask.sort)
359
- bytes[0] |= 32;
360
- return bytes;
730
+ function mapToG1(scalars) {
731
+ const { x, y } = G1_SWU(Fp.create(scalars[0]));
732
+ return isogenyMapG1(x, y);
361
733
  }
362
- function signatureG1ToRawBytes(point) {
363
- point.assertValidity();
364
- const isZero = point.equals(bls12_381.G1.ProjectivePoint.ZERO);
365
- const { x, y } = point.toAffine();
366
- if (isZero)
367
- return COMPRESSED_ZERO.slice();
368
- const P = Fp.ORDER;
369
- const sort = Boolean((y * _2n) / P);
370
- return setMask(numberToBytesBE(x, Fp.BYTES), { compressed: true, sort });
371
- }
372
- function signatureG2ToRawBytes(point) {
373
- // NOTE: by some reasons it was missed in bls12-381, looks like bug
374
- point.assertValidity();
375
- const len = Fp.BYTES;
376
- if (point.equals(bls12_381.G2.ProjectivePoint.ZERO))
377
- return concatB(COMPRESSED_ZERO, numberToBytesBE(_0n, len));
378
- const { x, y } = point.toAffine();
379
- const { re: x0, im: x1 } = Fp2.reim(x);
380
- const { re: y0, im: y1 } = Fp2.reim(y);
381
- const tmp = y1 > _0n ? y1 * _2n : y0 * _2n;
382
- const sort = Boolean((tmp / Fp.ORDER) & _1n);
383
- const z2 = x0;
384
- return concatB(setMask(numberToBytesBE(x1, len), { sort, compressed: true }), numberToBytesBE(z2, len));
734
+ function mapToG2(scalars) {
735
+ const { x, y } = G2_SWU(Fp2.fromBigTuple(scalars));
736
+ return isogenyMapG2(x, y);
385
737
  }
386
- /**
387
- * bls12-381 pairing-friendly curve.
388
- * @example
389
- * import { bls12_381 as bls } from '@noble/curves/bls12-381';
390
- * // G1 keys, G2 signatures
391
- * const privateKey = '67d53f170b908cabb9eb326c3c337762d59289a8fec79f7bc9254b584b73265c';
392
- * const message = '64726e3da8';
393
- * const publicKey = bls.getPublicKey(privateKey);
394
- * const signature = bls.sign(message, privateKey);
395
- * const isValid = bls.verify(signature, message, publicKey);
396
- */
397
- export const bls12_381 = bls({
398
- // Fields
399
- fields: {
400
- Fp,
401
- Fp2,
402
- Fp6,
403
- Fp12,
404
- Fr,
405
- },
406
- // G1 is the order-q subgroup of E1(Fp) : y² = x³ + 4, #E1(Fp) = h1q, where
407
- // characteristic; z + (z⁴ - z² + 1)(z - 1)²/3
408
- G1: {
409
- Fp,
410
- // cofactor; (z - 1)²/3
411
- h: BigInt('0x396c8c005555e1568c00aaab0000aaab'),
412
- // generator's coordinates
413
- // x = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507
414
- // y = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569
415
- Gx: BigInt('0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb'),
416
- Gy: BigInt('0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'),
417
- a: Fp.ZERO,
418
- b: _4n,
419
- htfDefaults: { ...htfDefaults, m: 1, DST: 'BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_' },
420
- wrapPrivateKey: true,
421
- allowInfinityPoint: true,
422
- // Checks is the point resides in prime-order subgroup.
423
- // point.isTorsionFree() should return true for valid points
424
- // It returns false for shitty points.
425
- // https://eprint.iacr.org/2021/1130.pdf
426
- isTorsionFree: (c, point) => {
427
- // GLV endomorphism ψ(P)
428
- const beta = BigInt('0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe');
429
- const phi = new c(Fp.mul(point.px, beta), point.py, point.pz);
430
- // TODO: unroll
431
- const xP = point.multiplyUnsafe(BLS_X).negate(); // [x]P
432
- const u2P = xP.multiplyUnsafe(BLS_X); // [u2]P
433
- return u2P.equals(phi);
434
- },
435
- // Clear cofactor of G1
436
- // https://eprint.iacr.org/2019/403
437
- clearCofactor: (_c, point) => {
438
- // return this.multiplyUnsafe(CURVE.h);
439
- return point.multiplyUnsafe(BLS_X).add(point); // x*P + P
440
- },
441
- mapToCurve: (scalars) => {
442
- const { x, y } = G1_SWU(Fp.create(scalars[0]));
443
- return isogenyMapG1(x, y);
444
- },
445
- fromBytes: (bytes) => {
446
- const { compressed, infinity, sort, value } = parseMask(bytes);
447
- if (value.length === 48 && compressed) {
448
- // TODO: Fp.bytes
449
- const P = Fp.ORDER;
450
- const compressedValue = bytesToNumberBE(value);
451
- // Zero
452
- const x = Fp.create(compressedValue & Fp.MASK);
453
- if (infinity) {
454
- if (x !== _0n)
455
- throw new Error('G1: non-empty compressed point at infinity');
456
- return { x: _0n, y: _0n };
457
- }
458
- const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381.params.G1b)); // y² = x³ + b
459
- let y = Fp.sqrt(right);
460
- if (!y)
461
- throw new Error('invalid compressed G1 point');
462
- if ((y * _2n) / P !== BigInt(sort))
463
- y = Fp.neg(y);
464
- return { x: Fp.create(x), y: Fp.create(y) };
465
- }
466
- else if (value.length === 96 && !compressed) {
467
- // Check if the infinity flag is set
468
- const x = bytesToNumberBE(value.subarray(0, Fp.BYTES));
469
- const y = bytesToNumberBE(value.subarray(Fp.BYTES));
470
- if (infinity) {
471
- if (x !== _0n || y !== _0n)
472
- throw new Error('G1: non-empty point at infinity');
473
- return bls12_381.G1.ProjectivePoint.ZERO.toAffine();
474
- }
475
- return { x: Fp.create(x), y: Fp.create(y) };
476
- }
477
- else {
478
- throw new Error('invalid point G1, expected 48/96 bytes');
479
- }
480
- },
481
- toBytes: (c, point, isCompressed) => {
482
- const isZero = point.equals(c.ZERO);
483
- const { x, y } = point.toAffine();
484
- if (isCompressed) {
485
- if (isZero)
486
- return COMPRESSED_ZERO.slice();
487
- const P = Fp.ORDER;
488
- const sort = Boolean((y * _2n) / P);
489
- return setMask(numberToBytesBE(x, Fp.BYTES), { compressed: true, sort });
490
- }
491
- else {
492
- if (isZero) {
493
- // 2x PUBLIC_KEY_LENGTH
494
- const x = concatB(new Uint8Array([0x40]), new Uint8Array(2 * Fp.BYTES - 1));
495
- return x;
496
- }
497
- else {
498
- return concatB(numberToBytesBE(x, Fp.BYTES), numberToBytesBE(y, Fp.BYTES));
499
- }
500
- }
501
- },
502
- ShortSignature: {
503
- fromHex(hex) {
504
- const { infinity, sort, value } = parseMask(ensureBytes('signatureHex', hex, 48));
505
- const P = Fp.ORDER;
506
- const compressedValue = bytesToNumberBE(value);
507
- // Zero
508
- if (infinity)
509
- return bls12_381.G1.ProjectivePoint.ZERO;
510
- const x = Fp.create(compressedValue & Fp.MASK);
511
- const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381.params.G1b)); // y² = x³ + b
512
- let y = Fp.sqrt(right);
513
- if (!y)
514
- throw new Error('invalid compressed G1 point');
515
- const aflag = BigInt(sort);
516
- if ((y * _2n) / P !== aflag)
517
- y = Fp.neg(y);
518
- const point = bls12_381.G1.ProjectivePoint.fromAffine({ x, y });
519
- point.assertValidity();
520
- return point;
521
- },
522
- toRawBytes(point) {
523
- return signatureG1ToRawBytes(point);
524
- },
525
- toHex(point) {
526
- return bytesToHex(signatureG1ToRawBytes(point));
527
- },
528
- },
529
- },
530
- // G2 is the order-q subgroup of E2(Fp²) : y² = x³+4(1+√−1),
531
- // where Fp2 is Fp[√−1]/(x2+1). #E2(Fp2 ) = h2q, where
532
- // G² - 1
533
- // h2q
534
- G2: {
535
- Fp: Fp2,
536
- // cofactor
537
- h: BigInt('0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5'),
538
- Gx: Fp2.fromBigTuple([
539
- BigInt('0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8'),
540
- BigInt('0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e'),
541
- ]),
542
- // y =
543
- // 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582,
544
- // 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905
545
- Gy: Fp2.fromBigTuple([
546
- BigInt('0x0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801'),
547
- BigInt('0x0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be'),
548
- ]),
549
- a: Fp2.ZERO,
550
- b: Fp2.fromBigTuple([_4n, _4n]),
551
- hEff: BigInt('0xbc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551'),
552
- htfDefaults: { ...htfDefaults },
553
- wrapPrivateKey: true,
554
- allowInfinityPoint: true,
555
- mapToCurve: (scalars) => {
556
- const { x, y } = G2_SWU(Fp2.fromBigTuple(scalars));
557
- return isogenyMapG2(x, y);
558
- },
559
- // Checks is the point resides in prime-order subgroup.
560
- // point.isTorsionFree() should return true for valid points
561
- // It returns false for shitty points.
562
- // https://eprint.iacr.org/2021/1130.pdf
563
- // Older version: https://eprint.iacr.org/2019/814.pdf
564
- isTorsionFree: (c, P) => {
565
- return P.multiplyUnsafe(BLS_X).negate().equals(G2psi(c, P)); // ψ(P) == [u](P)
566
- },
567
- // Maps the point into the prime-order subgroup G2.
568
- // clear_cofactor_bls12381_g2 from RFC 9380.
569
- // https://eprint.iacr.org/2017/419.pdf
570
- // prettier-ignore
571
- clearCofactor: (c, P) => {
572
- const x = BLS_X;
573
- let t1 = P.multiplyUnsafe(x).negate(); // [-x]P
574
- let t2 = G2psi(c, P); // Ψ(P)
575
- let t3 = P.double(); // 2P
576
- t3 = G2psi2(c, t3); // Ψ²(2P)
577
- t3 = t3.subtract(t2); // Ψ²(2P) - Ψ(P)
578
- t2 = t1.add(t2); // [-x]P + Ψ(P)
579
- t2 = t2.multiplyUnsafe(x).negate(); // [x²]P - [x]Ψ(P)
580
- t3 = t3.add(t2); // Ψ²(2P) - Ψ(P) + [x²]P - [x]Ψ(P)
581
- t3 = t3.subtract(t1); // Ψ²(2P) - Ψ(P) + [x²]P - [x]Ψ(P) + [x]P
582
- const Q = t3.subtract(P); // Ψ²(2P) - Ψ(P) + [x²]P - [x]Ψ(P) + [x]P - 1P
583
- return Q; // [x²-x-1]P + [x-1]Ψ(P) + Ψ²(2P)
584
- },
585
- fromBytes: (bytes) => {
586
- const { compressed, infinity, sort, value } = parseMask(bytes);
587
- if ((!compressed && !infinity && sort) || // 00100000
588
- (!compressed && infinity && sort) || // 01100000
589
- (sort && infinity && compressed) // 11100000
590
- ) {
591
- throw new Error('invalid encoding flag: ' + (bytes[0] & 224));
592
- }
593
- const L = Fp.BYTES;
594
- const slc = (b, from, to) => bytesToNumberBE(b.slice(from, to));
595
- if (value.length === 96 && compressed) {
596
- const b = bls12_381.params.G2b;
597
- const P = Fp.ORDER;
598
- if (infinity) {
599
- // check that all bytes are 0
600
- if (value.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
601
- throw new Error('invalid compressed G2 point');
602
- }
603
- return { x: Fp2.ZERO, y: Fp2.ZERO };
604
- }
605
- const x_1 = slc(value, 0, L);
606
- const x_0 = slc(value, L, 2 * L);
607
- const x = Fp2.create({ c0: Fp.create(x_0), c1: Fp.create(x_1) });
608
- const right = Fp2.add(Fp2.pow(x, _3n), b); // y² = x³ + 4 * (u+1) = x³ + b
609
- let y = Fp2.sqrt(right);
610
- const Y_bit = y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P ? _1n : _0n;
611
- y = sort && Y_bit > 0 ? y : Fp2.neg(y);
612
- return { x, y };
613
- }
614
- else if (value.length === 192 && !compressed) {
615
- if (infinity) {
616
- if (value.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
617
- throw new Error('invalid uncompressed G2 point');
618
- }
619
- return { x: Fp2.ZERO, y: Fp2.ZERO };
620
- }
621
- const x1 = slc(value, 0, L);
622
- const x0 = slc(value, L, 2 * L);
623
- const y1 = slc(value, 2 * L, 3 * L);
624
- const y0 = slc(value, 3 * L, 4 * L);
625
- return { x: Fp2.fromBigTuple([x0, x1]), y: Fp2.fromBigTuple([y0, y1]) };
626
- }
627
- else {
628
- throw new Error('invalid point G2, expected 96/192 bytes');
629
- }
630
- },
631
- toBytes: (c, point, isCompressed) => {
632
- const { BYTES: len, ORDER: P } = Fp;
633
- const isZero = point.equals(c.ZERO);
634
- const { x, y } = point.toAffine();
635
- if (isCompressed) {
636
- if (isZero)
637
- return concatB(COMPRESSED_ZERO, numberToBytesBE(_0n, len));
638
- const flag = Boolean(y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P);
639
- return concatB(setMask(numberToBytesBE(x.c1, len), { compressed: true, sort: flag }), numberToBytesBE(x.c0, len));
640
- }
641
- else {
642
- if (isZero)
643
- return concatB(new Uint8Array([0x40]), new Uint8Array(4 * len - 1)); // bytes[0] |= 1 << 6;
644
- const { re: x0, im: x1 } = Fp2.reim(x);
645
- const { re: y0, im: y1 } = Fp2.reim(y);
646
- return concatB(numberToBytesBE(x1, len), numberToBytesBE(x0, len), numberToBytesBE(y1, len), numberToBytesBE(y0, len));
647
- }
648
- },
649
- Signature: {
650
- // TODO: Optimize, it's very slow because of sqrt.
651
- fromHex(hex) {
652
- const { infinity, sort, value } = parseMask(ensureBytes('signatureHex', hex));
653
- const P = Fp.ORDER;
654
- const half = value.length / 2;
655
- if (half !== 48 && half !== 96)
656
- throw new Error('invalid compressed signature length, must be 96 or 192');
657
- const z1 = bytesToNumberBE(value.slice(0, half));
658
- const z2 = bytesToNumberBE(value.slice(half));
659
- // Indicates the infinity point
660
- if (infinity)
661
- return bls12_381.G2.ProjectivePoint.ZERO;
662
- const x1 = Fp.create(z1 & Fp.MASK);
663
- const x2 = Fp.create(z2);
664
- const x = Fp2.create({ c0: x2, c1: x1 });
665
- const y2 = Fp2.add(Fp2.pow(x, _3n), bls12_381.params.G2b); // y² = x³ + 4
666
- // The slow part
667
- let y = Fp2.sqrt(y2);
668
- if (!y)
669
- throw new Error('Failed to find a square root');
670
- // Choose the y whose leftmost bit of the imaginary part is equal to the a_flag1
671
- // If y1 happens to be zero, then use the bit of y0
672
- const { re: y0, im: y1 } = Fp2.reim(y);
673
- const aflag1 = BigInt(sort);
674
- const isGreater = y1 > _0n && (y1 * _2n) / P !== aflag1;
675
- const isZero = y1 === _0n && (y0 * _2n) / P !== aflag1;
676
- if (isGreater || isZero)
677
- y = Fp2.neg(y);
678
- const point = bls12_381.G2.ProjectivePoint.fromAffine({ x, y });
679
- point.assertValidity();
680
- return point;
681
- },
682
- toRawBytes(point) {
683
- return signatureG2ToRawBytes(point);
684
- },
685
- toHex(point) {
686
- return bytesToHex(signatureG2ToRawBytes(point));
687
- },
688
- },
689
- },
690
- params: {
691
- ateLoopSize: BLS_X, // The BLS parameter x for BLS12-381
692
- r: Fr.ORDER, // order; z⁴ − z² + 1; CURVE.n from other curves
693
- xNegative: true,
694
- twistType: 'multiplicative',
695
- },
696
- htfDefaults,
697
- hash: sha256,
698
- randomBytes,
699
- });
700
738
  //# sourceMappingURL=bls12-381.js.map