@noble/curves 2.0.0-beta.1 → 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 (118) hide show
  1. package/README.md +442 -273
  2. package/abstract/bls.d.ts +17 -17
  3. package/abstract/bls.d.ts.map +1 -1
  4. package/abstract/bls.js.map +1 -1
  5. package/abstract/curve.d.ts +14 -9
  6. package/abstract/curve.d.ts.map +1 -1
  7. package/abstract/curve.js +9 -3
  8. package/abstract/curve.js.map +1 -1
  9. package/abstract/edwards.d.ts +7 -9
  10. package/abstract/edwards.d.ts.map +1 -1
  11. package/abstract/edwards.js +12 -16
  12. package/abstract/edwards.js.map +1 -1
  13. package/abstract/hash-to-curve.d.ts +32 -31
  14. package/abstract/hash-to-curve.d.ts.map +1 -1
  15. package/abstract/hash-to-curve.js +15 -14
  16. package/abstract/hash-to-curve.js.map +1 -1
  17. package/abstract/modular.d.ts.map +1 -1
  18. package/abstract/modular.js +7 -5
  19. package/abstract/modular.js.map +1 -1
  20. package/abstract/montgomery.d.ts +3 -3
  21. package/abstract/montgomery.d.ts.map +1 -1
  22. package/abstract/montgomery.js +9 -13
  23. package/abstract/montgomery.js.map +1 -1
  24. package/abstract/oprf.d.ts +4 -4
  25. package/abstract/oprf.d.ts.map +1 -1
  26. package/abstract/oprf.js +2 -2
  27. package/abstract/oprf.js.map +1 -1
  28. package/abstract/poseidon.d.ts.map +1 -1
  29. package/abstract/poseidon.js +8 -9
  30. package/abstract/poseidon.js.map +1 -1
  31. package/abstract/weierstrass.d.ts +66 -20
  32. package/abstract/weierstrass.d.ts.map +1 -1
  33. package/abstract/weierstrass.js +72 -68
  34. package/abstract/weierstrass.js.map +1 -1
  35. package/bls12-381.d.ts +3 -9
  36. package/bls12-381.d.ts.map +1 -1
  37. package/bls12-381.js +3 -14
  38. package/bls12-381.js.map +1 -1
  39. package/bn254.d.ts +3 -3
  40. package/bn254.d.ts.map +1 -1
  41. package/bn254.js.map +1 -1
  42. package/ed25519.d.ts +22 -18
  43. package/ed25519.d.ts.map +1 -1
  44. package/ed25519.js +59 -31
  45. package/ed25519.js.map +1 -1
  46. package/ed448.d.ts +17 -8
  47. package/ed448.d.ts.map +1 -1
  48. package/ed448.js +69 -52
  49. package/ed448.js.map +1 -1
  50. package/index.d.ts +1 -0
  51. package/index.js +20 -4
  52. package/index.js.map +1 -1
  53. package/misc.js +2 -2
  54. package/misc.js.map +1 -1
  55. package/nist.d.ts +20 -2
  56. package/nist.d.ts.map +1 -1
  57. package/nist.js +30 -10
  58. package/nist.js.map +1 -1
  59. package/package.json +14 -13
  60. package/secp256k1.d.ts +10 -7
  61. package/secp256k1.d.ts.map +1 -1
  62. package/secp256k1.js +15 -16
  63. package/secp256k1.js.map +1 -1
  64. package/src/abstract/bls.ts +22 -22
  65. package/src/abstract/curve.ts +19 -5
  66. package/src/abstract/edwards.ts +20 -23
  67. package/src/abstract/hash-to-curve.ts +50 -51
  68. package/src/abstract/modular.ts +7 -5
  69. package/src/abstract/montgomery.ts +12 -18
  70. package/src/abstract/oprf.ts +5 -5
  71. package/src/abstract/poseidon.ts +6 -8
  72. package/src/abstract/weierstrass.ts +139 -89
  73. package/src/bls12-381.ts +4 -15
  74. package/src/bn254.ts +6 -6
  75. package/src/ed25519.ts +65 -40
  76. package/src/ed448.ts +87 -69
  77. package/src/index.ts +19 -3
  78. package/src/misc.ts +2 -2
  79. package/src/nist.ts +31 -15
  80. package/src/secp256k1.ts +16 -18
  81. package/src/utils.ts +33 -83
  82. package/src/webcrypto.ts +148 -107
  83. package/utils.d.ts +4 -20
  84. package/utils.d.ts.map +1 -1
  85. package/utils.js +30 -73
  86. package/utils.js.map +1 -1
  87. package/webcrypto.d.ts +73 -21
  88. package/webcrypto.d.ts.map +1 -1
  89. package/webcrypto.js +101 -76
  90. package/webcrypto.js.map +1 -1
  91. package/_shortw_utils.d.ts +0 -19
  92. package/_shortw_utils.d.ts.map +0 -1
  93. package/_shortw_utils.js +0 -20
  94. package/_shortw_utils.js.map +0 -1
  95. package/abstract/utils.d.ts +0 -5
  96. package/abstract/utils.d.ts.map +0 -1
  97. package/abstract/utils.js +0 -23
  98. package/abstract/utils.js.map +0 -1
  99. package/jubjub.d.ts +0 -12
  100. package/jubjub.d.ts.map +0 -1
  101. package/jubjub.js +0 -15
  102. package/jubjub.js.map +0 -1
  103. package/p256.d.ts +0 -16
  104. package/p256.d.ts.map +0 -1
  105. package/p256.js +0 -13
  106. package/p256.js.map +0 -1
  107. package/p384.d.ts +0 -16
  108. package/p384.d.ts.map +0 -1
  109. package/p384.js +0 -13
  110. package/p384.js.map +0 -1
  111. package/p521.d.ts +0 -16
  112. package/p521.d.ts.map +0 -1
  113. package/p521.js +0 -13
  114. package/p521.js.map +0 -1
  115. package/pasta.d.ts +0 -10
  116. package/pasta.d.ts.map +0 -1
  117. package/pasta.js +0 -13
  118. package/pasta.js.map +0 -1
