@noble/curves 1.9.7 → 2.0.0-beta.2

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 (242) hide show
  1. package/README.md +520 -505
  2. package/abstract/bls.d.ts +58 -120
  3. package/abstract/bls.d.ts.map +1 -1
  4. package/abstract/bls.js +108 -152
  5. package/abstract/bls.js.map +1 -1
  6. package/abstract/curve.d.ts +18 -54
  7. package/abstract/curve.d.ts.map +1 -1
  8. package/abstract/curve.js +30 -49
  9. package/abstract/curve.js.map +1 -1
  10. package/abstract/edwards.d.ts +18 -77
  11. package/abstract/edwards.d.ts.map +1 -1
  12. package/abstract/edwards.js +68 -144
  13. package/abstract/edwards.js.map +1 -1
  14. package/abstract/fft.js +14 -27
  15. package/abstract/fft.js.map +1 -1
  16. package/abstract/hash-to-curve.d.ts +35 -47
  17. package/abstract/hash-to-curve.d.ts.map +1 -1
  18. package/abstract/hash-to-curve.js +42 -46
  19. package/abstract/hash-to-curve.js.map +1 -1
  20. package/abstract/modular.d.ts +5 -17
  21. package/abstract/modular.d.ts.map +1 -1
  22. package/abstract/modular.js +170 -169
  23. package/abstract/modular.js.map +1 -1
  24. package/abstract/montgomery.d.ts +7 -12
  25. package/abstract/montgomery.d.ts.map +1 -1
  26. package/abstract/montgomery.js +22 -29
  27. package/abstract/montgomery.js.map +1 -1
  28. package/abstract/oprf.d.ts +282 -0
  29. package/abstract/oprf.d.ts.map +1 -0
  30. package/abstract/oprf.js +297 -0
  31. package/abstract/oprf.js.map +1 -0
  32. package/abstract/poseidon.d.ts.map +1 -1
  33. package/abstract/poseidon.js +26 -31
  34. package/abstract/poseidon.js.map +1 -1
  35. package/abstract/tower.d.ts.map +1 -1
  36. package/abstract/tower.js +43 -19
  37. package/abstract/tower.js.map +1 -1
  38. package/abstract/weierstrass.d.ts +77 -168
  39. package/abstract/weierstrass.d.ts.map +1 -1
  40. package/abstract/weierstrass.js +184 -389
  41. package/abstract/weierstrass.js.map +1 -1
  42. package/bls12-381.d.ts +5 -11
  43. package/bls12-381.d.ts.map +1 -1
  44. package/bls12-381.js +161 -181
  45. package/bls12-381.js.map +1 -1
  46. package/bn254.d.ts +59 -11
  47. package/bn254.d.ts.map +1 -1
  48. package/bn254.js +69 -97
  49. package/bn254.js.map +1 -1
  50. package/ed25519.d.ts +33 -48
  51. package/ed25519.d.ts.map +1 -1
  52. package/ed25519.js +147 -161
  53. package/ed25519.js.map +1 -1
  54. package/ed448.d.ts +27 -36
  55. package/ed448.d.ts.map +1 -1
  56. package/ed448.js +143 -164
  57. package/ed448.js.map +1 -1
  58. package/index.d.ts +1 -0
  59. package/index.js +20 -4
  60. package/index.js.map +1 -1
  61. package/misc.d.ts +10 -14
  62. package/misc.d.ts.map +1 -1
  63. package/misc.js +53 -62
  64. package/misc.js.map +1 -1
  65. package/nist.d.ts +31 -16
  66. package/nist.d.ts.map +1 -1
  67. package/nist.js +75 -64
  68. package/nist.js.map +1 -1
  69. package/package.json +20 -234
  70. package/secp256k1.d.ts +17 -30
  71. package/secp256k1.d.ts.map +1 -1
  72. package/secp256k1.js +59 -73
  73. package/secp256k1.js.map +1 -1
  74. package/src/abstract/bls.ts +207 -354
  75. package/src/abstract/curve.ts +25 -84
  76. package/src/abstract/edwards.ts +68 -193
  77. package/src/abstract/hash-to-curve.ts +71 -85
  78. package/src/abstract/modular.ts +150 -134
  79. package/src/abstract/montgomery.ts +28 -35
  80. package/src/abstract/oprf.ts +600 -0
  81. package/src/abstract/poseidon.ts +6 -8
  82. package/src/abstract/tower.ts +0 -3
  83. package/src/abstract/weierstrass.ts +203 -525
  84. package/src/bls12-381.ts +133 -139
  85. package/src/bn254.ts +69 -93
  86. package/src/ed25519.ts +106 -133
  87. package/src/ed448.ts +111 -138
  88. package/src/index.ts +19 -3
  89. package/src/misc.ts +68 -51
  90. package/src/nist.ts +77 -70
  91. package/src/secp256k1.ts +46 -81
  92. package/src/utils.ts +67 -137
  93. package/src/webcrypto.ts +403 -0
  94. package/utils.d.ts +31 -38
  95. package/utils.d.ts.map +1 -1
  96. package/utils.js +66 -185
  97. package/utils.js.map +1 -1
  98. package/webcrypto.d.ts +99 -0
  99. package/webcrypto.d.ts.map +1 -0
  100. package/webcrypto.js +256 -0
  101. package/webcrypto.js.map +1 -0
  102. package/_shortw_utils.d.ts +0 -19
  103. package/_shortw_utils.d.ts.map +0 -1
  104. package/_shortw_utils.js +0 -20
  105. package/_shortw_utils.js.map +0 -1
  106. package/abstract/utils.d.ts +0 -78
  107. package/abstract/utils.d.ts.map +0 -1
  108. package/abstract/utils.js +0 -73
  109. package/abstract/utils.js.map +0 -1
  110. package/esm/_shortw_utils.d.ts +0 -19
  111. package/esm/_shortw_utils.d.ts.map +0 -1
  112. package/esm/_shortw_utils.js +0 -16
  113. package/esm/_shortw_utils.js.map +0 -1
  114. package/esm/abstract/bls.d.ts +0 -190
  115. package/esm/abstract/bls.d.ts.map +0 -1
  116. package/esm/abstract/bls.js +0 -408
  117. package/esm/abstract/bls.js.map +0 -1
  118. package/esm/abstract/curve.d.ts +0 -231
  119. package/esm/abstract/curve.d.ts.map +0 -1
  120. package/esm/abstract/curve.js +0 -465
  121. package/esm/abstract/curve.js.map +0 -1
  122. package/esm/abstract/edwards.d.ts +0 -243
  123. package/esm/abstract/edwards.d.ts.map +0 -1
  124. package/esm/abstract/edwards.js +0 -627
  125. package/esm/abstract/edwards.js.map +0 -1
  126. package/esm/abstract/fft.d.ts +0 -122
  127. package/esm/abstract/fft.d.ts.map +0 -1
  128. package/esm/abstract/fft.js +0 -425
  129. package/esm/abstract/fft.js.map +0 -1
  130. package/esm/abstract/hash-to-curve.d.ts +0 -102
  131. package/esm/abstract/hash-to-curve.d.ts.map +0 -1
  132. package/esm/abstract/hash-to-curve.js +0 -203
  133. package/esm/abstract/hash-to-curve.js.map +0 -1
  134. package/esm/abstract/modular.d.ts +0 -171
  135. package/esm/abstract/modular.d.ts.map +0 -1
  136. package/esm/abstract/modular.js +0 -530
  137. package/esm/abstract/modular.js.map +0 -1
  138. package/esm/abstract/montgomery.d.ts +0 -30
  139. package/esm/abstract/montgomery.d.ts.map +0 -1
  140. package/esm/abstract/montgomery.js +0 -157
  141. package/esm/abstract/montgomery.js.map +0 -1
  142. package/esm/abstract/poseidon.d.ts +0 -68
  143. package/esm/abstract/poseidon.d.ts.map +0 -1
  144. package/esm/abstract/poseidon.js +0 -296
  145. package/esm/abstract/poseidon.js.map +0 -1
  146. package/esm/abstract/tower.d.ts +0 -95
  147. package/esm/abstract/tower.d.ts.map +0 -1
  148. package/esm/abstract/tower.js +0 -714
  149. package/esm/abstract/tower.js.map +0 -1
  150. package/esm/abstract/utils.d.ts +0 -78
  151. package/esm/abstract/utils.d.ts.map +0 -1
  152. package/esm/abstract/utils.js +0 -70
  153. package/esm/abstract/utils.js.map +0 -1
  154. package/esm/abstract/weierstrass.d.ts +0 -416
  155. package/esm/abstract/weierstrass.d.ts.map +0 -1
  156. package/esm/abstract/weierstrass.js +0 -1413
  157. package/esm/abstract/weierstrass.js.map +0 -1
  158. package/esm/bls12-381.d.ts +0 -16
  159. package/esm/bls12-381.d.ts.map +0 -1
  160. package/esm/bls12-381.js +0 -705
  161. package/esm/bls12-381.js.map +0 -1
  162. package/esm/bn254.d.ts +0 -18
  163. package/esm/bn254.d.ts.map +0 -1
  164. package/esm/bn254.js +0 -214
  165. package/esm/bn254.js.map +0 -1
  166. package/esm/ed25519.d.ts +0 -106
  167. package/esm/ed25519.d.ts.map +0 -1
  168. package/esm/ed25519.js +0 -467
  169. package/esm/ed25519.js.map +0 -1
  170. package/esm/ed448.d.ts +0 -100
  171. package/esm/ed448.d.ts.map +0 -1
  172. package/esm/ed448.js +0 -459
  173. package/esm/ed448.js.map +0 -1
  174. package/esm/index.d.ts +0 -2
  175. package/esm/index.d.ts.map +0 -1
  176. package/esm/index.js +0 -17
  177. package/esm/index.js.map +0 -1
  178. package/esm/jubjub.d.ts +0 -12
  179. package/esm/jubjub.d.ts.map +0 -1
  180. package/esm/jubjub.js +0 -12
  181. package/esm/jubjub.js.map +0 -1
  182. package/esm/misc.d.ts +0 -19
  183. package/esm/misc.d.ts.map +0 -1
  184. package/esm/misc.js +0 -109
  185. package/esm/misc.js.map +0 -1
  186. package/esm/nist.d.ts +0 -21
  187. package/esm/nist.d.ts.map +0 -1
  188. package/esm/nist.js +0 -132
  189. package/esm/nist.js.map +0 -1
  190. package/esm/p256.d.ts +0 -16
  191. package/esm/p256.d.ts.map +0 -1
  192. package/esm/p256.js +0 -16
  193. package/esm/p256.js.map +0 -1
  194. package/esm/p384.d.ts +0 -16
  195. package/esm/p384.d.ts.map +0 -1
  196. package/esm/p384.js +0 -16
  197. package/esm/p384.js.map +0 -1
  198. package/esm/p521.d.ts +0 -16
  199. package/esm/p521.d.ts.map +0 -1
  200. package/esm/p521.js +0 -16
  201. package/esm/p521.js.map +0 -1
  202. package/esm/package.json +0 -4
  203. package/esm/pasta.d.ts +0 -10
  204. package/esm/pasta.d.ts.map +0 -1
  205. package/esm/pasta.js +0 -10
  206. package/esm/pasta.js.map +0 -1
  207. package/esm/secp256k1.d.ts +0 -89
  208. package/esm/secp256k1.d.ts.map +0 -1
  209. package/esm/secp256k1.js +0 -294
  210. package/esm/secp256k1.js.map +0 -1
  211. package/esm/utils.d.ts +0 -110
  212. package/esm/utils.d.ts.map +0 -1
  213. package/esm/utils.js +0 -322
  214. package/esm/utils.js.map +0 -1
  215. package/jubjub.d.ts +0 -12
  216. package/jubjub.d.ts.map +0 -1
  217. package/jubjub.js +0 -15
  218. package/jubjub.js.map +0 -1
  219. package/p256.d.ts +0 -16
  220. package/p256.d.ts.map +0 -1
  221. package/p256.js +0 -13
  222. package/p256.js.map +0 -1
  223. package/p384.d.ts +0 -16
  224. package/p384.d.ts.map +0 -1
  225. package/p384.js +0 -13
  226. package/p384.js.map +0 -1
  227. package/p521.d.ts +0 -16
  228. package/p521.d.ts.map +0 -1
  229. package/p521.js +0 -13
  230. package/p521.js.map +0 -1
  231. package/pasta.d.ts +0 -10
  232. package/pasta.d.ts.map +0 -1
  233. package/pasta.js +0 -13
  234. package/pasta.js.map +0 -1
  235. package/src/_shortw_utils.ts +0 -21
  236. package/src/abstract/utils.ts +0 -80
  237. package/src/jubjub.ts +0 -12
  238. package/src/p256.ts +0 -15
  239. package/src/p384.ts +0 -15
  240. package/src/p521.ts +0 -15
  241. package/src/package.json +0 -3
  242. package/src/pasta.ts +0 -9