package/README.md CHANGED
@@ -12,7 +12,7 @@ Audited & minimal JS implementation of elliptic curve cryptography.
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,12 +50,12 @@ 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';
58
+ import { jubjub, babyjubjub, brainpoolP256r1, brainpoolP384r1, brainpoolP512r1 } from '@noble/curves/misc.js';
59
59
 
60
60
  // hash-to-curve
61
61
  import { secp256k1_hasher } from '@noble/curves/secp256k1.js';
@@ -66,48 +66,75 @@ import { decaf448_hasher } from '@noble/curves/ed448.js';
66
66
  // OPRFs
67
67
  import { p256_oprf, p384_oprf, p521_oprf } from '@noble/curves/nist.js';
68
68
  import { ristretto255_oprf } from '@noble/curves/ed25519.js';
69
- import { decaf448_orpf } from '@noble/curves/ed448.js';
69
+ import { decaf448_oprf } from '@noble/curves/ed448.js';
70
70
 
71
71
  // utils
72
+ import { bytesToHex, hexToBytes, concatBytes } from '@noble/curves/abstract/utils.js';
73
+ import { Field } from '@noble/curves/abstract/modular.js';
72
74
  import { weierstrass, ecdsa } from '@noble/curves/abstract/weierstrass.js';
73
75
  import { edwards, eddsa } from '@noble/curves/abstract/edwards.js';
74
76
  import { poseidon, poseidonSponge } from '@noble/curves/abstract/poseidon.js';
75
- import { Field, mod, pow } from '@noble/curves/abstract/modular.js';
76
77
  import { FFT, poly } from '@noble/curves/abstract/fft.js';
77
- import { bytesToHex, hexToBytes, concatBytes, utf8ToBytes } from '@noble/curves/abstract/utils.js';
78
78
  ```
79
79
 
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)
101
+ - [Security](#security)
102
+ - [Speed](#speed)
103
+ - [Contributing & testing](#contributing--testing)
104
+ - [Upgrading](#upgrading)
80
105
 
81
106
  ### ECDSA, EdDSA, Schnorr signatures
82
107
 
83
- #### secp256k1, p256, p384, p521, ed25519, ed448
108
+ #### secp256k1, p256, p384, p521, ed25519, ed448, brainpool
84
109
 
85
110
  ```js
86
111
  import { secp256k1, schnorr } from '@noble/curves/secp256k1.js';
87
112
  import { p256, p384, p521 } from '@noble/curves/nist.js';
88
113
  import { ed25519 } from '@noble/curves/ed25519.js';
89
114
  import { ed448 } from '@noble/curves/ed448.js';
90
-
91
- import { hexToBytes, utf8ToBytes } from '@noble/curves/utils.js';
92
-
93
- for (const curve of [secp256k1, schnorr, p256, p384, p521, ed25519, ed448]) {
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
+ ]) {
94
122
  const { secretKey, publicKey } = curve.keygen();
95
- const msg = utf8ToBytes('hello noble');
123
+ const msg = new TextEncoder().encode('hello noble');
96
124
  const sig = curve.sign(msg, secretKey);
97
125
  const isValid = curve.verify(sig, msg, publicKey);
98
- console.log(curve, secretKey, publicKey, sig);
126
+ console.log(curve, secretKey, publicKey, sig, isValid);
99
127
  }
100
128
 
101
129
  // Specific private key
102
- const priv2 = hexToBytes('46c930bc7bb4db7f55da20798697421b98c4175a52c630294d75a84b9c126236');
103
- const pub2 = secp256k1.getPublicKey(priv2);
130
+ import { hexToBytes } from '@noble/curves/utils.js';
131
+ const secret2 = hexToBytes('46c930bc7bb4db7f55da20798697421b98c4175a52c630294d75a84b9c126236');
132
+ const pub2 = secp256k1.getPublicKey(secret2);
104
133
  ```
105
134
 
106
- - We provide NIST P256 (same as secp256r1 / prime256v1), P384 (secp384r1) & P521 (secp521r1),
107
- their hash-to-curve methods, and OPRFs.
108
- - ECDSA signatures conform to ....
109
- - EdDSA conform to RFC8032.
110
- - Schnorr is only available for secp256k1 and conforms to BIP340.
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).
111
138
 
112
139
  #### ristretto255, decaf448
113
140
 
@@ -115,67 +142,90 @@ their hash-to-curve methods, and OPRFs.
115
142
  import { ristretto255, ristretto255_hasher, ristretto255_oprf } from '@noble/curves/ed25519.js';
116
143
  import { decaf448, decaf448_hasher, decaf448_oprf } from '@noble/curves/ed448.js';
117
144
 
118
- import { sha512 } from '@noble/hashes/sha2.js';
119
- import { shake256 } from '@noble/hashes/sha3.js';
120
-
121
- const msg = new TextEncoder().encode('Ristretto is traditionally a short shot of espresso coffee');
122
- hashToCurve(msg);
123
-
124
- const dp = DecafPoint.fromHex(
125
- 'c898eb4f87f97c564c6fd61fc7e49689314a1f818ec85eeb3bd5514ac816d38778f69ef347a89fca817e66defdedce178c7cc709b2116e75'
126
- );
127
- DecafPoint.BASE.multiply(2n).add(dp).subtract(DecafPoint.BASE).toBytes();
128
- DecafPoint.ZERO.equals(dp) === false;
129
- // pre-hashed hash-to-curve
130
- DecafPoint.hashToCurve(shake256(msg, { dkLen: 112 }));
131
- // full hash-to-curve including domain separation tag
132
- hashToDecaf448(msg, { DST: 'decaf448_XOF:SHAKE256_D448MAP_RO_' });
145
+ console.log(ristretto255.Point, decaf448.Point);
133
146
  ```
134
147
 
135
- Check out [RFC9496](https://www.rfc-editor.org/rfc/rfc9496) more info on ristretto255 & decaf448.
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).
136
150
 
137
151
  #### Prehashed signing
138
152
 
139
- #### Hedged ECDSA with noise
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 });
162
+ ```
140
163
 
141
- #### Consensus-friendliness vs e-voting
164
+ ECDSA `sign()` allows providing `prehash: false`, which enables using custom hashes.
142
165
 
143
- #### webcrypto: Friendly wrapper
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.
144
174
 
175
+ #### Hedged ECDSA with noise
145
176
 
146
177
  ```js