package/README.md CHANGED
@@ -5,14 +5,14 @@ Audited & minimal JS implementation of elliptic curve cryptography.
5
5
  - 🔒 [**Audited**](#security) by independent security firms
6
6
  - 🔻 Tree-shakeable: unused code is excluded from your builds
7
7
  - 🏎 Fast: hand-optimized for caveats of JS engines
8
- - 🔍 Reliable: tested against cross-library, wycheproof and acvp vectors
8
+ - 🔍 Reliable: cross-library / wycheproof tests and fuzzing ensure correctness
9
9
  - ➰ Weierstrass, Edwards, Montgomery curves; ECDSA, EdDSA, Schnorr, BLS signatures
10
10
  - ✍️ ECDH, hash-to-curve, OPRF, Poseidon ZK-friendly hash
11
11
  - 🔖 Non-repudiation (SUF-CMA, SBS) & consensus-friendliness (ZIP215) in ed25519, ed448
12
12
  - 🥈 Optional, friendly wrapper over native WebCrypto
13
13
  - 🪶 36KB (gzipped) including bundled hashes, 11KB for single-curve build
14
14
 
15
- Curves have 4KB sister projects
15
+ Curves have 5kb sister projects
16
16
  [secp256k1](https://github.com/paulmillr/noble-secp256k1) & [ed25519](https://github.com/paulmillr/noble-ed25519).
17
17
  They have smaller attack surface, but less features.
18
18
 
@@ -30,7 +30,7 @@ Take a glance at [GitHub Discussions](https://github.com/paulmillr/noble-curves/
30
30
  [curves](https://github.com/paulmillr/noble-curves),
31
31
  [hashes](https://github.com/paulmillr/noble-hashes),
32
32
  [post-quantum](https://github.com/paulmillr/noble-post-quantum),
33
- 4kb [secp256k1](https://github.com/paulmillr/noble-secp256k1) /
33
+ 5kb [secp256k1](https://github.com/paulmillr/noble-secp256k1) /
34
34
  [ed25519](https://github.com/paulmillr/noble-ed25519)
35
35
  - [Check out homepage](https://paulmillr.com/noble/)
36
36
  for reading resources, documentation and apps built with noble
@@ -50,251 +50,314 @@ A standalone file [noble-curves.js](https://github.com/paulmillr/noble-curves/re
50
50
  ```ts
51
51
  // import * from '@noble/curves'; // Error: use sub-imports, to ensure small app size
52
52
  import { secp256k1, schnorr } from '@noble/curves/secp256k1.js';
53
- import { ed25519, ed25519ph, ed25519ctx, x25519 } from '@noble/curves/ed25519.js';
54
- import { ed448, ed448ph, ed448ctx, x448 } from '@noble/curves/ed448.js';
53
+ import { ed25519, ed25519ph, ed25519ctx, x25519, ristretto255 } from '@noble/curves/ed25519.js';
54
+ import { ed448, ed448ph, x448, decaf448 } from '@noble/curves/ed448.js';
55
55
  import { p256, p384, p521 } from '@noble/curves/nist.js';
56
56
  import { bls12_381 } from '@noble/curves/bls12-381.js';
57
57
  import { bn254 } from '@noble/curves/bn254.js';
58
- import { jubjub, babyjubjub } from '@noble/curves/misc.js';
59
- import { bytesToHex, hexToBytes, concatBytes, utf8ToBytes } from '@noble/curves/abstract/utils.js';
58
+ import { jubjub, babyjubjub, brainpoolP256r1, brainpoolP384r1, brainpoolP512r1 } from '@noble/curves/misc.js';
59
+
60
+ // hash-to-curve
61
+ import { secp256k1_hasher } from '@noble/curves/secp256k1.js';
62
+ import { p256_hasher, p384_hasher, p521_hasher } from '@noble/curves/nist.js';
63
+ import { ristretto255_hasher } from '@noble/curves/ed25519.js';
64
+ import { decaf448_hasher } from '@noble/curves/ed448.js';
65
+
66
+ // OPRFs
67
+ import { p256_oprf, p384_oprf, p521_oprf } from '@noble/curves/nist.js';
68
+ import { ristretto255_oprf } from '@noble/curves/ed25519.js';
69
+ import { decaf448_oprf } from '@noble/curves/ed448.js';
70
+
71
+ // utils
72
+ import { bytesToHex, hexToBytes, concatBytes } from '@noble/curves/abstract/utils.js';
73
+ import { Field } from '@noble/curves/abstract/modular.js';
74
+ import { weierstrass, ecdsa } from '@noble/curves/abstract/weierstrass.js';
75
+ import { edwards, eddsa } from '@noble/curves/abstract/edwards.js';
76
+ import { poseidon, poseidonSponge } from '@noble/curves/abstract/poseidon.js';
77
+ import { FFT, poly } from '@noble/curves/abstract/fft.js';
60
78
  ```
61
79
 
62
- - [ECDSA signatures over secp256k1 and others](#ecdsa-signatures-over-secp256k1-and-others)
63
- - [Hedged ECDSA with noise](#hedged-ecdsa-with-noise)
64
- - [ECDH: Diffie-Hellman shared secrets](#ecdh-diffie-hellman-shared-secrets)
65
- - [secp256k1 Schnorr signatures from BIP340](#secp256k1-schnorr-signatures-from-bip340)
66
- - [ed25519](#ed25519) / [X25519](#x25519) / [ristretto255](#ristretto255)
67
- - [ed448](#ed448) / [X448](#x448) / [decaf448](#decaf448)
68
- - [bls12-381](#bls12-381)
69
- - [bn254 aka alt_bn128](#bn254-aka-alt_bn128)
70
- - [misc curves](#misc-curves)
71
- - [Low-level methods](#low-level-methods)
72
- - [Abstract API](#abstract-api)
73
- - [weierstrass](#weierstrass-short-weierstrass-curve), [Projective Point](#projective-weierstrass-point), [ECDSA signatures](#ecdsa-signatures)
74
- - [edwards](#edwards-twisted-edwards-curve), [Extended Point](#extended-edwards-point), [EdDSA signatures](#eddsa-signatures)
75
- - [montgomery](#montgomery-montgomery-curve)
76
- - [bls](#bls-barreto-lynn-scott-curves)
77
- - [hash-to-curve](#hash-to-curve-hashing-strings-to-curve-points)
78
- - [poseidon](#poseidon-poseidon-hash)
79
- - [modular](#modular-modular-arithmetics-utilities)
80
- - [fft](#fft-fast-fourier-transform)
81
- - [Creating private keys from hashes](#creating-private-keys-from-hashes)
82
- - [utils](#utils-useful-utilities)
80
+ - Examples
81
+ - [ECDSA, EdDSA, Schnorr signatures](#ecdsa-eddsa-schnorr-signatures)
82
+ - [secp256k1, p256, p384, p521, ed25519, ed448, brainpool](#secp256k1-p256-p384-p521-ed25519-ed448-brainpool)
83
+ - [ristretto255, decaf448](#ristretto255-decaf448)
84
+ - [Prehashed signing](#prehashed-signing)
85
+ - [Hedged ECDSA with noise](#hedged-ecdsa-with-noise)
86
+ - [Consensus-friendliness vs e-voting](#consensus-friendliness-vs-e-voting)
87
+ - [ECDH: Diffie-Hellman shared secrets](#ecdh-diffie-hellman-shared-secrets)
88
+ - [webcrypto: Friendly wrapper](#webcrypto-friendly-wrapper)
89
+ - [BLS signatures, bls12-381, bn254 aka alt\_bn128](#bls-signatures-bls12-381-bn254-aka-alt_bn128)
90
+ - [Hashing to curve points](#hash-to-curve-hashing-to-curve-points)
91
+ - [OPRFs](#oprfs)
92
+ - [Poseidon hash](#poseidon-poseidon-hash)
93
+ - [Fast Fourier Transform](#fft-fast-fourier-transform)
94
+ - [utils](#utils-byte-shuffling-conversion)
95
+ - [Internals](#internals)
96
+ - [Elliptic curve Point math](#elliptic-curve-point-math)
97
+ - [modular: Modular arithmetics \& finite fields](#modular-modular-arithmetics--finite-fields)
98
+ - [weierstrass: Custom Weierstrass curve](#weierstrass-custom-weierstrass-curve)
99
+ - [edwards: Custom Edwards curve](#edwards-custom-edwards-curve)
100
+ - [Custom ECDSA instance](#custom-ecdsa-instance)
83
101
  - [Security](#security)
84
102
  - [Speed](#speed)
85
- - [Upgrading](#upgrading)
86
103
  - [Contributing & testing](#contributing--testing)
87
- - [License](#license)
104
+ - [Upgrading](#upgrading)
88
105
 
89
- ### Implementations
106
+ ### ECDSA, EdDSA, Schnorr signatures
90
107
 
91
- #### ECDSA signatures over secp256k1 and others
108
+ #### secp256k1, p256, p384, p521, ed25519, ed448, brainpool
92
109
 
93
- ```ts
94
- import { secp256k1 } from '@noble/curves/secp256k1.js';
95
- // import { p256 } from '@noble/curves/nist.js'; // or p384 / p521
96
-
97
- const priv = secp256k1.utils.randomPrivateKey();
98
- const pub = secp256k1.getPublicKey(priv);
99
- const msg = new Uint8Array(32).fill(1); // message hash (not message) in ecdsa
100
- const sig = secp256k1.sign(msg, priv); // `{prehash: true}` option is available
101
- const isValid = secp256k1.verify(sig, msg, pub) === true;
102
-
103
- // hex strings are also supported besides Uint8Array-s:
104
- const privHex = '46c930bc7bb4db7f55da20798697421b98c4175a52c630294d75a84b9c126236';
105
- const pub2 = secp256k1.getPublicKey(privHex);
106
-
107
- // public key recovery
108
- // let sig = secp256k1.Signature.fromCompact(sigHex); // or .fromDER(sigDERHex)
109
- // sig = sig.addRecoveryBit(bit); // bit is not serialized into compact / der format
110
- sig.recoverPublicKey(msg).toRawBytes(); // === pub; // public key recovery
110
+ ```js
111
+ import { secp256k1, schnorr } from '@noble/curves/secp256k1.js';
112
+ import { p256, p384, p521 } from '@noble/curves/nist.js';
113
+ import { ed25519 } from '@noble/curves/ed25519.js';
114
+ import { ed448 } from '@noble/curves/ed448.js';
115
+ import { brainpoolP256r1, brainpoolP384r1, brainpoolP512r1 } from '@noble/curves/misc.js';
116
+ for (const curve of [
117
+ secp256k1, schnorr,
118
+ p256, p384, p521,
119
+ ed25519, ed448,
120
+ brainpoolP256r1, brainpoolP384r1, brainpoolP512r1
121
+ ]) {
122
+ const { secretKey, publicKey } = curve.keygen();
123
+ const msg = new TextEncoder().encode('hello noble');
124
+ const sig = curve.sign(msg, secretKey);
125
+ const isValid = curve.verify(sig, msg, publicKey);
126
+ console.log(curve, secretKey, publicKey, sig, isValid);
127
+ }
128
+
129
+ // Specific private key
130
+ import { hexToBytes } from '@noble/curves/utils.js';
131
+ const secret2 = hexToBytes('46c930bc7bb4db7f55da20798697421b98c4175a52c630294d75a84b9c126236');
132
+ const pub2 = secp256k1.getPublicKey(secret2);
111
133
  ```
112
134
 
113
- The same code would work for NIST P256 (secp256r1), P384 (secp384r1) & P521 (secp521r1).
135
+ ECDSA signatures use deterministic k, conforming to [RFC 6979](https://www.rfc-editor.org/rfc/rfc6979).
136
+ EdDSA conforms to [RFC 8032](https://www.rfc-editor.org/rfc/rfc8032).
137
+ Schnorr (secp256k1-only) conforms to [BIP 340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
114
138
 
115
- #### Hedged ECDSA with noise
139
+ #### ristretto255, decaf448
116
140
 
117
141
  ```ts
118
- const noisySignature = secp256k1.sign(msg, priv, { extraEntropy: true });
119
- const ent = new Uint8Array(32).fill(3); // set custom entropy
120
- const noisySignature2 = secp256k1.sign(msg, priv, { extraEntropy: ent });
142
+ import { ristretto255, ristretto255_hasher, ristretto255_oprf } from '@noble/curves/ed25519.js';
143
+ import { decaf448, decaf448_hasher, decaf448_oprf } from '@noble/curves/ed448.js';
144
+
145
+ console.log(ristretto255.Point, decaf448.Point);
121
146
  ```
122
147
 
123
- Hedged ECDSA is add-on, providing improved protection against fault attacks.
124
- It adds noise to signatures. The technique is used by default in BIP340; we also implement them
125
- optionally for ECDSA. Check out blog post
126
- [Deterministic signatures are not your friends](https://paulmillr.com/posts/deterministic-signatures/)
127
- and [spec draft](https://datatracker.ietf.org/doc/draft-irtf-cfrg-det-sigs-with-noise/).
148
+ Check out [RFC 9496](https://www.rfc-editor.org/rfc/rfc9496) more info on ristretto255 & decaf448.
149
+ Check out separate documentation for [Point](#elliptic-curve-point-math), [hasher](#hash-to-curve-hashing-to-curve-points) and [oprf](#oprfs).
128
150
 
129
- #### ECDH: Diffie-Hellman shared secrets
151
+ #### Prehashed signing
130
152
 
131
- ```ts
132
- const someonesPub = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
133
- const shared = secp256k1.getSharedSecret(priv, someonesPub);
134
- // NOTE:
135
- // - `shared` includes parity byte: strip it using shared.slice(1)
136
- // - `shared` is not hashed: more secure way is sha256(shared) or hkdf(shared)
153
+ ```js
154
+ import { secp256k1 } from '@noble/curves/secp256k1.js';
155
+ import { keccak256 } from '@noble/hashes/sha3.js';
156
+ const { secretKey } = curve.keygen();
157
+ const msg = new TextEncoder().encode('hello noble');
158
+ // prehash: true (default) - hash using secp256k1.hash (sha256)
159
+ const sig = secp256k1.sign(msg, secretKey);
160
+ // prehash: false - hash using custom hash
161
+ const sigKeccak = secp256k1.sign(keccak256(msg), secretKey, { prehash: false });
137
162
  ```
138
163
 
139
- #### secp256k1 Schnorr signatures from BIP340
164
+ ECDSA `sign()` allows providing `prehash: false`, which enables using custom hashes.
140
165
 
141
- ```ts
142
- import { schnorr } from '@noble/curves/secp256k1.js';
143
- const priv = schnorr.utils.randomPrivateKey();
144
- const pub = schnorr.getPublicKey(priv);
145
- const msg = new TextEncoder().encode('hello');
146
- const sig = schnorr.sign(msg, priv);
147
- const isValid = schnorr.verify(sig, msg, pub);
166
+ A ECDSA signature is not just "math over elliptic curve points".
167
+ It's actually math + hashing: p256 is in fact p256 point + sha256 hash.
168
+ By default, we hash messages. To use custom hash methods,
169
+ make sure to disable prehashing.
170
+
171
+ > [!NOTE]
172
+ > Previously, in noble-curves v1, `prehash: false` was the default.
173
+ > Some other libraries (like libsecp256k1) have no prehashing.
174
+
175
+ #### Hedged ECDSA with noise
176
+
177
+ ```js
178
+ import { secp256k1 } from '@noble/curves/secp256k1.js';
179
+ const { secretKey } = curve.keygen();
180
+ const msg = new TextEncoder().encode('hello noble');
181
+ // extraEntropy: false - default, hedging disabled
182
+ const sigNoisy = secp256k1.sign(msg, secretKey);
183
+ // extraEntropy: true - fetch 32 random bytes from CSPRNG
184
+ const sigNoisy = secp256k1.sign(msg, secretKey, { extraEntropy: true });
185
+ // extraEntropy: bytes - specific extra entropy
186
+ const ent = Uint8Array.from([0xca, 0xfe, 0x01, 0x23]);
187
+ const sigNoisy2 = secp256k1.sign(msg, secretKey, { extraEntropy: ent });
148
188
  ```
149
189
 
150
- #### ed25519
190
+ ECDSA `sign()` allows providing `extraEntropy`, which switches sig generation to hedged mode.
151
191
 
152
- ```ts
192
+ By default, ECDSA signatures are generated deterministically,
193
+ following [RFC 6979](https://www.rfc-editor.org/rfc/rfc6979).
194
+ However, purely deterministic signatures are vulnerable to fault attacks.
195
+ Newer signature schemes, such as BIP340 schnorr, switched to hedged signatures because of this.
196
+ Hedging is basically incorporating some randomness into sig generation process.
197
+
198
+ For more info, check out
199
+ [Deterministic signatures are not your friends](https://paulmillr.com/posts/deterministic-signatures/),
200
+ [RFC 6979](https://www.rfc-editor.org/rfc/rfc6979) section 3.6,
201
+ and [cfrg-det-sigs-with-noise draft](https://datatracker.ietf.org/doc/draft-irtf-cfrg-det-sigs-with-noise/).
202
+
203
+ #### Consensus-friendliness vs e-voting
204
+
205
+ ```js
153
206
  import { ed25519 } from '@noble/curves/ed25519.js';
154
- const priv = ed25519.utils.randomPrivateKey();
155
- const pub = ed25519.getPublicKey(priv);
156
- const msg = new TextEncoder().encode('hello');
157
- const sig = ed25519.sign(msg, priv);
158
- ed25519.verify(sig, msg, pub); // Default mode: follows ZIP215
159
- ed25519.verify(sig, msg, pub, { zip215: false }); // SBS / e-voting / RFC8032 / FIPS 186-5
160
-
161
- // Variants from RFC8032: with context, prehashed
162
- import { ed25519ctx, ed25519ph } from '@noble/curves/ed25519.js';
207
+ const { secretKey, publicKey } = ed25519.keygen();
208
+ const msg = new TextEncoder().encode('hello noble');
209
+ const sig = ed25519.sign(msg, secretKey);
210
+ // zip215: true
211
+ const isValid = ed25519.verify(sig, msg, pub);
212
+ // SBS / e-voting / RFC8032 / FIPS 186-5
213
+ const isValidRfc = ed25519.verify(sig, msg, pub, { zip215: false });
163
214
  ```
164
215
 
165
- Default `verify` behavior follows ZIP215 and
166
- can be used in consensus-critical applications.
167
- If you need SBS (Strongly Binding Signatures) and FIPS 186-5 compliance,
168
- use `zip215: false`. Check out [Edwards Signatures section for more info](#edwards-twisted-edwards-curve).
169
- Both options have SUF-CMA (strong unforgeability under chosen message attacks).
216
+ In ed25519, there is an ability to choose between consensus-friendliness vs e-voting mode.
170
217
 
171
- #### X25519
218
+ - `zip215: true` is default behavior. It has slightly looser verification logic
219
+ to be [consensus-friendly](https://hdevalence.ca/blog/2020-10-04-its-25519am), following [ZIP215](https://zips.z.cash/zip-0215) rules
220
+ - `zip215: false` switches verification criteria to strict
221
+ [RFC 8032](https://www.rfc-editor.org/rfc/rfc8032) / [FIPS 186-5](https://csrc.nist.gov/publications/detail/fips/186/5/final)
222
+ and additionally provides [non-repudiation with SBS](https://eprint.iacr.org/2020/1244),
223
+ which is useful for:
224
+ - Contract Signing: if A signed an agreement with B using key that allows repudiation, it can later claim that it signed a different contract
225
+ - E-voting: malicious voters may pick keys that allow repudiation in order to deny results
226
+ - Blockchains: transaction of amount X might also be valid for a different amount Y
172
227
 
173
- ```ts
174
- // X25519 aka ECDH on Curve25519 from [RFC7748](https://www.rfc-editor.org/rfc/rfc7748)
228
+ Both modes have SUF-CMA (strong unforgeability under chosen message attacks).
229
+
230
+ ### ECDH: Diffie-Hellman shared secrets
231
+
232
+ ```js
233
+ import { secp256k1 } from '@noble/curves/secp256k1.js';
175
234
  import { x25519 } from '@noble/curves/ed25519.js';
176
- const priv = 'a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4';
177
- const pub = 'e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c';
178
- x25519.getSharedSecret(priv, pub) === x25519.scalarMult(priv, pub); // aliases
179
- x25519.getPublicKey(priv) === x25519.scalarMultBase(priv);
180
- x25519.getPublicKey(x25519.utils.randomPrivateKey());
181
-
182
- // ed25519 => x25519 conversion
183
- import { edwardsToMontgomeryPub, edwardsToMontgomeryPriv } from '@noble/curves/ed25519.js';
184
- edwardsToMontgomeryPub(ed25519.getPublicKey(ed25519.utils.randomPrivateKey()));
185
- edwardsToMontgomeryPriv(ed25519.utils.randomPrivateKey());
186
- ```
235
+ import { x448 } from '@noble/curves/ed448.js';
236
+ import { p256, p384, p521 } from '@noble/curves/nist.js';
187
237
 
188
- #### ristretto255
238
+ for (const curve of [secp256k1, schnorr, x25519, x448, p256, p384, p521]) {
239
+ const alice = curve.keygen();
240
+ const bob = curve.keygen();
241
+ const sharedKey = curve.getSharedSecret(alice.secretKey, bob.publicKey);
242
+ console.log('alice', alice, 'bob', bob, 'shared', sharedKey);
243
+ }
189
244
 
190
- ```ts
191
- import { sha512 } from '@noble/hashes/sha2.js';
192
- import {
193
- hashToCurve,
194
- encodeToCurve,
195
- RistrettoPoint,
196
- hashToRistretto255,
197
- } from '@noble/curves/ed25519.js';
198
-
199
- const msg = new TextEncoder().encode('Ristretto is traditionally a short shot of espresso coffee');
200
- hashToCurve(msg);
201
-
202
- const rp = RistrettoPoint.fromHex(
203
- '6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919'
204
- );
205
- RistrettoPoint.BASE.multiply(2n).add(rp).subtract(RistrettoPoint.BASE).toRawBytes();
206
- RistrettoPoint.ZERO.equals(dp) === false;
207
- // pre-hashed hash-to-curve
208
- RistrettoPoint.hashToCurve(sha512(msg));
209
- // full hash-to-curve including domain separation tag
210
- hashToRistretto255(msg, { DST: 'ristretto255_XMD:SHA-512_R255MAP_RO_' });
245
+ // x25519 & x448 specific methods
246
+ import { ed25519 } from '@noble/curves/ed25519.js';
247
+ const alice = ed25519.keygen();
248
+ const bob = ed25519.keygen();
249
+ const aliceSecX = ed25519.utils.toMontgomerySecret(alice.secretKey);
250
+ const bobPubX = ed25519.utils.toMontgomery(bob.publicKey);
251
+ const sharedKey = x25519.getSharedSecret(aliceSecX, bobPubX);
211
252
  ```
212
253
 
213
- Check out [RFC9496](https://www.rfc-editor.org/rfc/rfc9496) more info on ristretto255.
254
+ We provide ECDH over all Weierstrass curves, and over 2 Montgomery curves
255
+ X25519 (Curve25519) & X448 (Curve448), conforming to [RFC 7748](https://www.rfc-editor.org/rfc/rfc7748).
214
256
 
215
- #### ed448
257
+ In Weierstrass curves, shared secrets:
216
258
 
217
- ```ts
218
- import { ed448 } from '@noble/curves/ed448.js';
219
- const priv = ed448.utils.randomPrivateKey();
220
- const pub = ed448.getPublicKey(priv);
221
- const msg = new TextEncoder().encode('whatsup');
222
- const sig = ed448.sign(msg, priv);
223
- ed448.verify(sig, msg, pub);
224
-
225
- // Variants from RFC8032: prehashed
226
- import { ed448ph } from '@noble/curves/ed448.js';
227
- ```
259
+ - Include y-parity bytes: use `key.slice(1)` to strip it
260
+ - Are not hashed: use hashing or KDF on top, like `sha256(shared)` or `hkdf(shared)`
228
261
 
229
- #### X448
262
+ #### webcrypto: Friendly wrapper
230
263
 
231
- ```ts
232
- // X448 aka ECDH on Curve448 from [RFC7748](https://www.rfc-editor.org/rfc/rfc7748)
233
- import { x448 } from '@noble/curves/ed448.js';
234
- x448.getSharedSecret(priv, pub) === x448.scalarMult(priv, pub); // aliases
235
- x448.getPublicKey(priv) === x448.scalarMultBase(priv);
264
+ > [!NOTE]
265
+ > Webcrypto methods are always async.
266
+
267
+ ##### webcrypto signatures
236
268
 
237
- // ed448 => x448 conversion
238
- import { edwardsToMontgomeryPub } from '@noble/curves/ed448.js';
239
- edwardsToMontgomeryPub(ed448.getPublicKey(ed448.utils.randomPrivateKey()));
269
+ ```js
270
+ import { ed25519, ed448, p256, p384, p521 } from './src/webcrypto.ts';
271
+
272
+ (async () => {
273
+ for (let [name, curve] of Object.entries({ p256, p384, p521, ed25519, ed448 })) {
274
+ console.log('curve', name);
275
+ if (!await curve.isSupported()) {
276
+ console.log('is not supported, skipping');
277
+ continue;
278
+ }
279
+ const keys = await curve.keygen();
280
+ const msg = new TextEncoder().encode('hello noble');
281
+ const sig = await curve.sign(msg, keys.secretKey);
282
+ const isValid = await curve.verify(sig, msg, keys.publicKey);
283
+ console.log({
284
+ keys, msg, sig, isValid
285
+ });
286
+ }
287
+ })();
240
288
  ```
241
289
 
242
- #### decaf448
290
+ ##### webcrypto ecdh
243
291
 
244
- ```ts
245
- // decaf448 from [RFC9496](https://www.rfc-editor.org/rfc/rfc9496)
246
- import { shake256 } from '@noble/hashes/sha3.js';
247
- import { hashToCurve, encodeToCurve, DecafPoint, hashToDecaf448 } from '@noble/curves/ed448.js';
248
-
249
- const msg = new TextEncoder().encode('Ristretto is traditionally a short shot of espresso coffee');
250
- hashToCurve(msg);
251
-
252
- const dp = DecafPoint.fromHex(
253
- 'c898eb4f87f97c564c6fd61fc7e49689314a1f818ec85eeb3bd5514ac816d38778f69ef347a89fca817e66defdedce178c7cc709b2116e75'
254
- );
255
- DecafPoint.BASE.multiply(2n).add(dp).subtract(DecafPoint.BASE).toRawBytes();
256
- DecafPoint.ZERO.equals(dp) === false;
257
- // pre-hashed hash-to-curve
258
- DecafPoint.hashToCurve(shake256(msg, { dkLen: 112 }));
259
- // full hash-to-curve including domain separation tag
260
- hashToDecaf448(msg, { DST: 'decaf448_XOF:SHAKE256_D448MAP_RO_' });
292
+ ```js
293
+ import { p256, p384, p521, x25519, x448 } from './src/webcrypto.ts';
294
+
295
+ (async () => {
296
+ for (let [name, curve] of Object.entries({ p256, p384, p521, x25519, x448 })) {
297
+ console.log('curve', name);
298
+ if (!await curve.isSupported()) {
299
+ console.log('is not supported, skipping');
300
+ continue;
301
+ }
302
+ const alice = await curve.keygen();
303
+ const bob = await curve.keygen();
304
+ const shared = await curve.getSharedSecret(alice.secretKey, bob.publicKey);
305
+ const shared2 = await curve.getSharedSecret(bob.secretKey, alice.publicKey);
306
+ console.log({shared});
307
+ }
308
+ })();
261
309
  ```
262
310
 
263
- Check out [RFC9496](https://www.rfc-editor.org/rfc/rfc9496) more info on decaf448.
311
+ ##### Key conversion from noble to webcrypto and back
264
312
 
265
- #### bls12-381
313
+ ```js
314
+ import { p256 as p256n } from './src/nist.ts';
315
+ import { p256 } from './src/webcrypto.ts';
316
+ (async () => {
317
+ const nobleKeys = p256n.keygen();
318
+ // convert noble keys to webcrypto
319
+ const webKeys = {
320
+ secretKey: await p256.utils.convertSecretKey(nobleKeys.secretKey, 'raw', 'pkcs8'),
321
+ publicKey: await p256.utils.convertPublicKey(nobleKeys.publicKey, 'raw', 'spki')
322
+ };
323
+ // convert webcrypto keys to noble
324
+ const nobleKeys2 = {
325
+ secretKey: await p256.utils.convertSecretKey(webKeys.secretKey, 'pkcs8', 'raw'),
326
+ publicKey: await p256.utils.convertPublicKey(webKeys.publicKey, 'spki', 'raw')
327
+ };
328
+ })();
329
+ ```
330
+
331
+ ### BLS signatures, bls12-381, bn254 aka alt_bn128
266
332
 
267
333
  ```ts
268
334
  import { bls12_381 } from '@noble/curves/bls12-381.js';
269
- import { hexToBytes } from '@noble/curves/abstract/utils.js';
270
-
271
- // private keys are 32 bytes
272
- const privKey = hexToBytes('67d53f170b908cabb9eb326c3c337762d59289a8fec79f7bc9254b584b73265c');
273
- // const privKey = bls12_381.utils.randomPrivateKey();
274
335
 
275
- // Long signatures (G2), short public keys (G1)
336
+ // G1 pubkeys, G2 sigs
276
337
  const blsl = bls12_381.longSignatures;
277
- const publicKey = blsl.getPublicKey(privateKey);
278
- // Sign msg with custom (Ethereum) DST
279
- const msg = new TextEncoder().encode('hello');
280
- const DST = 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_';
281
- const msgp = blsl.hash(msg, DST);
282
- const signature = blsl.sign(msgp, privateKey);
338
+ const { secretKey, publicKey } = blsl.keygen();
339
+ // const publicKey = blsl.getPublicKey(secretKey);
340
+ const msg = new TextEncoder().encode('hello noble');
341
+ // default DST
342
+ const msgp = blsl.hash(msg);
343
+ // custom DST (Ethereum)
344
+ const msgpd = blsl.hash(msg, 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_');
345
+ const signature = blsl.sign(msgp, secretKey);
283
346
  const isValid = blsl.verify(signature, msgp, publicKey);
284
- console.log({ publicKey, signature, isValid });
347
+ console.log('long', { publicKey, signature, isValid });
285
348
 
286
- // Short signatures (G1), long public keys (G2)
349
+ // G1 sigs, G2 pubkeys
287
350
  const blss = bls12_381.shortSignatures;
288
- const publicKey2 = blss.getPublicKey(privateKey);
289
- const msgp2 = blss.hash(new TextEncoder().encode('hello'), 'BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_')
290
- const signature2 = blss.sign(msgp2, privateKey);
351
+ const publicKey2 = blss.getPublicKey(secretKey);
352
+ const msgp2 = blss.hash(msg, 'BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_');
353
+ const signature2 = blss.sign(msgp2, secretKey);
291
354
  const isValid2 = blss.verify(signature2, msgp2, publicKey);
292
355
  console.log({ publicKey2, signature2, isValid2 });
293
356
 
294
357
  // Aggregation
295
358
  const aggregatedKey = bls12_381.longSignatures.aggregatePublicKeys([
296
- bls12_381.utils.randomPrivateKey(),
297
- bls12_381.utils.randomPrivateKey(),
359
+ bls12_381.utils.randomSecretKey(),
360
+ bls12_381.utils.randomSecretKey(),
298
361
  ]);
299
362
  // const aggregatedSig = bls.aggregateSignatures(sigs)
300
363
 
@@ -304,278 +367,88 @@ const aggregatedKey = bls12_381.longSignatures.aggregatePublicKeys([
304
367
  // bls.fields.Fp12.finalExponentiate(bls.fields.Fp12.mul(PointG1, PointG2));
305
368
 
306
369
  // Others
307
- // bls.G1.ProjectivePoint.BASE, bls.G2.ProjectivePoint.BASE;
370
+ // bls.G1.Point.BASE, bls.G2.Point.BASE;
308
371
  // bls.fields.Fp, bls.fields.Fp2, bls.fields.Fp12, bls.fields.Fr;
309
372
  ```
310
373
 
311
374
  See [abstract/bls](#bls-barreto-lynn-scott-curves).
312
375
  For example usage, check out [the implementation of BLS EVM precompiles](https://github.com/ethereumjs/ethereumjs-monorepo/blob/361f4edbc239e795a411ac2da7e5567298b9e7e5/packages/evm/src/precompiles/bls12_381/noble.ts).
313
376
 
314
- #### bn254 aka alt_bn128
315
-
316
- ```ts
317
- import { bn254 } from '@noble/curves/bn254.js';
318
-
319
- console.log(bn254.G1, bn254.G2, bn254.pairing);
320
- ```
321
-
322
- The API mirrors [BLS](#bls12-381). The curve was previously called alt_bn128.
377
+ The BN254 API mirrors [BLS](#bls12-381). The curve was previously called alt_bn128.
323
378
  The implementation is compatible with [EIP-196](https://eips.ethereum.org/EIPS/eip-196) and
324
379
  [EIP-197](https://eips.ethereum.org/EIPS/eip-197).
325
380
 
326
- We don't implement Point methods toHex / toRawBytes.
327
- To work around this limitation, has to initialize points on their own from BigInts.
328
- Reason it's not implemented is because [there is no standard](https://github.com/privacy-scaling-explorations/halo2curves/issues/109).
381
+ For BN254 usage, check out [the implementation of bn254 EVM precompiles](https://github.com/paulmillr/noble-curves/blob/3ed792f8ad9932765b84d1064afea8663a255457/test/bn254.test.js#L697).
382
+ We don't implement Point methods toBytes. To work around this limitation, has to initialize points on their own from BigInts. Reason it's not implemented is because [there is no standard](https://github.com/privacy-scaling-explorations/halo2curves/issues/109).
329
383
  Points of divergence:
330
384
 
331
385
  - Endianness: LE vs BE (byte-swapped)
332
386
  - Flags as first hex bits (similar to BLS) vs no-flags
333
387
  - Imaginary part last in G2 vs first (c0, c1 vs c1, c0)
334
388
 
335
- For example usage, check out [the implementation of bn254 EVM precompiles](https://github.com/paulmillr/noble-curves/blob/3ed792f8ad9932765b84d1064afea8663a255457/test/bn254.test.js#L697).
336
-
337
- #### misc curves
389
+ ### hash-to-curve: hashing to curve points
338
390
 
339
391
  ```ts
340
- import { jubjub, babyjubjub } from '@noble/curves/misc.js';
341
- ```
342
-
343
- Miscellaneous, rarely used curves are contained in the module.
344
- Jubjub curves have Fp over scalar fields of other curves. They are friendly to ZK proofs.
345
- jubjub Fp = bls n. babyjubjub Fp = bn254 n.
346
-
347
- ## Abstract API
348
-
349
- Abstract API allows to define custom curves. All arithmetics is done with JS
350
- bigints over finite fields, which is defined from `modular` sub-module.
351
- For scalar multiplication, we use
352
- [precomputed tables with w-ary non-adjacent form (wNAF)](https://paulmillr.com/posts/noble-secp256k1-fast-ecc/).
353
- Precomputes are enabled for weierstrass and edwards BASE points of a curve.
354
- Implementations use [noble-hashes](https://github.com/paulmillr/noble-hashes).
355
- It's always possible to use different hashing library.
356
-
357
-
358
- ### weierstrass: Short Weierstrass curve
359
-
360
- ```js
361
- import { weierstrass } from '@noble/curves/abstract/weierstrass.js';
362
- // NIST secp192r1 aka p192. https://www.secg.org/sec2-v2.pdf
363
- const p192_CURVE = {
364
- p: 0xfffffffffffffffffffffffffffffffeffffffffffffffffn,
365
- n: 0xffffffffffffffffffffffff99def836146bc9b1b4d22831n,
366
- h: 1n,
367
- a: 0xfffffffffffffffffffffffffffffffefffffffffffffffcn,
368
- b: 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1n,
369
- Gx: 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012n,
370
- Gy: 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811n,
392
+ import { bls12_381 } from './src/bls12-381.ts';
393
+ import { ed25519_hasher, ristretto255_hasher } from './src/ed25519.ts';
394
+ import { decaf448_hasher, ed448_hasher } from './src/ed448.ts';
395
+ import { p256_hasher, p384_hasher, p521_hasher } from './src/nist.ts';
396
+ import { secp256k1_hasher } from './src/secp256k1.ts';
397
+
398
+ const h = {
399
+ secp256k1_hasher,
400
+ p256_hasher, p384_hasher, p521_hasher,
401
+ ed25519_hasher,
402
+ ed448_hasher,
403
+ ristretto255_hasher,
404
+ decaf448_hasher,
405
+ bls_G1: bls12_381.G1,
406
+ bls_G2: bls12_381.G2
371
407
  };
372
- const p192_Point = weierstrass(p192_CURVE);
373
- ```
374
-
375
- Short Weierstrass curve's formula is `y² = x³ + ax + b`. `weierstrass`
376
- expects arguments `a`, `b`, field characteristic `p`, curve order `n`,
377
- cofactor `h` and coordinates `Gx`, `Gy` of generator point.
378
-
379
- #### Projective Weierstrass Point
380
408
 
381
- ```js
382
- // # weierstrass Point methods
383
- // projective (homogeneous) coordinates: (x, y, z) (x=x/z, y=y/z)
384
- // const p = new Point(x, y, z);
385
- const p = Point.BASE;
386
- // arithmetics
387
- p.add(p).equals(p.double());
388
- p.subtract(p).equals(Point.ZERO);
389
- p.negate();
390
- p.multiply(31415n);
391
-
392
- // decoding, encoding
393
- const b = p.toBytes();
394
- const p2 = Point.fromBytes(b);
395
- // affine conversion
396
- const { x, y } = p.toAffine();
397
- const p3 = Point.fromAffine({ x, y });
398
-
399
- // Multi-scalar-multiplication (MSM) is basically `(Pa + Qb + Rc + ...)`.
400
- // It's 10-30x faster vs naive addition for large amount of points.
401
- // Pippenger algorithm is used underneath.
402
- const points = [Point.BASE, Point.BASE.multiply(2n), Point.BASE.multiply(4n), Point.BASE.multiply(8n)];
403
- Point.msm(points, [3n, 5n, 7n, 11n]).equals(Point.BASE.multiply(129n)); // 129*G
409
+ const msg = Uint8Array.from([0xca, 0xfe, 0x01, 0x23]);
410
+ console.log('msg', msg);
411
+ for (let [name, c] of Object.entries(h)) {
412
+ const hashToCurve = c.hashToCurve(msg).toHex();
413
+ const hashToCurve_customDST = c.hashToCurve(msg, { DST: 'hello noble' }).toHex();
414
+ const encodeToCurve = 'encodeToCurve' in c ? c.encodeToCurve(msg).toHex() : undefined;
415
+ // ristretto255, decaf448 only
416
+ const deriveToCurve = 'deriveToCurve' in c ?
417
+ c.deriveToCurve!(new Uint8Array(c.Point.Fp.BYTES * 2)).toHex() : undefined;
418
+ const hashToScalar = c.hashToScalar(msg);
419
+ console.log({
420
+ name, hashToCurve, hashToCurve_customDST, encodeToCurve, deriveToCurve, hashToScalar
421
+ });
422
+ }
423
+
424
+ // abstract methods
425
+ import { expand_message_xmd, expand_message_xof, hash_to_field } from '@noble/curves/abstract/hash-to-curve.js';
404
426
  ```
405
427
 
406
- #### ECDSA signatures
407
-
408
- ```js
409
- import { ecdsa } from '@noble/curves/abstract/weierstrass.js';
410
- import { sha256 } from '@noble/hashes/sha2.js';
411
- const p192 = ecdsa(p192_Point, sha256);
412
- const priv = p192.utils.randomPrivateKey();
413
- const pub = p192.getPublicKey(priv);
414
- const msg = sha256(new TextEncoder().encode('custom curve'));
415
- const sig = p192.sign(msg);
416
- const isValid = p192.verify(sig, msg, pub);
417
- ```
418
-
419
- ECDSA signatures:
420
-
421
- - Are represented by `Signature` instances with `r, s` and optional `recovery` properties
422
- - Have `recoverPublicKey()`, `toBytes()` with optional `format: 'compact' | 'der'`
423
- - Can be prehashed, or non-prehashed:
424
- - `sign(msgHash, privKey)` (default, prehash: false) - you did hashing before
425
- - `sign(msg, privKey, {prehash: true})` - curves will do hashing for you
426
- - Are generated deterministically, following [RFC6979](https://www.rfc-editor.org/rfc/rfc6979).
427
- - Consider [hedged ECDSA with noise](#hedged-ecdsa-with-noise) for adding randomness into
428
- for signatures, to get improved security against fault attacks.
429
-
430
- ### edwards: Twisted Edwards curve
431
-
432
- ```ts
433
- import { edwards } from '@noble/curves/abstract/edwards.js';
434
- const ed25519_CURVE = {
435
- p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn,
436
- n: 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn,
437
- h: 8n,
438
- a: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffecn,
439
- d: 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n,
440
- Gx: 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an,
441
- Gy: 0x6666666666666666666666666666666666666666666666666666666666666658n,
442
- };
443
- const ed25519_Point = edwards(ed25519_CURVE);
444
- ```
445
-
446
- Twisted Edwards curve's formula is `ax² + y² = 1 + dx²y²`.
447
- You must specify `a`, `d`, field characteristic `p`, curve order `n` (sometimes named as `L`),
448
- cofactor `h` and coordinates `Gx`, `Gy` of generator point.
449
-
450
- #### Extended Edwards Point
428
+ The module allows to hash arbitrary strings to elliptic curve points. Implements [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380).
451
429
 
452
- ```js
453
- const Point = ed25519_Point;
454
- // extended coordinates: (x, y, z, t) (x=x/z, y=y/z)
455
- // const p = new Point(x, y, z, t);
456
-
457
- const p = Point.BASE;
458
- // arithmetics
459
- p.add(p).equals(p.double());
460
- p.subtract(p).equals(Point.ZERO);
461
- p.negate();
462
- p.multiply(31415n);
463
-
464
- // decoding, encoding
465
- const b = p.toBytes();
466
- const p2 = Point.fromBytes(b);
467
- // on-curve test
468
- p.assertValidity();
469
- // affine conversion
470
- const { x, y } = p.toAffine();
471
- const p3 = Point.fromAffine({ x, y });
472
- // misc
473
- const pcl = p.clearCofactor();
474
- console.log(p.isTorsionFree(), p.isSmallOrder());
475
- ```
430
+ > [!NOTE]
431
+ > Why is `p256_hasher` separate from `p256`?
432
+ > The methods reside in separate _hasher namespace for tree-shaking:
433
+ > this way users who don't need hash-to-curve, won't have it in their builds.
476
434
 
477
- #### EdDSA signatures
435
+ ### OPRFs
478
436
 
479
437
  ```js
480
- const ed25519 = eddsa(ed25519_Point, { hash: sha512 });
481
- // ed25519.getPublicKey();
482
- // ed25519.sign();
483
- // ed25519.verify();
438
+ import { p256_oprf, p384_oprf, p521_oprf } from '@noble/curves/nist.js';
439
+ import { ristretto255_oprf } from '@noble/curves/ed25519.js';
440
+ import { decaf448_orpf } from '@noble/curves/ed448.js';
484
441
  ```
485
442
 
486
- We define ed25519, ed448; user can use custom curves with EdDSA,
487
- but EdDSA in general is not defined. Check out `edwards.ts` source code.
488
-
489
- For EdDSA signatures:
490
-
491
- - `zip215: true` is default behavior. It has slightly looser verification logic
492
- to be [consensus-friendly](https://hdevalence.ca/blog/2020-10-04-its-25519am), following [ZIP215](https://zips.z.cash/zip-0215) rules
493
- - `zip215: false` switches verification criteria to strict
494
- [RFC8032](https://www.rfc-editor.org/rfc/rfc8032) / [FIPS 186-5](https://csrc.nist.gov/publications/detail/fips/186/5/final)
495
- and additionally provides [non-repudiation with SBS](https://eprint.iacr.org/2020/1244),
496
- which is useful for:
497
- - Contract Signing: if A signed an agreement with B using key that allows repudiation, it can later claim that it signed a different contract
498
- - E-voting: malicious voters may pick keys that allow repudiation in order to deny results
499
- - Blockchains: transaction of amount X might also be valid for a different amount Y
500
- - Both modes have SUF-CMA (strong unforgeability under chosen message attacks).
501
-
502
- ### montgomery: Montgomery curve
503
-
504
- The module contains methods for x-only ECDH on Curve25519 / Curve448 from RFC7748.
505
- Proper Elliptic Curve Points are not implemented yet.
506
-
507
- ### bls: Barreto-Lynn-Scott curves
508
-
509
- The module abstracts BLS (Barreto-Lynn-Scott) pairing-friendly elliptic curve construction.
510
- They allow to construct [zk-SNARKs](https://z.cash/technology/zksnarks/) and
511
- use aggregated, batch-verifiable
512
- [threshold signatures](https://medium.com/snigirev.stepan/bls-signatures-better-than-schnorr-5a7fe30ea716),
513
- using Boneh-Lynn-Shacham signature scheme.
514
-
515
- The module doesn't expose `CURVE` property: use `G1.CURVE`, `G2.CURVE` instead.
516
- Only BLS12-381 is currently implemented.
517
- Defining BLS12-377 and BLS24 should be straightforward.
518
-
519
- The default BLS uses short public keys (with public keys in G1 and signatures in G2).
520
- Short signatures (public keys in G2 and signatures in G1) are also supported.
521
-
522
- ### hash-to-curve: Hashing strings to curve points
523
-
524
- The module allows to hash arbitrary strings to elliptic curve points. Implements [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380).
525
-
526
- Every curve has exported `hashToCurve` and `encodeToCurve` methods. You should always prefer `hashToCurve` for security:
527
-
528
- ```ts
529
- import { hashToCurve, encodeToCurve } from '@noble/curves/secp256k1.js';
530
- import { randomBytes } from '@noble/hashes/utils.js';
531
- hashToCurve('0102abcd');
532
- console.log(hashToCurve(randomBytes()));
533
- console.log(encodeToCurve(randomBytes()));
534
-
535
- import { bls12_381 } from '@noble/curves/bls12-381.js';
536
- bls12_381.G1.hashToCurve(randomBytes(), { DST: 'another' });
537
- bls12_381.G2.hashToCurve(randomBytes(), { DST: 'custom' });
538
- ```
443
+ We provide OPRFs (oblivious pseudorandom functions),
444
+ conforming to [RFC 9497](https://www.rfc-editor.org/rfc/rfc9497).
539
445
 
540
- Low-level methods from the spec:
446
+ OPRF allows to interactively create an `Output = PRF(Input, serverSecretKey)`:
541
447
 
542
- ```ts
543
- // produces a uniformly random byte string using a cryptographic hash function H that outputs b bits.
544
- function expand_message_xmd(
545
- msg: Uint8Array,
546
- DST: Uint8Array,
547
- lenInBytes: number,
548
- H: CHash // For CHash see abstract/weierstrass docs section
549
- ): Uint8Array;
550
- // produces a uniformly random byte string using an extendable-output function (XOF) H.
551
- function expand_message_xof(
552
- msg: Uint8Array,
553
- DST: Uint8Array,
554
- lenInBytes: number,
555
- k: number,
556
- H: CHash
557
- ): Uint8Array;
558
- // Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F
559
- function hash_to_field(msg: Uint8Array, count: number, options: Opts): bigint[][];
560
-
561
- /**
562
- * * `DST` is a domain separation tag, defined in section 2.2.5
563
- * * `p` characteristic of F, where F is a finite field of characteristic p and order q = p^m
564
- * * `m` is extension degree (1 for prime fields)
565
- * * `k` is the target security target in bits (e.g. 128), from section 5.1
566
- * * `expand` is `xmd` (SHA2, SHA3, BLAKE) or `xof` (SHAKE, BLAKE-XOF)
567
- * * `hash` conforming to `utils.CHash` interface, with `outputLen` / `blockLen` props
568
- */
569
- type UnicodeOrBytes = string | Uint8Array;
570
- type Opts = {
571
- DST: UnicodeOrBytes;
572
- p: bigint;
573
- m: number;
574
- k: number;
575
- expand?: 'xmd' | 'xof';
576
- hash: CHash;
577
- };
578
- ```
448
+ - Server cannot calculate Output by itself: it doesn't know Input
449
+ - Client cannot calculate Output by itself: it doesn't know server secretKey
450
+ - An attacker interception the communication can't restore Input/Output/serverSecretKey and can't
451
+ link Input to some value.
579
452
 
580
453
  ### poseidon: Poseidon hash
581
454
 
@@ -611,13 +484,93 @@ const permutation = poseidon.poseidon(opts);
611
484
  const sponge = poseidon.poseidonSponge(opts); // use carefully, not specced
612
485
  ```
613
486
 
614
- ### modular: Modular arithmetics utilities
487
+ ### fft: Fast Fourier Transform
488
+
489
+ ```ts
490
+ import * as fft from '@noble/curves/abstract/fft.js';
491
+ import { bls12_381 } from '@noble/curves/bls12-381.js';
492
+ const Fr = bls12_381.fields.Fr;
493
+ const roots = fft.rootsOfUnity(Fr, 7n);
494
+ const fftFr = fft.FFT(roots, Fr);
495
+ ```
496
+
497
+ Experimental implementation of NTT / FFT (Fast Fourier Transform) over finite fields.
498
+ API may change at any time. The code has not been audited. Feature requests are welcome.
499
+
500
+ ### utils: byte shuffling, conversion
615
501
 
616
502
  ```ts
617
- import * as mod from '@noble/curves/abstract/modular.js';
503
+ import { bytesToHex, concatBytes, equalBytes, hexToBytes } from '@noble/curves/abstract/utils.js';
504
+
505
+ bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23]));
506
+ hexToBytes('cafe0123');
507
+ concatBytes(Uint8Array.from([0xca, 0xfe]), Uint8Array.from([0x01, 0x23]));
508
+ equalBytes(Uint8Array.of(0xca), Uint8Array.of(0xca));
509
+ ```
510
+
511
+ ### Internals
512
+
513
+ #### Elliptic curve Point math
514
+
515
+ ```js
516
+ import { secp256k1, schnorr } from '@noble/curves/secp256k1.js';
517
+ import { p256, p384, p521 } from '@noble/curves/nist.js';
518
+ import { ed25519, ristretto255 } from '@noble/curves/ed25519.js';
519
+ import { ed448, decaf448 } from '@noble/curves/ed448.js';
520
+ import { bls12_381 } from '@noble/curves/bls12-381.js'
521
+ import { bn254 } from '@noble/curves/bn254.js';
522
+ import { jubjub, babyjubjub } from '@noble/curves/misc.js';
523
+
524
+ const curves = [
525
+ secp256k1, schnorr, p256, p384, p521, ed25519, ed448,
526
+ ristretto255, decaf448,
527
+ bls12_381.G1, bls12_381.G2, bn254.G1, bn254.G2,
528
+ jubjub, babyjubjub
529
+ ];
530
+ for (const curve of curves) {
531
+ const { Point } = curve;
532
+ const { BASE, ZERO, Fp, Fn } = Point;
533
+ const p = BASE.multiply(2n);
534
+
535
+ // Initialization
536
+ if (info.type === 'weierstrass') {
537
+ // projective (homogeneous) coordinates: (X, Y, Z) ∋ (x=X/Z, y=Y/Z)
538
+ const p_ = new Point(BASE.X, BASE.Y, BASE.Z);
539
+ } else if (info.type === 'edwards') {
540
+ // extended coordinates: (X, Y, Z, T) ∋ (x=X/Z, y=Y/Z)
541
+ const p_ = new Point(BASE.X, BASE.Y, BASE.Z, BASE.T);
542
+ }
543
+
544
+ // Math
545
+ const p1 = p.add(p);
546
+ const p2 = p.double();
547
+ const p3 = p.subtract(p);
548
+ const p4 = p.negate();
549
+ const p5 = p.multiply(451n);
550
+
551
+ // MSM (multi-scalar multiplication)
552
+ const pa = [BASE, BASE.multiply(2n), BASE.multiply(4n), BASE.multiply(8n)];
553
+ const p6 = Point.msm(pa, [3n, 5n, 7n, 11n]);
554
+ const _true3 = p6.equals(BASE.multiply(129n)); // 129*G
555
+
556
+ const pcl = p.clearCofactor();
557
+ console.log(p.isTorsionFree(), p.isSmallOrder());
558
+
559
+ const r1 = p.toBytes();
560
+ const r1_ = Point.fromBytes(r1);
561
+ const r2 = p.toAffine();
562
+ const { x, y } = r2;
563
+ const r2_ = Point.fromAffine(r2);
564
+ }
565
+ ```
566
+
567
+ #### modular: Modular arithmetics & finite fields
568
+
569
+ ```js
570
+ import { mod, invert, Field } from '@noble/curves/abstract/modular.js';
618
571
 
619
572
  // Finite Field utils
620
- const fp = mod.Field(2n ** 255n - 19n); // Finite field over 2^255-19
573
+ const fp = Field(2n ** 255n - 19n); // Finite field over 2^255-19
621
574
  fp.mul(591n, 932n); // multiplication
622
575
  fp.pow(481n, 11024858120n); // exponentiation
623
576
  fp.div(5n, 17n); // division: 5/17 mod 2^255-19 == 5 * invert(17)
@@ -625,79 +578,73 @@ fp.inv(5n); // modular inverse
625
578
  fp.sqrt(21n); // square root
626
579
 
627
580
  // Non-Field generic utils are also available
628
- mod.mod(21n, 10n); // 21 mod 10 == 1n; fixed version of 21 % 10
629
- mod.invert(17n, 10n); // invert(17) mod 10; modular multiplicative inverse
630
- mod.invertBatch([1n, 2n, 4n], 21n); // => [1n, 11n, 16n] in one inversion
581
+ mod(21n, 10n); // 21 mod 10 == 1n; fixed version of 21 % 10
582
+ invert(17n, 10n); // invert(17) mod 10; modular multiplicative inverse
631
583
  ```
632
584
 
633
- Field operations are not constant-time: they are using JS bigints, see [security](#security).
585
+ All arithmetics is done with JS bigints over finite fields,
586
+ which is defined from `modular` sub-module.
587
+
588
+ Field operations are not constant-time: see [security](#security).
634
589
  The fact is mostly irrelevant, but the important method to keep in mind is `pow`,
635
590
  which may leak exponent bits, when used naïvely.
636
591
 
637
- `mod.Field` is always **field over prime number**. Non-prime fields aren't supported for now.
638
- We don't test for prime-ness for speed and because algorithms are probabilistic anyway.
639
- Initializing a non-prime field could make your app suspectible to
640
- DoS (infilite loop) on Tonelli-Shanks square root calculation.
641
-
642
- Unlike `mod.inv`, `mod.invertBatch` won't throw on `0`: make sure to throw an error yourself.
643
-
644
- ### fft: Fast Fourier Transform
645
-
646
- Experimental implementation of NTT / FFT (Fast Fourier Transform) over finite fields.
647
- API may change at any time. The code has not been audited. Feature requests are welcome.
592
+ #### weierstrass: Custom Weierstrass curve
648
593
 
649
- ```ts
650
- import * as fft from '@noble/curves/abstract/fft.js';
594
+ ```js
595
+ import { weierstrass } from '@noble/curves/abstract/weierstrass.js';
596
+ // NIST secp192r1 aka p192. https://www.secg.org/sec2-v2.pdf
597
+ const p192_CURVE = {
598
+ p: 0xfffffffffffffffffffffffffffffffeffffffffffffffffn,
599
+ n: 0xffffffffffffffffffffffff99def836146bc9b1b4d22831n,
600
+ h: 1n,
601
+ a: 0xfffffffffffffffffffffffffffffffefffffffffffffffcn,
602
+ b: 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1n,
603
+ Gx: 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012n,
604
+ Gy: 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811n,
605
+ };
606
+ const p192_Point = weierstrass(p192_CURVE);
651
607
  ```
652
608
 
653
- #### Creating private keys from hashes
654
-
655
- You can't simply make a 32-byte private key from a 32-byte hash.
656
- Doing so will make the key [biased](https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/).
657
-
658
- To make the bias negligible, we follow [FIPS 186-5 A.2](https://csrc.nist.gov/publications/detail/fips/186/5/final)
659
- and [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380#section-5.2).
660
- This means, for 32-byte key, we would need 48-byte hash to get 2^-128 bias, which matches curve security level.
609
+ Short Weierstrass curve's formula is `y² = x³ + ax + b`. `weierstrass`
610
+ expects arguments `a`, `b`, field characteristic `p`, curve order `n`,
611
+ cofactor `h` and coordinates `Gx`, `Gy` of generator point.
661
612
 
662
- `hashToPrivateScalar()` that hashes to **private key** was created for this purpose.
663
- Use [abstract/hash-to-curve](#hash-to-curve-hashing-strings-to-curve-points)
664
- if you need to hash to **public key**.
613
+ #### edwards: Custom Edwards curve
665
614
 
666
- ```ts
667
- import { p256 } from '@noble/curves/nist.js';
668
- import { sha256 } from '@noble/hashes/sha2.js';
669
- import { hkdf } from '@noble/hashes/hkdf.js';
670
- import * as mod from '@noble/curves/abstract/modular.js';
671
- const someKey = new Uint8Array(32).fill(2); // Needs to actually be random, not .fill(2)
672
- const derived = hkdf(sha256, someKey, undefined, 'application', 48); // 48 bytes for 32-byte priv
673
- const validPrivateKey = mod.hashToPrivateScalar(derived, p256.CURVE.n);
615
+ ```js
616
+ import { edwards } from '@noble/curves/abstract/edwards.js';
617
+ const ed25519_CURVE = {
618
+ p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn,
619
+ n: 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn,
620
+ h: 8n,
621
+ a: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffecn,
622
+ d: 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n,
623
+ Gx: 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an,
624
+ Gy: 0x6666666666666666666666666666666666666666666666666666666666666658n,
625
+ };
626
+ const ed25519_Point = edwards(ed25519_CURVE);
674
627
  ```
675
628
 
676
- ### utils: Useful utilities
677
-
678
- ```ts
679
- import * as utils from '@noble/curves/abstract/utils.js';
680
-
681
- utils.bytesToHex(Uint8Array.from([0xde, 0xad, 0xbe, 0xef]));
682
- utils.hexToBytes('deadbeef');
683
- utils.numberToHexUnpadded(123n);
684
- utils.hexToNumber();
629
+ Twisted Edwards curve's formula is `ax² + y² = 1 + dx²y²`.
630
+ You must specify `a`, `d`, field characteristic `p`, curve order `n` (sometimes named as `L`),
631
+ cofactor `h` and coordinates `Gx`, `Gy` of generator point.
685
632
 
686
- utils.bytesToNumberBE(Uint8Array.from([0xde, 0xad, 0xbe, 0xef]));
687
- utils.bytesToNumberLE(Uint8Array.from([0xde, 0xad, 0xbe, 0xef]));
688
- utils.numberToBytesBE(123n, 32);
689
- utils.numberToBytesLE(123n, 64);
633
+ #### Custom ECDSA instance
690
634
 
691
- utils.concatBytes(Uint8Array.from([0xde, 0xad]), Uint8Array.from([0xbe, 0xef]));
692
- utils.nLength(255n);
693
- utils.equalBytes(Uint8Array.from([0xde]), Uint8Array.from([0xde]));
635
+ ```js
636
+ import { ecdsa } from '@noble/curves/abstract/weierstrass.js';
637
+ import { sha256 } from '@noble/hashes/sha2.js';
638
+ const p192_sha256 = ecdsa(p192_Point, sha256);
639
+ // or
640
+ const p192_sha224 = ecdsa(p192.Point, sha224);
641
+
642
+ const keys = p192_sha256.keygen();
643
+ const msg = new TextEncoder().encode('custom curve');
644
+ const sig = p192_sha256.sign(msg, keys.secretKey);
645
+ const isValid = p192_sha256.verify(sig, msg, keys.publicKey);
694
646
  ```
695
647
 
696
- ### Unreleased bits
697
-
698
- - `test/unreleased-xeddsa.ts` contains implementation of XEd25519, defined by Signal
699
- - `test/misc/endomorphism.js` contains tool for generation of endomorphism params for Koblitz curves
700
-
701
648
  ## Security
702
649
 
703
650
  The library has been independently audited:
@@ -723,7 +670,7 @@ The library has been independently audited:
723
670
  - The audit has been funded by [Ryan Shea](https://www.shea.io)
724
671
 
725
672
  It is tested against property-based, cross-library and Wycheproof vectors,
726
- and is being fuzzed in [the separate repo](https://github.com/paulmillr/fuzzing).
673
+ and is being fuzzed in [the separate repo](https://github.com/paulmillr/integration-tests).
727
674
 
728
675
  If you see anything unusual: investigate and report.
729
676
 
@@ -820,8 +767,8 @@ init 10ms
820
767
  getPublicKey x 9,099 ops/sec @ 109μs/op
821
768
  sign x 7,182 ops/sec @ 139μs/op
822
769
  verify x 1,188 ops/sec @ 841μs/op
823
- getSharedSecret x 735 ops/sec @ 1ms/op
824
770
  recoverPublicKey x 1,265 ops/sec @ 790μs/op
771
+ getSharedSecret x 735 ops/sec @ 1ms/op
825
772
  schnorr.sign x 957 ops/sec @ 1ms/op
826
773
  schnorr.verify x 1,210 ops/sec @ 825μs/op
827
774
 
@@ -917,14 +864,82 @@ aggregateSignatures/2048 x 0 ops/sec @ 2823ms/op
917
864
 
918
865
  Supported node.js versions:
919
866
 
920
- - v2: v20.19+ (ESM-only)
921
- - v1: v14.21+ (ESM & CJS)
922
-
923
- ### curves v1 => curves v2
924
-
925
- WIP. Changelog of v2, when upgrading from curves v1.
926
-
927
- ### noble-secp256k1 v1 => curves v1
867
+ - v2 (2025-08): v20.19+ (ESM-only)
868
+ - v1 (2023-04): v14.21+ (ESM & CJS)
869
+
870
+ ### curves v1 to curves v2
871
+
872
+ v2 massively simplifies internals, improves security, reduces bundle size and lays path for the future.
873
+ We tried to keep v2 as much backwards-compatible as possible.
874
+
875
+ Submodule paths now require `.js` extension e.g. `curves/ed25519` => `curves/ed25519.js`.
876
+ This allows usage in bundler-less environments without source maps
877
+
878
+ **Logic** changes:
879
+
880
+ - Most methods now expect Uint8Array, string hex inputs are prohibited
881
+ - The change simplifies reasoning, improves security and reduces malleability
882
+ - `Point.fromHex` now expects string-only hex inputs, use `Point.fromBytes` for Uint8Array
883
+ - Breaking changes of ECDSA (secp256k1, p256, p384...):
884
+ - sign, verify: Switch to **prehashed messages**. Instead of
885
+ messageHash, the methods now expect unhashed message.
886
+ To bring back old behavior, use option `{prehash: false}`
887
+ - sign, verify: Switch to **lowS signatures** by default.
888
+ This change doesn't affect secp256k1, which has been using lowS since beginning.
889
+ To bring back old behavior, use option `{lowS: true}`
890
+ - sign, verify: Switch to **Uint8Array signatures** (format: 'compact') by default.
891
+ - verify: **der format must be explicitly specified** in `{format: 'der'}`.
892
+ This reduces malleability
893
+ - verify: **prohibit Signature-instance** signature. User must now always do
894
+ `signature.toBytes()`
895
+ - Breaking changes of BLS signatures (bls12-381, bn254):
896
+ - Move getPublicKey, sign, verify, signShortSignature etc into two new namespaces:
897
+ bls.longSignatures (G1 pubkeys, G2 sigs) and bls.shortSignatures (G1 sigs, G2 pubkeys).
898
+ - verifyBatch now expects array of inputs `{message: ..., publicKey: ...}[]`
899
+ - Curve changes:
900
+ - Massively simplify curve creation, split it into point creation & sig generator creation
901
+ - New methods are `weierstrass() + ecdsa()` / `edwards() + eddsa()`
902
+ - weierstrass / edwards expect simplified curve params (Fp became p)
903
+ - ecdsa / eddsa expect Point class and hash
904
+ - Remove unnecessary Fn argument in `pippenger`
905
+ - modular changes:
906
+ - Field#fromBytes() now validates elements to be in 0..order-1 range
907
+ - Massive type renamings and improvements
908
+
909
+ **Renamings:**
910
+
911
+ - Module changes
912
+ - `p256`, `p384`, `p521` modules have been moved into `nist`
913
+ - `jubjub` module has been moved into `misc`
914
+ - Point changes
915
+ - ExtendedPoint, ProjectivePoint => Point
916
+ - Point coordinates (projective / extended) from px/ex, py/ey, pz/ez, et => X, Y, Z, T
917
+ - Point.normalizeZ, Point.msm => separate methods in `abstract/curve.js` submodule
918
+ - Point.fromPrivateKey() got removed, use `Point.BASE.multiply()` and `Point.Fn.fromBytes(secretKey)`
919
+ - toRawBytes, fromRawBytes => toBytes, fromBytes
920
+ - RistrettoPoint => ristretto255.Point, DecafPoiont => decaf448.Point
921
+ - Signature (ECDSA) changes
922
+ - toCompactRawBytes, toDERRawBytes => toBytes('compact'), toBytes('der')
923
+ - toCompactHex, toDERHex => toHex('compact'), toHex('der')
924
+ - fromCompact, fromDER => fromBytes(format), fromHex(format)
925
+ - utils changes
926
+ - randomPrivateKey => randomSecretKey
927
+ - utils.precompute, Point#_setWindowSize => Point#precompute
928
+ - edwardsToMontgomery => utils.toMontgomery
929
+ - edwardsToMontgomeryPriv => utils.toMontgomerySecret
930
+ - Rename all curve-specific hash-to-curve methods to `*curve*_hasher`.
931
+ Example: `secp256k1.hashToCurve` => `secp256k1_hasher.hashToCurve()`
932
+
933
+ **Removed features:**
934
+
935
+ - Point#multiplyAndAddUnsafe, Point#hasEvenY
936
+ - CURVE property with all kinds of random stuff. Point.CURVE() now replaces it, but only provides
937
+ curve parameters
938
+ - Remove `pasta`, `bn254_weierstrass` (NOT pairing-based bn254) curves
939
+ - Field.MASK
940
+ - utils.normPrivateKeyToScalar
941
+
942
+ ### noble-secp256k1 v1 to curves v1
928
943
 
929
944
  Previously, the library was split into single-feature packages
930
945
  [noble-secp256k1](https://github.com/paulmillr/noble-secp256k1),
@@ -932,7 +947,7 @@ Previously, the library was split into single-feature packages
932
947
  [noble-bls12-381](https://github.com/paulmillr/noble-bls12-381).
933
948
 
934
949
  Curves continue their original work. The single-feature packages changed their
935
- direction towards providing minimal 4kb implementations of cryptography,
950
+ direction towards providing minimal 5kb implementations of cryptography,
936
951
  which means they have less features.
937
952
 
938
953
  - `getPublicKey`
@@ -961,9 +976,9 @@ which means they have less features.
961
976
  - `utils` were split into `utils` (same api as in noble-curves) and
962
977
  `etc` (`hmacSha256Sync` and others)
963
978
 
964
- ### noble-ed25519 v1 => curves v1
979
+ ### noble-ed25519 v1 to curves v1
965
980
 
966
- Upgrading from [@noble/ed25519](https://github.com/paulmillr/noble-ed25519) 1.7:
981
+ Upgrading from [@noble/ed25519](https://github.com/paulmillr/noble-ed25519):
967
982
 
968
983
  - Methods are now sync by default
969
984
  - `bigint` is no longer allowed in `getPublicKey`, `sign`, `verify`. Reason: ed25519 is LE, can lead to bugs
@@ -974,7 +989,7 @@ Upgrading from [@noble/ed25519](https://github.com/paulmillr/noble-ed25519) 1.7:
974
989
  - `getSharedSecret` was moved to `x25519` module
975
990
  - `toX25519` has been moved to `edwardsToMontgomeryPub` and `edwardsToMontgomeryPriv` methods
976
991
 
977
- ### noble-bls12-381 => curves v1
992
+ ### noble-bls12-381 to curves v1
978
993
 
979
994
  Upgrading from [@noble/bls12-381](https://github.com/paulmillr/noble-bls12-381):
980
995