147
- const sig2 = curve.sign(msg, secretKey, { prehash: false })
148
- const msg = new Uint8Array(32).fill(1); // message hash (not message) in ecdsa
149
- const sig = secp256k1.sign(msg, priv); // `{prehash: true}` option is available
150
- const isValid = secp256k1.verify(sig, msg, pub) === true;
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 });
188
+ ```
151
189
 
152
- const isValid = ed25519.verify(sig, msg, pub); // Default mode: follows ZIP215
190
+ ECDSA `sign()` allows providing `extraEntropy`, which switches sig generation to hedged mode.
153
191
 
154
- // SBS / e-voting / RFC8032 / FIPS 186-5
155
- const isValidRfc = ed25519.verify(sig, msg, pub, { zip215: false });
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.
156
197
 
157
- // Variants from RFC8032: with context, prehashed
158
- import { ed25519ctx, ed25519ph } from '@noble/curves/ed25519.js';
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/).
159
202
 
203
+ #### Consensus-friendliness vs e-voting
160
204
 
161
- import { secp256k1 } from '@noble/curves/secp256k1.js';
162
- // random entropy
163
- const sigNoisy = secp256k1.sign(msg, priv, { extraEntropy: true });
164
- // set custom entropy
165
- const ent = new Uint8Array(32).fill(3);
166
- const sigNoisy2 = secp256k1.sign(msg, priv, { extraEntropy: ent });
205
+ ```js
206
+ import { ed25519 } 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 });
167
214
  ```
168
215
 
169
- - Hedged ECDSA is add-on, providing improved protection against fault attacks.
170
- It adds noise to signatures.
171
- The technique is used by default in BIP340; we also implement them optionally for ECDSA.
172
- Check out blog post [Deterministic signatures are not your friends](https://paulmillr.com/posts/deterministic-signatures/)
173
- and [cfrg-det-sigs-with-noise draft](https://datatracker.ietf.org/doc/draft-irtf-cfrg-det-sigs-with-noise/).
174
- - In ed25519 & ed448, default `verify` behavior follows ZIP215 and
175
- can be used in consensus-critical applications.
176
- If you need SBS (Strongly Binding Signatures) and FIPS 186-5 compliance,
177
- use `zip215: false`. Check out [Edwards Signatures section for more info](#edwards-twisted-edwards-curve).
178
- 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.
217
+
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
227
+
228
+ Both modes have SUF-CMA (strong unforgeability under chosen message attacks).
179
229
 
180
230
  ### ECDH: Diffie-Hellman shared secrets
181
231
 
@@ -192,57 +242,122 @@ for (const curve of [secp256k1, schnorr, x25519, x448, p256, p384, p521]) {
192
242
  console.log('alice', alice, 'bob', bob, 'shared', sharedKey);
193
243
  }
194
244
 
195
- x25519.getSharedSecret(priv, pub) === x25519.scalarMult(priv, pub); // aliases
196
- x25519.getPublicKey(priv) === x25519.scalarMultBase(priv);
197
- // ed25519 => x25519 conversion
198
- import { edwardsToMontgomeryPub, edwardsToMontgomeryPriv } from '@noble/curves/ed25519.js';
199
- edwardsToMontgomeryPub(ed25519.getPublicKey(ed25519.utils.randomPrivateKey()));
200
- edwardsToMontgomeryPriv(ed25519.utils.randomPrivateKey());
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);
201
252
  ```
202
253
 
203
- - X25519 aka ECDH on Curve25519 from [RFC7748](https://www.rfc-editor.org/rfc/rfc7748).
204
- - X448 aka ECDH on Curve448 from [RFC7748](https://www.rfc-editor.org/rfc/rfc7748)
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).
205
256
 
206
- > [!NOTE]
207
- > In Weierstrass curves, shared secrets include y-parity bytes. To strip it, use `key.slice(1)`.
257
+ In Weierstrass curves, shared secrets:
258
+
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)`
261
+
262
+ #### webcrypto: Friendly wrapper
208
263
 
209
264
  > [!NOTE]
210
- > In Weierstrass curves, shared secrets are not hashed: use hashing or KDF on top, like `sha256(shared)` or `hkdf(shared)`.
265
+ > Webcrypto methods are always async.
266
+
267
+ ##### webcrypto signatures
268
+
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
+ })();
288
+ ```
289
+
290
+ ##### webcrypto ecdh
291
+
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
+ })();
309
+ ```
211
310
 
311
+ ##### Key conversion from noble to webcrypto and back
312
+
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
+ ```
212
330
 
213
331
  ### BLS signatures, bls12-381, bn254 aka alt_bn128
214
332
 
215
333
  ```ts
216
334
  import { bls12_381 } from '@noble/curves/bls12-381.js';
217
- import { hexToBytes } from '@noble/curves/abstract/utils.js';
218
-
219
- // private keys are 32 bytes
220
- const privKey = hexToBytes('67d53f170b908cabb9eb326c3c337762d59289a8fec79f7bc9254b584b73265c');
221
- // const privKey = bls12_381.utils.randomPrivateKey();
222
335
 
223
- // Long signatures (G2), short public keys (G1)
336
+ // G1 pubkeys, G2 sigs
224
337
  const blsl = bls12_381.longSignatures;
225
- const publicKey = blsl.getPublicKey(privateKey);
226
- // Sign msg with custom (Ethereum) DST
227
- const msg = new TextEncoder().encode('hello');
228
- const DST = 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_';
229
- const msgp = blsl.hash(msg, DST);
230
- 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);
231
346
  const isValid = blsl.verify(signature, msgp, publicKey);
232
- console.log({ publicKey, signature, isValid });
347
+ console.log('long', { publicKey, signature, isValid });
233
348
 
234
- // Short signatures (G1), long public keys (G2)
349
+ // G1 sigs, G2 pubkeys
235
350
  const blss = bls12_381.shortSignatures;
236
- const publicKey2 = blss.getPublicKey(privateKey);
237
- const msgp2 = blss.hash(new TextEncoder().encode('hello'), 'BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_')
238
- 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);
239
354
  const isValid2 = blss.verify(signature2, msgp2, publicKey);
240
355
  console.log({ publicKey2, signature2, isValid2 });
241
356
 
242
357
  // Aggregation
243
358
  const aggregatedKey = bls12_381.longSignatures.aggregatePublicKeys([
244
- bls12_381.utils.randomPrivateKey(),
245
- bls12_381.utils.randomPrivateKey(),
359
+ bls12_381.utils.randomSecretKey(),
360
+ bls12_381.utils.randomSecretKey(),
246
361
  ]);
247
362
  // const aggregatedSig = bls.aggregateSignatures(sigs)
248
363
 
@@ -252,7 +367,7 @@ const aggregatedKey = bls12_381.longSignatures.aggregatePublicKeys([
252
367
  // bls.fields.Fp12.finalExponentiate(bls.fields.Fp12.mul(PointG1, PointG2));
253
368
 
254
369
  // Others
255
- // bls.G1.ProjectivePoint.BASE, bls.G2.ProjectivePoint.BASE;
370
+ // bls.G1.Point.BASE, bls.G2.Point.BASE;
256
371
  // bls.fields.Fp, bls.fields.Fp2, bls.fields.Fp12, bls.fields.Fr;
257
372
  ```
258
373
 
@@ -263,18 +378,139 @@ The BN254 API mirrors [BLS](#bls12-381). The curve was previously called alt_bn1
263
378
  The implementation is compatible with [EIP-196](https://eips.ethereum.org/EIPS/eip-196) and
264
379
  [EIP-197](https://eips.ethereum.org/EIPS/eip-197).
265
380
 
266
- We don't implement Point methods toBytes.
267
- To work around this limitation, has to initialize points on their own from BigInts.
268
- 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).
269
383
  Points of divergence:
270
384
 
271
385
  - Endianness: LE vs BE (byte-swapped)
272
386
  - Flags as first hex bits (similar to BLS) vs no-flags
273
387
  - Imaginary part last in G2 vs first (c0, c1 vs c1, c0)
274
388
 
275
- For example usage, check out [the implementation of bn254 EVM precompiles](https://github.com/paulmillr/noble-curves/blob/3ed792f8ad9932765b84d1064afea8663a255457/test/bn254.test.js#L697).
389
+ ### hash-to-curve: hashing to curve points
390
+
391
+ ```ts
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
407
+ };
408
+
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';
426
+ ```
427
+
428
+ The module allows to hash arbitrary strings to elliptic curve points. Implements [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380).
429
+
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.
434
+
435
+ ### OPRFs
436
+
437
+ ```js
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';
441
+ ```
442
+
443
+ We provide OPRFs (oblivious pseudorandom functions),
444
+ conforming to [RFC 9497](https://www.rfc-editor.org/rfc/rfc9497).
445
+
446
+ OPRF allows to interactively create an `Output = PRF(Input, serverSecretKey)`:
447
+
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.
452
+
453
+ ### poseidon: Poseidon hash
454
+
455
+ Implements [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash:
456
+ permutation and sponge.
457
+
458
+ There are many poseidon variants with different constants.
459
+ We don't provide them: you should construct them manually.
460
+ Check out [scure-starknet](https://github.com/paulmillr/scure-starknet) package for a proper example.
461
+
462
+ ```ts
463
+ import { poseidon, poseidonSponge } from '@noble/curves/abstract/poseidon.js';
464
+
465
+ const rate = 2;
466
+ const capacity = 1;
467
+ const { mds, roundConstants } = poseidon.grainGenConstants({
468
+ Fp,
469
+ t: rate + capacity,
470
+ roundsFull: 8,
471
+ roundsPartial: 31,
472
+ });
473
+ const opts = {
474
+ Fp,
475
+ rate,
476
+ capacity,
477
+ sboxPower: 17,
478
+ mds,
479
+ roundConstants,
480
+ roundsFull: 8,
481
+ roundsPartial: 31,
482
+ };
483
+ const permutation = poseidon.poseidon(opts);
484
+ const sponge = poseidon.poseidonSponge(opts); // use carefully, not specced
485
+ ```
486
+
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
501
+
502
+ ```ts
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
276
512
 
277
- ### Low-level math: EC Point, modular
513
+ #### Elliptic curve Point math
278
514
 
279
515
  ```js
280
516
  import { secp256k1, schnorr } from '@noble/curves/secp256k1.js';
@@ -292,7 +528,7 @@ const curves = [
292
528
  jubjub, babyjubjub
293
529
  ];
294
530
  for (const curve of curves) {
295
- const { info, Point } = curve;
531
+ const { Point } = curve;
296
532
  const { BASE, ZERO, Fp, Fn } = Point;
297
533
  const p = BASE.multiply(2n);
298
534
 
@@ -328,7 +564,7 @@ for (const curve of curves) {
328
564
  }
329
565
  ```
330
566
 
331
- #### Modular math
567
+ #### modular: Modular arithmetics & finite fields
332
568
 
333
569
  ```js
334
570
  import { mod, invert, Field } from '@noble/curves/abstract/modular.js';
@@ -346,59 +582,14 @@ mod(21n, 10n); // 21 mod 10 == 1n; fixed version of 21 % 10
346
582
  invert(17n, 10n); // invert(17) mod 10; modular multiplicative inverse
347
583
  ```
348
584
 
349
- ECDSA signatures:
350
-
351
- - Are represented by `Signature` instances with `r, s` and optional `recovery` properties
352
- - Have `recoverPublicKey()`, `toBytes()` with optional `format: 'compact' | 'der'`
353
- - Can be prehashed, or non-prehashed:
354
- - `sign(msgHash, privKey)` (default, prehash: false) - you did hashing before
355
- - `sign(msg, privKey, {prehash: true})` - curves will do hashing for you
356
- - Are generated deterministically, following [RFC6979](https://www.rfc-editor.org/rfc/rfc6979).
357
- - Consider [hedged ECDSA with noise](#hedged-ecdsa-with-noise) for adding randomness into
358
- for signatures, to get improved security against fault attacks.
359
-
360
- All arithmetics is done with JS
361
- bigints over finite fields, which is defined from `modular` sub-module.
362
- For scalar multiplication, we use
363
- [precomputed tables with w-ary non-adjacent form (wNAF)](https://paulmillr.com/posts/noble-secp256k1-fast-ecc/).
364
- Precomputes are enabled for weierstrass and edwards BASE points of a curve.
365
- 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).
366
589
  The fact is mostly irrelevant, but the important method to keep in mind is `pow`,
367
590
  which may leak exponent bits, when used naïvely.
368
591
 
369
- `mod.Field` is always **field over prime number**. Non-prime fields aren't supported for now.
370
- We don't test for prime-ness for speed and because algorithms are probabilistic anyway.
371
- Initializing a non-prime field could make your app suspectible to
372
- DoS (infilite loop) on Tonelli-Shanks square root calculation.
373
-
374
- Unlike `mod.inv`, `mod.invertBatch` won't throw on `0`: make sure to throw an error yourself.
375
-
376
- We define ed25519, ed448; user can use custom curves with EdDSA,
377
- but EdDSA in general is not defined. Check out `edwards.ts` source code.
378
-
379
- For EdDSA signatures:
380
-
381
- - `zip215: true` is default behavior. It has slightly looser verification logic
382
- to be [consensus-friendly](https://hdevalence.ca/blog/2020-10-04-its-25519am), following [ZIP215](https://zips.z.cash/zip-0215) rules
383
- - `zip215: false` switches verification criteria to strict
384
- [RFC8032](https://www.rfc-editor.org/rfc/rfc8032) / [FIPS 186-5](https://csrc.nist.gov/publications/detail/fips/186/5/final)
385
- and additionally provides [non-repudiation with SBS](https://eprint.iacr.org/2020/1244),
386
- which is useful for:
387
- - Contract Signing: if A signed an agreement with B using key that allows repudiation, it can later claim that it signed a different contract
388
- - E-voting: malicious voters may pick keys that allow repudiation in order to deny results
389
- - Blockchains: transaction of amount X might also be valid for a different amount Y
390
- - Both modes have SUF-CMA (strong unforgeability under chosen message attacks).
391
-
392
- ### Making custom curves
393
-
394
- - Short Weierstrass curve's formula is `y² = x³ + ax + b`. `weierstrass`
395
- expects arguments `a`, `b`, field characteristic `p`, curve order `n`,
396
- cofactor `h` and coordinates `Gx`, `Gy` of generator point.
397
- - Twisted Edwards curve's formula is `ax² + y² = 1 + dx²y²`.
398
- You must specify `a`, `d`, field characteristic `p`, curve order `n` (sometimes named as `L`),
399
- cofactor `h` and coordinates `Gx`, `Gy` of generator point.
400
-
401
- #### Custom Weierstrass curve
592
+ #### weierstrass: Custom Weierstrass curve
402
593
 
403
594
  ```js
404
595
  import { weierstrass } from '@noble/curves/abstract/weierstrass.js';
@@ -415,7 +606,11 @@ const p192_CURVE = {
415
606
  const p192_Point = weierstrass(p192_CURVE);
416
607
  ```
417
608
 
418
- #### Custom Edwards curve
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.
612
+
613
+ #### edwards: Custom Edwards curve
419
614
 
420
615
  ```js
421
616
  import { edwards } from '@noble/curves/abstract/edwards.js';
@@ -431,117 +626,23 @@ const ed25519_CURVE = {
431
626
  const ed25519_Point = edwards(ed25519_CURVE);
432
627
  ```
433
628
 
434
- #### Custom ECDSA, requires curve and hash
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.
632
+
633
+ #### Custom ECDSA instance
435
634
 
436
635
  ```js
437
636
  import { ecdsa } from '@noble/curves/abstract/weierstrass.js';
438
637
  import { sha256 } from '@noble/hashes/sha2.js';
439
- const p192 = ecdsa(p192_Point, sha256);
638
+ const p192_sha256 = ecdsa(p192_Point, sha256);
639
+ // or
440
640
  const p192_sha224 = ecdsa(p192.Point, sha224);
441
- const keys = p192.keygen();
442
- const msg = new TextEncoder().encode('custom curve');
443
- const sig = p192.sign(msg, keys.secretKey);
444
- const isValid = p192.verify(sig, msg, keys.publicKey);
445
- // const ed25519 = eddsa(ed25519_Point, { hash: sha512 });
446
- ```
447
-
448
- ### hash-to-curve: hashing to curve points
449
-
450
- ```ts
451
- import { secp256k1_hasher } from '@noble/curves/secp256k1.js';
452
- import { p256_hasher, p384_hasher, p521_hasher } from '@noble/curves/nist.js';
453
- import { ristretto255_hasher } from '@noble/curves/ed25519.js';
454
- import { decaf448_hasher } from '@noble/curves/ed448.js';
455
-
456
- import { bls12_381 } from '@noble/curves/bls12-381.js';
457
- bls12_381.G1.hashToCurve(randomBytes(), { DST: 'another' });
458
- bls12_381.G2.hashToCurve(randomBytes(), { DST: 'custom' });
459
-
460
- import { expand_message_xmd, expand_message_xof, hash_to_field } from '@noble/curves/abstract/hash-to-curve.js';
461
- ```
462
-
463
- The module allows to hash arbitrary strings to elliptic curve points. Implements [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380).
464
-
465
- Every curve has exported `hashToCurve` and `encodeToCurve` methods. You should always prefer `hashToCurve` for security:
466
-
467
- ### oprf: oblivious pseudorandom functions
468
-
469
- ```js
470
- import { p256_oprf, p384_oprf, p521_oprf } from '@noble/curves/nist.js';
471
- import { ristretto255_oprf } from '@noble/curves/ed25519.js';
472
- import { decaf448_orpf } from '@noble/curves/ed448.js';
473
- ```
474
-
475
- We provide OPRFs, conforming to [RFC 9497](https://www.rfc-editor.org/rfc/rfc9497).
476
-
477
- OPRF allows to interactively create an `Output = PRF(Input, serverSecretKey)`:
478
641
 
479
- - Server cannot calculate Output by itself: it doesn't know Input
480
- - Client cannot calculate Output by itself: it doesn't know server secretKey
481
- - An attacker interception the communication can't restore Input/Output/serverSecretKey and can't
482
- link Input to some value.
483
-
484
- ### poseidon: Poseidon hash
485
-
486
- Implements [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash:
487
- permutation and sponge.
488
-
489
- There are many poseidon variants with different constants.
490
- We don't provide them: you should construct them manually.
491
- Check out [scure-starknet](https://github.com/paulmillr/scure-starknet) package for a proper example.
492
-
493
- ```ts
494
- import { poseidon, poseidonSponge } from '@noble/curves/abstract/poseidon.js';
495
-
496
- const rate = 2;
497
- const capacity = 1;
498
- const { mds, roundConstants } = poseidon.grainGenConstants({
499
- Fp,
500
- t: rate + capacity,
501
- roundsFull: 8,
502
- roundsPartial: 31,
503
- });
504
- const opts = {
505
- Fp,
506
- rate,
507
- capacity,
508
- sboxPower: 17,
509
- mds,
510
- roundConstants,
511
- roundsFull: 8,
512
- roundsPartial: 31,
513
- };
514
- const permutation = poseidon.poseidon(opts);
515
- const sponge = poseidon.poseidonSponge(opts); // use carefully, not specced
516
- ```
517
-
518
- ### fft: Fast Fourier Transform
519
-
520
- Experimental implementation of NTT / FFT (Fast Fourier Transform) over finite fields.
521
- API may change at any time. The code has not been audited. Feature requests are welcome.
522
-
523
- ```ts
524
- import * as fft from '@noble/curves/abstract/fft.js';
525
- ```
526
-
527
- ### utils: byte shuffling, conversion
528
-
529
- ```ts
530
- import * as utils from '@noble/curves/abstract/utils.js';
531
-
532
- utils.bytesToHex(Uint8Array.from([0xde, 0xad, 0xbe, 0xef]));
533
- utils.hexToBytes('deadbeef');
534
- utils.numberToHexUnpadded(123n);
535
- utils.hexToNumber();
536
-
537
- utils.bytesToNumberBE(Uint8Array.from([0xde, 0xad, 0xbe, 0xef]));
538
- utils.bytesToNumberLE(Uint8Array.from([0xde, 0xad, 0xbe, 0xef]));
539
- utils.numberToBytesBE(123n, 32);
540
- utils.numberToBytesLE(123n, 64);
541
-
542
- utils.concatBytes(Uint8Array.from([0xde, 0xad]), Uint8Array.from([0xbe, 0xef]));
543
- utils.nLength(255n);
544
- utils.equalBytes(Uint8Array.from([0xde]), Uint8Array.from([0xde]));
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);
545
646
  ```
546
647
 
547
648
  ## Security
@@ -666,8 +767,8 @@ init 10ms
666
767
  getPublicKey x 9,099 ops/sec @ 109μs/op
667
768
  sign x 7,182 ops/sec @ 139μs/op
668
769
  verify x 1,188 ops/sec @ 841μs/op
669
- getSharedSecret x 735 ops/sec @ 1ms/op
670
770
  recoverPublicKey x 1,265 ops/sec @ 790μs/op
771
+ getSharedSecret x 735 ops/sec @ 1ms/op
671
772
  schnorr.sign x 957 ops/sec @ 1ms/op
672
773
  schnorr.verify x 1,210 ops/sec @ 825μs/op
673
774
 
@@ -763,14 +864,82 @@ aggregateSignatures/2048 x 0 ops/sec @ 2823ms/op
763
864
 
764
865
  Supported node.js versions:
765
866
 
766
- - v2: v20.19+ (ESM-only)
767
- - v1: v14.21+ (ESM & CJS)
768
-
769
- ### curves v1 => curves v2
770
-
771
- WIP. Changelog of v2, when upgrading from curves v1.
772
-
773
- ### 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
774
943
 
775
944
  Previously, the library was split into single-feature packages
776
945
  [noble-secp256k1](https://github.com/paulmillr/noble-secp256k1),
@@ -778,7 +947,7 @@ Previously, the library was split into single-feature packages
778
947
  [noble-bls12-381](https://github.com/paulmillr/noble-bls12-381).
779
948
 
780
949
  Curves continue their original work. The single-feature packages changed their
781
- direction towards providing minimal 4kb implementations of cryptography,
950
+ direction towards providing minimal 5kb implementations of cryptography,
782
951
  which means they have less features.
783
952
 
784
953
  - `getPublicKey`
@@ -807,9 +976,9 @@ which means they have less features.
807
976
  - `utils` were split into `utils` (same api as in noble-curves) and
808
977
  `etc` (`hmacSha256Sync` and others)
809
978
 
810
- ### noble-ed25519 v1 => curves v1
979
+ ### noble-ed25519 v1 to curves v1
811
980
 
812
- Upgrading from [@noble/ed25519](https://github.com/paulmillr/noble-ed25519) 1.7:
981
+ Upgrading from [@noble/ed25519](https://github.com/paulmillr/noble-ed25519):
813
982
 
814
983
  - Methods are now sync by default
815
984
  - `bigint` is no longer allowed in `getPublicKey`, `sign`, `verify`. Reason: ed25519 is LE, can lead to bugs
@@ -820,7 +989,7 @@ Upgrading from [@noble/ed25519](https://github.com/paulmillr/noble-ed25519) 1.7:
820
989
  - `getSharedSecret` was moved to `x25519` module
821
990
  - `toX25519` has been moved to `edwardsToMontgomeryPub` and `edwardsToMontgomeryPriv` methods
822
991
 
823
- ### noble-bls12-381 => curves v1
992
+ ### noble-bls12-381 to curves v1
824
993
 
825
994
  Upgrading from [@noble/bls12-381](https://github.com/paulmillr/noble-bls12-381):
826
995