@noble/curves 1.8.1 → 1.8.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 (174) hide show
  1. package/README.md +278 -418
  2. package/_shortw_utils.d.ts +2 -2
  3. package/_shortw_utils.js +2 -2
  4. package/abstract/bls.d.ts +5 -5
  5. package/abstract/bls.d.ts.map +1 -1
  6. package/abstract/bls.js +14 -15
  7. package/abstract/bls.js.map +1 -1
  8. package/abstract/curve.d.ts +10 -2
  9. package/abstract/curve.d.ts.map +1 -1
  10. package/abstract/curve.js +81 -78
  11. package/abstract/curve.js.map +1 -1
  12. package/abstract/edwards.d.ts +2 -2
  13. package/abstract/edwards.d.ts.map +1 -1
  14. package/abstract/edwards.js +55 -69
  15. package/abstract/edwards.js.map +1 -1
  16. package/abstract/hash-to-curve.d.ts +5 -4
  17. package/abstract/hash-to-curve.d.ts.map +1 -1
  18. package/abstract/hash-to-curve.js +20 -18
  19. package/abstract/hash-to-curve.js.map +1 -1
  20. package/abstract/modular.d.ts.map +1 -1
  21. package/abstract/modular.js +9 -9
  22. package/abstract/montgomery.js +12 -12
  23. package/abstract/poseidon.d.ts +1 -1
  24. package/abstract/poseidon.js +3 -3
  25. package/abstract/tower.d.ts +2 -2
  26. package/abstract/tower.js +13 -13
  27. package/abstract/utils.d.ts +4 -2
  28. package/abstract/utils.d.ts.map +1 -1
  29. package/abstract/utils.js +25 -14
  30. package/abstract/utils.js.map +1 -1
  31. package/abstract/weierstrass.d.ts +17 -4
  32. package/abstract/weierstrass.d.ts.map +1 -1
  33. package/abstract/weierstrass.js +97 -80
  34. package/abstract/weierstrass.js.map +1 -1
  35. package/bls12-381.d.ts +1 -1
  36. package/bls12-381.js +41 -41
  37. package/bls12-381.js.map +1 -1
  38. package/bn254.d.ts +2 -2
  39. package/bn254.js +29 -29
  40. package/bn254.js.map +1 -1
  41. package/ed25519.d.ts +8 -6
  42. package/ed25519.d.ts.map +1 -1
  43. package/ed25519.js +65 -66
  44. package/ed25519.js.map +1 -1
  45. package/ed448.d.ts +6 -6
  46. package/ed448.d.ts.map +1 -1
  47. package/ed448.js +50 -52
  48. package/ed448.js.map +1 -1
  49. package/esm/_shortw_utils.d.ts +2 -2
  50. package/esm/_shortw_utils.js +1 -1
  51. package/esm/abstract/bls.d.ts +5 -5
  52. package/esm/abstract/bls.d.ts.map +1 -1
  53. package/esm/abstract/bls.js +5 -6
  54. package/esm/abstract/bls.js.map +1 -1
  55. package/esm/abstract/curve.d.ts +10 -2
  56. package/esm/abstract/curve.d.ts.map +1 -1
  57. package/esm/abstract/curve.js +77 -74
  58. package/esm/abstract/curve.js.map +1 -1
  59. package/esm/abstract/edwards.d.ts +2 -2
  60. package/esm/abstract/edwards.d.ts.map +1 -1
  61. package/esm/abstract/edwards.js +36 -50
  62. package/esm/abstract/edwards.js.map +1 -1
  63. package/esm/abstract/hash-to-curve.d.ts +5 -4
  64. package/esm/abstract/hash-to-curve.d.ts.map +1 -1
  65. package/esm/abstract/hash-to-curve.js +4 -2
  66. package/esm/abstract/hash-to-curve.js.map +1 -1
  67. package/esm/abstract/modular.d.ts.map +1 -1
  68. package/esm/abstract/modular.js +1 -1
  69. package/esm/abstract/montgomery.js +2 -2
  70. package/esm/abstract/poseidon.d.ts +1 -1
  71. package/esm/abstract/poseidon.js +1 -1
  72. package/esm/abstract/tower.d.ts +2 -2
  73. package/esm/abstract/tower.js +5 -5
  74. package/esm/abstract/utils.d.ts +4 -2
  75. package/esm/abstract/utils.d.ts.map +1 -1
  76. package/esm/abstract/utils.js +24 -13
  77. package/esm/abstract/utils.js.map +1 -1
  78. package/esm/abstract/weierstrass.d.ts +17 -4
  79. package/esm/abstract/weierstrass.d.ts.map +1 -1
  80. package/esm/abstract/weierstrass.js +70 -53
  81. package/esm/abstract/weierstrass.js.map +1 -1
  82. package/esm/bls12-381.d.ts +1 -1
  83. package/esm/bls12-381.js +9 -9
  84. package/esm/bls12-381.js.map +1 -1
  85. package/esm/bn254.d.ts +2 -2
  86. package/esm/bn254.js +7 -7
  87. package/esm/bn254.js.map +1 -1
  88. package/esm/ed25519.d.ts +8 -6
  89. package/esm/ed25519.d.ts.map +1 -1
  90. package/esm/ed25519.js +20 -21
  91. package/esm/ed25519.js.map +1 -1
  92. package/esm/ed448.d.ts +6 -6
  93. package/esm/ed448.d.ts.map +1 -1
  94. package/esm/ed448.js +13 -15
  95. package/esm/ed448.js.map +1 -1
  96. package/esm/jubjub.d.ts +1 -4
  97. package/esm/jubjub.d.ts.map +1 -1
  98. package/esm/jubjub.js +1 -60
  99. package/esm/jubjub.js.map +1 -1
  100. package/esm/misc.d.ts +15 -0
  101. package/esm/misc.d.ts.map +1 -0
  102. package/esm/misc.js +101 -0
  103. package/esm/misc.js.map +1 -0
  104. package/esm/p256.d.ts +8 -5
  105. package/esm/p256.d.ts.map +1 -1
  106. package/esm/p256.js +13 -12
  107. package/esm/p256.js.map +1 -1
  108. package/esm/p384.d.ts +8 -5
  109. package/esm/p384.d.ts.map +1 -1
  110. package/esm/p384.js +14 -15
  111. package/esm/p384.js.map +1 -1
  112. package/esm/p521.d.ts +6 -5
  113. package/esm/p521.d.ts.map +1 -1
  114. package/esm/p521.js +19 -28
  115. package/esm/p521.js.map +1 -1
  116. package/esm/pasta.d.ts +1 -7
  117. package/esm/pasta.d.ts.map +1 -1
  118. package/esm/pasta.js +1 -33
  119. package/esm/pasta.js.map +1 -1
  120. package/esm/secp256k1.d.ts +15 -10
  121. package/esm/secp256k1.d.ts.map +1 -1
  122. package/esm/secp256k1.js +18 -14
  123. package/esm/secp256k1.js.map +1 -1
  124. package/jubjub.d.ts +1 -4
  125. package/jubjub.d.ts.map +1 -1
  126. package/jubjub.js +5 -63
  127. package/jubjub.js.map +1 -1
  128. package/misc.d.ts +15 -0
  129. package/misc.d.ts.map +1 -0
  130. package/misc.js +106 -0
  131. package/misc.js.map +1 -0
  132. package/p256.d.ts +8 -5
  133. package/p256.d.ts.map +1 -1
  134. package/p256.js +19 -18
  135. package/p256.js.map +1 -1
  136. package/p384.d.ts +8 -5
  137. package/p384.d.ts.map +1 -1
  138. package/p384.js +19 -20
  139. package/p384.js.map +1 -1
  140. package/p521.d.ts +6 -5
  141. package/p521.d.ts.map +1 -1
  142. package/p521.js +23 -32
  143. package/p521.js.map +1 -1
  144. package/package.json +14 -10
  145. package/pasta.d.ts +1 -7
  146. package/pasta.d.ts.map +1 -1
  147. package/pasta.js +4 -34
  148. package/pasta.js.map +1 -1
  149. package/secp256k1.d.ts +15 -10
  150. package/secp256k1.d.ts.map +1 -1
  151. package/secp256k1.js +57 -53
  152. package/secp256k1.js.map +1 -1
  153. package/src/_shortw_utils.ts +2 -2
  154. package/src/abstract/bls.ts +9 -9
  155. package/src/abstract/curve.ts +88 -79
  156. package/src/abstract/edwards.ts +47 -54
  157. package/src/abstract/hash-to-curve.ts +7 -5
  158. package/src/abstract/modular.ts +1 -1
  159. package/src/abstract/montgomery.ts +2 -2
  160. package/src/abstract/poseidon.ts +1 -1
  161. package/src/abstract/tower.ts +6 -6
  162. package/src/abstract/utils.ts +26 -15
  163. package/src/abstract/weierstrass.ts +89 -75
  164. package/src/bls12-381.ts +10 -10
  165. package/src/bn254.ts +8 -8
  166. package/src/ed25519.ts +24 -22
  167. package/src/ed448.ts +18 -17
  168. package/src/jubjub.ts +5 -63
  169. package/src/misc.ts +117 -0
  170. package/src/p256.ts +13 -12
  171. package/src/p384.ts +18 -15
  172. package/src/p521.ts +27 -32
  173. package/src/pasta.ts +1 -39
  174. package/src/secp256k1.ts +19 -15
package/README.md CHANGED
@@ -40,40 +40,40 @@ Take a glance at [GitHub Discussions](https://github.com/paulmillr/noble-curves/
40
40
 
41
41
  > `deno add jsr:@noble/curves`
42
42
 
43
- > `deno doc jsr:@noble/curves` # command-line documentation
43
+ > `deno doc jsr:@noble/curves` # command-line documentation
44
44
 
45
45
  We support all major platforms and runtimes.
46
46
  For React Native, you may need a [polyfill for getRandomValues](https://github.com/LinusU/react-native-get-random-values).
47
47
  A standalone file [noble-curves.js](https://github.com/paulmillr/noble-curves/releases) is also available.
48
48
 
49
- ```js
49
+ ```ts
50
50
  // import * from '@noble/curves'; // Error: use sub-imports, to ensure small app size
51
- import { secp256k1 } from '@noble/curves/secp256k1'; // ESM and Common.js
52
- // import { secp256k1 } from 'npm:@noble/curves@1.6.0/secp256k1'; // Deno
51
+ import { secp256k1, schnorr } from '@noble/curves/secp256k1';
52
+ import { ed25519, ed25519ph, ed25519ctx, x25519 } from '@noble/curves/ed25519';
53
+ import { ed448, ed448ph, ed448ctx, x448 } from '@noble/curves/ed448';
54
+ import { p256 } from '@noble/curves/p256';
55
+ import { p384 } from '@noble/curves/p384';
56
+ import { p521 } from '@noble/curves/p521';
57
+ import { bls12_381 } from '@noble/curves/bls12-381';
58
+ import { bn254 } from '@noble/curves/bn254'; // also known as alt_bn128
59
+ import { jubjub, babyjubjub } from '@noble/curves/misc';
60
+ import { bytesToHex, hexToBytes, concatBytes, utf8ToBytes } from '@noble/curves/abstract/utils';
53
61
  ```
54
62
 
55
- - [Implementations](#implementations)
56
- - [ECDSA signatures over secp256k1 and others](#ecdsa-signatures-over-secp256k1-and-others)
57
- - [ECDSA public key recovery & extra entropy](#ecdsa-public-key-recovery--extra-entropy)
58
- - [ECDH: Elliptic Curve Diffie-Hellman](#ecdh-elliptic-curve-diffie-hellman)
59
- - [Schnorr signatures over secp256k1, BIP340](#schnorr-signatures-over-secp256k1-bip340)
60
- - [ed25519, X25519, ristretto255](#ed25519-x25519-ristretto255)
61
- - [ed448, X448, decaf448](#ed448-x448-decaf448)
62
- - [bls12-381](#bls12-381)
63
- - [bn254 aka alt_bn128](#bn254-aka-alt_bn128)
64
- - [Multi-scalar-multiplication](#multi-scalar-multiplication)
65
- - [Accessing a curve's variables](#accessing-a-curves-variables)
66
- - [All available imports](#all-available-imports)
63
+ - [ECDSA signatures over secp256k1 and others](#ecdsa-signatures-over-secp256k1-and-others)
64
+ - [Hedged ECDSA with noise](#hedged-ecdsa-with-noise)
65
+ - [ECDH: Diffie-Hellman shared secrets](#ecdh-diffie-hellman-shared-secrets)
66
+ - [secp256k1 Schnorr signatures from BIP340](#secp256k1-schnorr-signatures-from-bip340)
67
+ - [ed25519](#ed25519) / [X25519](#x25519) / [ristretto255](#ristretto255)
68
+ - [ed448](#ed448) / [X448](#x448) / [decaf448](#decaf448)
69
+ - [bls12-381](#bls12-381)
70
+ - [bn254 aka alt_bn128](#bn254-aka-alt_bn128)
71
+ - [misc curves](#misc-curves)
72
+ - [Low-level methods](#low-level-methods)
67
73
  - [Abstract API](#abstract-api)
68
- - [weierstrass: Short Weierstrass curve](#weierstrass-short-weierstrass-curve)
69
- - [edwards: Twisted Edwards curve](#edwards-twisted-edwards-curve)
70
- - [montgomery: Montgomery curve](#montgomery-montgomery-curve)
71
- - [bls: Barreto-Lynn-Scott curves](#bls-barreto-lynn-scott-curves)
72
- - [hash-to-curve: Hashing strings to curve points](#hash-to-curve-hashing-strings-to-curve-points)
73
- - [poseidon: Poseidon hash](#poseidon-poseidon-hash)
74
- - [modular: Modular arithmetics utilities](#modular-modular-arithmetics-utilities)
75
- - [Creating private keys from hashes](#creating-private-keys-from-hashes)
76
- - [utils: Useful utilities](#utils-useful-utilities)
74
+ - [weierstrass](#weierstrass-short-weierstrass-curve), [edwards](#edwards-twisted-edwards-curve), [montgomery](#montgomery-montgomery-curve), [bls](#bls-barreto-lynn-scott-curves)
75
+ - [hash-to-curve](#hash-to-curve-hashing-strings-to-curve-points), [poseidon](#poseidon-poseidon-hash)
76
+ - [modular](#modular-modular-arithmetics-utilities), [utils](#utils-useful-utilities)
77
77
  - [Security](#security)
78
78
  - [Speed](#speed)
79
79
  - [Upgrading](#upgrading)
@@ -82,9 +82,6 @@ import { secp256k1 } from '@noble/curves/secp256k1'; // ESM and Common.js
82
82
 
83
83
  ### Implementations
84
84
 
85
- Implementations use [noble-hashes](https://github.com/paulmillr/noble-hashes).
86
- If you want to use a different hashing library, [abstract API](#abstract-api) doesn't depend on them.
87
-
88
85
  #### ECDSA signatures over secp256k1 and others
89
86
 
90
87
  ```ts
@@ -100,31 +97,40 @@ const isValid = secp256k1.verify(sig, msg, pub) === true;
100
97
  // hex strings are also supported besides Uint8Array-s:
101
98
  const privHex = '46c930bc7bb4db7f55da20798697421b98c4175a52c630294d75a84b9c126236';
102
99
  const pub2 = secp256k1.getPublicKey(privHex);
100
+
101
+ // public key recovery
102
+ // let sig = secp256k1.Signature.fromCompact(sigHex); // or .fromDER(sigDERHex)
103
+ // sig = sig.addRecoveryBit(bit); // bit is not serialized into compact / der format
104
+ sig.recoverPublicKey(msg).toRawBytes(); // === pub; // public key recovery
103
105
  ```
104
106
 
105
107
  The same code would work for NIST P256 (secp256r1), P384 (secp384r1) & P521 (secp521r1).
106
108
 
107
- #### ECDSA public key recovery & extra entropy
109
+ #### Hedged ECDSA with noise
108
110
 
109
111
  ```ts
110
- // let sig = secp256k1.Signature.fromCompact(sigHex); // or .fromDER(sigDERHex)
111
- // sig = sig.addRecoveryBit(bit); // bit is not serialized into compact / der format
112
- sig.recoverPublicKey(msg).toRawBytes(); // === pub; // public key recovery
113
-
114
- // extraEntropy https://moderncrypto.org/mail-archive/curves/2017/000925.html
115
- const sigImprovedSecurity = secp256k1.sign(msg, priv, { extraEntropy: true });
112
+ const noisySignature = secp256k1.sign(msg, priv, { extraEntropy: true });
113
+ const ent = new Uint8Array(32).fill(3); // set custom entropy
114
+ const noisySignature2 = secp256k1.sign(msg, priv, { extraEntropy: ent });
116
115
  ```
117
116
 
118
- #### ECDH: Elliptic Curve Diffie-Hellman
117
+ Hedged ECDSA is add-on, providing improved protection against fault attacks.
118
+ It adds noise to signatures. The technique is used by default in BIP340; we also implement them
119
+ optionally for ECDSA. Check out blog post
120
+ [Deterministic signatures are not your friends](https://paulmillr.com/posts/deterministic-signatures/)
121
+ and [spec draft](https://datatracker.ietf.org/doc/draft-irtf-cfrg-det-sigs-with-noise/).
122
+
123
+ #### ECDH: Diffie-Hellman shared secrets
119
124
 
120
125
  ```ts
121
- // 1. The output includes parity byte. Strip it using shared.slice(1)
122
- // 2. The output is not hashed. More secure way is sha256(shared) or hkdf(shared)
123
126
  const someonesPub = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
124
127
  const shared = secp256k1.getSharedSecret(priv, someonesPub);
128
+ // NOTE:
129
+ // - `shared` includes parity byte: strip it using shared.slice(1)
130
+ // - `shared` is not hashed: more secure way is sha256(shared) or hkdf(shared)
125
131
  ```
126
132
 
127
- #### Schnorr signatures over secp256k1 (BIP340)
133
+ #### secp256k1 Schnorr signatures from BIP340
128
134
 
129
135
  ```ts
130
136
  import { schnorr } from '@noble/curves/secp256k1';
@@ -135,7 +141,7 @@ const sig = schnorr.sign(msg, priv);
135
141
  const isValid = schnorr.verify(sig, msg, pub);
136
142
  ```
137
143
 
138
- #### ed25519, X25519, ristretto255
144
+ #### ed25519
139
145
 
140
146
  ```ts
141
147
  import { ed25519 } from '@noble/curves/ed25519';
@@ -144,23 +150,22 @@ const pub = ed25519.getPublicKey(priv);
144
150
  const msg = new TextEncoder().encode('hello');
145
151
  const sig = ed25519.sign(msg, priv);
146
152
  ed25519.verify(sig, msg, pub); // Default mode: follows ZIP215
147
- ed25519.verify(sig, msg, pub, { zip215: false }); // RFC8032 / FIPS 186-5
153
+ ed25519.verify(sig, msg, pub, { zip215: false }); // SBS / e-voting / RFC8032 / FIPS 186-5
154
+
155
+ // Variants from RFC8032: with context, prehashed
156
+ import { ed25519ctx, ed25519ph } from '@noble/curves/ed25519';
148
157
  ```
149
158
 
150
- Default `verify` behavior follows [ZIP215](https://zips.z.cash/zip-0215) and
151
- [can be used in consensus-critical applications](https://hdevalence.ca/blog/2020-10-04-its-25519am).
152
- It has SUF-CMA (strong unforgeability under chosen message attacks).
153
- `zip215: false` option switches verification criteria to strict
154
- [RFC8032](https://www.rfc-editor.org/rfc/rfc8032) / [FIPS 186-5](https://csrc.nist.gov/publications/detail/fips/186/5/final)
155
- and additionally provides [non-repudiation with SBS](#edwards-twisted-edwards-curve).
159
+ Default `verify` behavior follows ZIP215 and
160
+ can be used in consensus-critical applications.
161
+ If you need SBS (Strongly Binding Signatures) and FIPS 186-5 compliance,
162
+ use `zip215: false`. Check out [Edwards Signatures section for more info](#edwards-twisted-edwards-curve).
163
+ Both options have SUF-CMA (strong unforgeability under chosen message attacks).
156
164
 
157
- X25519 follows [RFC7748](https://www.rfc-editor.org/rfc/rfc7748).
165
+ #### X25519
158
166
 
159
167
  ```ts
160
- // Variants from RFC8032: with context, prehashed
161
- import { ed25519ctx, ed25519ph } from '@noble/curves/ed25519';
162
-
163
- // ECDH using curve25519 aka x25519
168
+ // X25519 aka ECDH on Curve25519 from [RFC7748](https://www.rfc-editor.org/rfc/rfc7748)
164
169
  import { x25519 } from '@noble/curves/ed25519';
165
170
  const priv = 'a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4';
166
171
  const pub = 'e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c';
@@ -174,10 +179,10 @@ edwardsToMontgomeryPub(ed25519.getPublicKey(ed25519.utils.randomPrivateKey()));
174
179
  edwardsToMontgomeryPriv(ed25519.utils.randomPrivateKey());
175
180
  ```
176
181
 
177
- ristretto255 follows [irtf draft](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448).
182
+ #### ristretto255
178
183
 
179
184
  ```ts
180
- // hash-to-curve, ristretto255
185
+ // ristretto255 from [RFC9496](https://www.rfc-editor.org/rfc/rfc9496)
181
186
  import { utf8ToBytes } from '@noble/hashes/utils';
182
187
  import { sha512 } from '@noble/hashes/sha512';
183
188
  import {
@@ -201,7 +206,7 @@ RistrettoPoint.hashToCurve(sha512(msg));
201
206
  hashToRistretto255(msg, { DST: 'ristretto255_XMD:SHA-512_R255MAP_RO_' });
202
207
  ```
203
208
 
204
- #### ed448, X448, decaf448
209
+ #### ed448
205
210
 
206
211
  ```ts
207
212
  import { ed448 } from '@noble/curves/ed448';
@@ -215,9 +220,10 @@ ed448.verify(sig, msg, pub);
215
220
  import { ed448ph } from '@noble/curves/ed448';
216
221
  ```
217
222
 
218
- ECDH using Curve448 aka X448, follows [RFC7748](https://www.rfc-editor.org/rfc/rfc7748).
223
+ #### X448
219
224
 
220
225
  ```ts
226
+ // X448 aka ECDH on Curve448 from [RFC7748](https://www.rfc-editor.org/rfc/rfc7748)
221
227
  import { x448 } from '@noble/curves/ed448';
222
228
  x448.getSharedSecret(priv, pub) === x448.scalarMult(priv, pub); // aliases
223
229
  x448.getPublicKey(priv) === x448.scalarMultBase(priv);
@@ -227,9 +233,10 @@ import { edwardsToMontgomeryPub } from '@noble/curves/ed448';
227
233
  edwardsToMontgomeryPub(ed448.getPublicKey(ed448.utils.randomPrivateKey()));
228
234
  ```
229
235
 
230
- decaf448 follows [irtf draft](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448).
236
+ #### decaf448
231
237
 
232
238
  ```ts
239
+ // decaf448 from [RFC9496](https://www.rfc-editor.org/rfc/rfc9496)
233
240
  import { utf8ToBytes } from '@noble/hashes/utils';
234
241
  import { shake256 } from '@noble/hashes/sha3';
235
242
  import { hashToCurve, encodeToCurve, DecafPoint, hashToDecaf448 } from '@noble/curves/ed448';
@@ -248,8 +255,6 @@ DecafPoint.hashToCurve(shake256(msg, { dkLen: 112 }));
248
255
  hashToDecaf448(msg, { DST: 'decaf448_XOF:SHAKE256_D448MAP_RO_' });
249
256
  ```
250
257
 
251
- Same RFC7748 / RFC8032 / IRTF draft are followed.
252
-
253
258
  #### bls12-381
254
259
 
255
260
  ```ts
@@ -275,7 +280,10 @@ const signatureEth = bls.sign(message, privateKey, htfEthereum);
275
280
  const isValidEth = bls.verify(signature, message, publicKey, htfEthereum);
276
281
 
277
282
  // Aggregation
278
- const aggregatedKey = bls.aggregatePublicKeys([bls.utils.randomPrivateKey(), bls.utils.randomPrivateKey()])
283
+ const aggregatedKey = bls.aggregatePublicKeys([
284
+ bls.utils.randomPrivateKey(),
285
+ bls.utils.randomPrivateKey(),
286
+ ]);
279
287
  // const aggregatedSig = bls.aggregateSignatures(sigs)
280
288
 
281
289
  // Pairings, with and without final exponentiation
@@ -296,11 +304,7 @@ For example usage, check out [the implementation of BLS EVM precompiles](https:/
296
304
  ```ts
297
305
  import { bn254 } from '@noble/curves/bn254';
298
306
 
299
- console.log(
300
- bn254.G1,
301
- bn254.G2,
302
- bn254.pairing
303
- )
307
+ console.log(bn254.G1, bn254.G2, bn254.pairing);
304
308
  ```
305
309
 
306
310
  The API mirrors [BLS](#bls12-381). The curve was previously called alt_bn128.
@@ -316,49 +320,43 @@ different implementations of bn254 do it differently - there is no standard. Poi
316
320
 
317
321
  For example usage, check out [the implementation of bn254 EVM precompiles](https://github.com/paulmillr/noble-curves/blob/3ed792f8ad9932765b84d1064afea8663a255457/test/bn254.test.js#L697).
318
322
 
319
- #### Multi-scalar-multiplication
323
+ #### misc curves
320
324
 
321
325
  ```ts
322
- import { secp256k1 } from '@noble/curves/secp256k1';
323
- const p = secp256k1.ProjectivePoint;
324
- const points = [p.BASE, p.BASE.multiply(2n), p.BASE.multiply(4n), p.BASE.multiply(8n)];
325
- p.msm(points, [3n, 5n, 7n, 11n]).equals(p.BASE.multiply(129n)); // 129*G
326
+ import { jubjub, babyjubjub } from '@noble/curves/misc';
326
327
  ```
327
328
 
328
- Pippenger algorithm is used underneath.
329
- Multi-scalar-multiplication (MSM) is basically `(Pa + Qb + Rc + ...)`.
330
- It's 10-30x faster vs naive addition for large amount of points.
329
+ Miscellaneous, rarely used curves are contained in the module.
330
+ Jubjub curves have Fp over scalar fields of other curves. They are friendly to ZK proofs.
331
+ jubjub Fp = bls n. babyjubjub Fp = bn254 n.
331
332
 
332
- #### Accessing a curve's variables
333
+ #### Low-level methods
333
334
 
334
335
  ```ts
335
336
  import { secp256k1 } from '@noble/curves/secp256k1';
337
+
338
+ // Curve's variables
336
339
  // Every curve has `CURVE` object that contains its parameters, field, and others
337
340
  console.log(secp256k1.CURVE.p); // field modulus
338
341
  console.log(secp256k1.CURVE.n); // curve order
339
342
  console.log(secp256k1.CURVE.a, secp256k1.CURVE.b); // equation params
340
343
  console.log(secp256k1.CURVE.Gx, secp256k1.CURVE.Gy); // base point coordinates
341
- ```
342
-
343
344
 
344
- #### All available imports
345
-
346
- ```typescript
347
- import { secp256k1, schnorr } from '@noble/curves/secp256k1';
348
- import { ed25519, ed25519ph, ed25519ctx, x25519, RistrettoPoint } from '@noble/curves/ed25519';
349
- import { ed448, ed448ph, ed448ctx, x448 } from '@noble/curves/ed448';
350
- import { p256 } from '@noble/curves/p256';
351
- import { p384 } from '@noble/curves/p384';
352
- import { p521 } from '@noble/curves/p521';
353
- import { pallas, vesta } from '@noble/curves/pasta';
354
- import { bls12_381 } from '@noble/curves/bls12-381';
355
- import { bn254 } from '@noble/curves/bn254'; // also known as alt_bn128
356
- import { jubjub } from '@noble/curves/jubjub';
357
- import { bytesToHex, hexToBytes, concatBytes, utf8ToBytes } from '@noble/curves/abstract/utils';
345
+ // MSM
346
+ const p = secp256k1.ProjectivePoint;
347
+ const points = [p.BASE, p.BASE.multiply(2n), p.BASE.multiply(4n), p.BASE.multiply(8n)];
348
+ p.msm(points, [3n, 5n, 7n, 11n]).equals(p.BASE.multiply(129n)); // 129*G
358
349
  ```
359
350
 
351
+ Multi-scalar-multiplication (MSM) is basically `(Pa + Qb + Rc + ...)`.
352
+ It's 10-30x faster vs naive addition for large amount of points.
353
+ Pippenger algorithm is used underneath.
354
+
360
355
  ## Abstract API
361
356
 
357
+ Implementations use [noble-hashes](https://github.com/paulmillr/noble-hashes).
358
+ If you want to use a different hashing library, abstract API doesn't depend on them.
359
+
362
360
  Abstract API allows to define custom curves. All arithmetics is done with JS
363
361
  bigints over finite fields, which is defined from `modular` sub-module. For
364
362
  scalar multiplication, we use
@@ -371,171 +369,69 @@ method: check out examples.
371
369
 
372
370
  ```ts
373
371
  import { weierstrass } from '@noble/curves/abstract/weierstrass';
374
- import { Field } from '@noble/curves/abstract/modular'; // finite field for mod arithmetics
375
- import { sha256 } from '@noble/hashes/sha256'; // 3rd-party sha256() of type utils.CHash
376
- import { hmac } from '@noble/hashes/hmac'; // 3rd-party hmac() that will accept sha256()
377
- import { concatBytes, randomBytes } from '@noble/hashes/utils'; // 3rd-party utilities
372
+ import { Field } from '@noble/curves/abstract/modular';
373
+ import { sha256 } from '@noble/hashes/sha256';
374
+ import { hmac } from '@noble/hashes/hmac';
375
+ import { concatBytes, randomBytes } from '@noble/hashes/utils';
378
376
 
379
- const hmacSha256 = (key: Uint8Array, ...msgs: Uint8Array[]) => hmac(sha256, key, concatBytes(...msgs));
377
+ const hmacSha256 = (key: Uint8Array, ...msgs: Uint8Array[]) =>
378
+ hmac(sha256, key, concatBytes(...msgs));
380
379
 
381
- // secq256k1: cycle of secp256k1 with Fp/N flipped.
380
+ // secQ (not secP) - secq256k1 is a cycle of secp256k1 with Fp/N flipped.
382
381
  // https://personaelabs.org/posts/spartan-ecdsa
383
382
  // https://zcash.github.io/halo2/background/curves.html#cycles-of-curves
384
383
  const secq256k1 = weierstrass({
385
- // Curve equation params a, b
386
384
  a: 0n,
387
385
  b: 7n,
388
- // Field over which we'll do calculations
389
386
  Fp: Field(2n ** 256n - 432420386565659656852420866394968145599n),
390
- // Curve order, total count of valid points in the field.
391
387
  n: 2n ** 256n - 2n ** 32n - 2n ** 9n - 2n ** 8n - 2n ** 7n - 2n ** 6n - 2n ** 4n - 1n,
392
- // Base point (x, y) aka generator point
393
388
  Gx: 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
394
389
  Gy: 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
395
-
396
390
  hash: sha256,
397
391
  hmac: hmacSha256,
398
392
  randomBytes,
399
393
  });
400
394
 
401
- // NIST secp192r1 aka p192 https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/secg/secp192r1
395
+ // NIST secp192r1 aka p192
396
+ // https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/secg/secp192r1
402
397
  const secp192r1 = weierstrass({
403
- a: BigInt('0xfffffffffffffffffffffffffffffffefffffffffffffffc'),
404
- b: BigInt('0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1'),
405
- Fp: Field(BigInt('0xfffffffffffffffffffffffffffffffeffffffffffffffff')),
406
- n: BigInt('0xffffffffffffffffffffffff99def836146bc9b1b4d22831'),
407
- Gx: BigInt('0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012'),
408
- Gy: BigInt('0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811'),
409
- h: BigInt(1),
398
+ a: 0xfffffffffffffffffffffffffffffffefffffffffffffffcn,
399
+ b: 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1n,
400
+ Fp: Field(0xfffffffffffffffffffffffffffffffeffffffffffffffffn),
401
+ n: 0xffffffffffffffffffffffff99def836146bc9b1b4d22831n,
402
+ Gx: 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012n,
403
+ Gy: 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811n,
410
404
  hash: sha256,
411
405
  hmac: hmacSha256,
412
406
  randomBytes,
413
407
  });
414
-
415
-
416
- // Replace weierstrass() with weierstrassPoints() if you don't need ECDSA, hash, hmac, randomBytes
417
408
  ```
418
409
 
419
410
  Short Weierstrass curve's formula is `y² = x³ + ax + b`. `weierstrass`
420
411
  expects arguments `a`, `b`, field `Fp`, curve order `n`, cofactor `h`
421
412
  and coordinates `Gx`, `Gy` of generator point.
422
-
423
- **`k` generation** is done deterministically, following
424
- [RFC6979](https://www.rfc-editor.org/rfc/rfc6979). It is suggested to use `extraEntropy`
425
- option, which incorporates randomness into signatures to increase their security.
426
-
427
- For k generation, specifying `hmac` & `hash` is required,
428
- which in our implementations is done by noble-hashes. If
429
- you're using different hashing library, make sure to wrap it in the following interface:
430
-
431
- ```ts
432
- type CHash = {
433
- (message: Uint8Array): Uint8Array;
434
- blockLen: number;
435
- outputLen: number;
436
- create(): any;
437
- };
438
-
439
- // example
440
- function sha256(message: Uint8Array) {
441
- return _internal_lowlvl(message);
442
- }
443
- sha256.outputLen = 32; // 32 bytes of output for sha2-256
444
- ```
445
-
446
- **Message hash** is expected instead of message itself:
447
-
448
- - `sign(msgHash, privKey)` is default behavior, assuming you pre-hash msg with sha2, or other hash
449
- - `sign(msg, privKey, {prehash: true})` option can be used if you want to pass the message itself
413
+ `hmac` and `hash` must be specified for deterministic `k` generation.
450
414
 
451
415
  **Weierstrass points:**
452
416
 
453
- 1. Exported as `ProjectivePoint`
454
- 2. Represented in projective (homogeneous) coordinates: (x, y, z) ∋ (x=x/z, y=y/z)
455
- 3. Use complete exception-free formulas for addition and doubling
456
- 4. Can be decoded/encoded from/to Uint8Array / hex strings using
457
- `ProjectivePoint.fromHex` and `ProjectivePoint#toRawBytes()`
458
- 5. Have `assertValidity()` which checks for being on-curve
459
- 6. Have `toAffine()` and `x` / `y` getters which convert to 2d xy affine coordinates
460
-
461
- ```ts
462
- // `weierstrassPoints()` returns `CURVE` and `ProjectivePoint`
463
- // `weierstrass()` returns `CurveFn`
464
- type SignOpts = { lowS?: boolean; prehash?: boolean; extraEntropy: boolean | Uint8Array };
465
- type CurveFn = {
466
- CURVE: ReturnType<typeof validateOpts>;
467
- getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
468
- getSharedSecret: (privateA: PrivKey, publicB: Hex, isCompressed?: boolean) => Uint8Array;
469
- sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) => SignatureType;
470
- verify: (
471
- signature: Hex | SignatureType,
472
- msgHash: Hex,
473
- publicKey: Hex,
474
- opts?: { lowS?: boolean; prehash?: boolean; format?: 'compact' | 'der' }
475
- ) => boolean;
476
- ProjectivePoint: ProjectivePointConstructor;
477
- Signature: SignatureConstructor;
478
- utils: {
479
- normPrivateKeyToScalar: (key: PrivKey) => bigint;
480
- isValidPrivateKey(key: PrivKey): boolean;
481
- randomPrivateKey: () => Uint8Array;
482
- precompute: (windowSize?: number, point?: ProjPointType<bigint>) => ProjPointType<bigint>;
483
- };
484
- };
485
-
486
- // T is usually bigint, but can be something else like complex numbers in BLS curves
487
- interface ProjPointType<T> extends Group<ProjPointType<T>> {
488
- readonly px: T;
489
- readonly py: T;
490
- readonly pz: T;
491
- get x(): bigint;
492
- get y(): bigint;
493
- multiply(scalar: bigint): ProjPointType<T>;
494
- multiplyUnsafe(scalar: bigint): ProjPointType<T>;
495
- multiplyAndAddUnsafe(Q: ProjPointType<T>, a: bigint, b: bigint): ProjPointType<T> | undefined;
496
- toAffine(iz?: T): AffinePoint<T>;
497
- isTorsionFree(): boolean;
498
- clearCofactor(): ProjPointType<T>;
499
- assertValidity(): void;
500
- hasEvenY(): boolean;
501
- toRawBytes(isCompressed?: boolean): Uint8Array;
502
- toHex(isCompressed?: boolean): string;
503
- }
504
- // Static methods for 3d XYZ points
505
- interface ProjConstructor<T> extends GroupConstructor<ProjPointType<T>> {
506
- new (x: T, y: T, z: T): ProjPointType<T>;
507
- fromAffine(p: AffinePoint<T>): ProjPointType<T>;
508
- fromHex(hex: Hex): ProjPointType<T>;
509
- fromPrivateKey(privateKey: PrivKey): ProjPointType<T>;
510
- msm(points: ProjPointType[], scalars: bigint[]): ProjPointType<T>;
511
- }
512
- ```
513
-
514
- **ECDSA signatures** are represented by `Signature` instances and can be
515
- described by the interface:
516
-
517
- ```ts
518
- interface SignatureType {
519
- readonly r: bigint;
520
- readonly s: bigint;
521
- readonly recovery?: number;
522
- assertValidity(): void;
523
- addRecoveryBit(recovery: number): SignatureType;
524
- hasHighS(): boolean;
525
- normalizeS(): SignatureType;
526
- recoverPublicKey(msgHash: Hex): ProjPointType<bigint>;
527
- toCompactRawBytes(): Uint8Array;
528
- toCompactHex(): string;
529
- // DER-encoded
530
- toDERRawBytes(): Uint8Array;
531
- toDERHex(): string;
532
- }
533
- type SignatureConstructor = {
534
- new (r: bigint, s: bigint): SignatureType;
535
- fromCompact(hex: Hex): SignatureType;
536
- fromDER(hex: Hex): SignatureType;
537
- };
538
- ```
417
+ - Are exported as `ProjectivePoint`
418
+ - Are represented in projective (homogeneous) coordinates: (x, y, z) ∋ (x=x/z, y=y/z)
419
+ - Use complete exception-free formulas for addition and doubling
420
+ - Can be decoded/encoded from/to Uint8Array / hex strings using
421
+ `ProjectivePoint.fromHex` and `ProjectivePoint#toRawBytes()`
422
+ - Have `assertValidity()` which checks for being on-curve
423
+ - Have `toAffine()` and `x` / `y` getters which convert to 2d xy affine coordinates
424
+
425
+ **ECDSA signatures:**
426
+
427
+ - Are represented by `Signature` instances with `r, s` and optional `recovery` properties
428
+ - Have `recoverPublicKey()`, `toCompactRawBytes()` and `toDERRawBytes()` methods
429
+ - Can be prehashed, or non-prehashed:
430
+ - `sign(msgHash, privKey)` (default, prehash: false) - you did hashing before
431
+ - `sign(msg, privKey, {prehash: true})` - curves will do hashing for you
432
+ - Are generated deterministically, following [RFC6979](https://www.rfc-editor.org/rfc/rfc6979).
433
+ - Consider [hedged ECDSA with noise](#hedged-ecdsa-with-noise) for adding randomness into
434
+ for signatures, to get improved security against fault attacks.
539
435
 
540
436
  More examples:
541
437
 
@@ -599,101 +495,43 @@ const ed25519 = twistedEdwards({
599
495
  } as const);
600
496
  ```
601
497
 
602
- Twisted Edwards curve's formula is `ax² + y² = 1 + dx²y²`. You must specify `a`, `d`, field `Fp`, order `n`, cofactor `h`
498
+ Twisted Edwards curve's formula is `ax² + y² = 1 + dx²y²`.
499
+ You must specify `a`, `d`, field `Fp`, order `n`, cofactor `h`
603
500
  and coordinates `Gx`, `Gy` of generator point.
604
-
605
- For EdDSA signatures, `hash` param required. `adjustScalarBytes` which instructs how to change private scalars could be specified.
606
-
607
- We support [non-repudiation](https://eprint.iacr.org/2020/1244), which help in following scenarios:
608
-
609
- - Contract Signing: if A signed an agreement with B using key that allows repudiation, it can later claim that it signed a different contract
610
- - E-voting: malicious voters may pick keys that allow repudiation in order to deny results
611
- - Blockchains: transaction of amount X might also be valid for a different amount Y
501
+ For EdDSA signatures, `hash` param required.
502
+ `adjustScalarBytes` which instructs how to change private scalars could be specified.
612
503
 
613
504
  **Edwards points:**
614
505
 
615
- 1. Exported as `ExtendedPoint`
616
- 2. Represented in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z)
617
- 3. Use complete exception-free formulas for addition and doubling
618
- 4. Can be decoded/encoded from/to Uint8Array / hex strings using `ExtendedPoint.fromHex` and `ExtendedPoint#toRawBytes()`
619
- 5. Have `assertValidity()` which checks for being on-curve
620
- 6. Have `toAffine()` and `x` / `y` getters which convert to 2d xy affine coordinates
621
- 7. Have `isTorsionFree()`, `clearCofactor()` and `isSmallOrder()` utilities to handle torsions
622
-
623
- ```ts
624
- // `twistedEdwards()` returns `CurveFn` of following type:
625
- type CurveFn = {
626
- CURVE: ReturnType<typeof validateOpts>;
627
- getPublicKey: (privateKey: Hex) => Uint8Array;
628
- sign: (message: Hex, privateKey: Hex, context?: Hex) => Uint8Array;
629
- verify: (sig: SigType, message: Hex, publicKey: Hex, context?: Hex) => boolean;
630
- ExtendedPoint: ExtPointConstructor;
631
- utils: {
632
- randomPrivateKey: () => Uint8Array;
633
- getExtendedPublicKey: (key: PrivKey) => {
634
- head: Uint8Array;
635
- prefix: Uint8Array;
636
- scalar: bigint;
637
- point: PointType;
638
- pointBytes: Uint8Array;
639
- };
640
- };
641
- };
642
-
643
- interface ExtPointType extends Group<ExtPointType> {
644
- readonly ex: bigint;
645
- readonly ey: bigint;
646
- readonly ez: bigint;
647
- readonly et: bigint;
648
- get x(): bigint;
649
- get y(): bigint;
650
- assertValidity(): void;
651
- multiply(scalar: bigint): ExtPointType;
652
- multiplyUnsafe(scalar: bigint): ExtPointType;
653
- isSmallOrder(): boolean;
654
- isTorsionFree(): boolean;
655
- clearCofactor(): ExtPointType;
656
- toAffine(iz?: bigint): AffinePoint<bigint>;
657
- toRawBytes(isCompressed?: boolean): Uint8Array;
658
- toHex(isCompressed?: boolean): string;
659
- }
660
- // Static methods of Extended Point with coordinates in X, Y, Z, T
661
- interface ExtPointConstructor extends GroupConstructor<ExtPointType> {
662
- new (x: bigint, y: bigint, z: bigint, t: bigint): ExtPointType;
663
- fromAffine(p: AffinePoint<bigint>): ExtPointType;
664
- fromHex(hex: Hex): ExtPointType;
665
- fromPrivateKey(privateKey: Hex): ExtPointType;
666
- msm(points: ExtPointType[], scalars: bigint[]): ExtPointType;
667
- }
668
- ```
506
+ - Are exported as `ExtendedPoint`
507
+ - Are represented in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z)
508
+ - Use complete exception-free formulas for addition and doubling
509
+ - Can be decoded/encoded from/to Uint8Array / hex strings using `ExtendedPoint.fromHex` and `ExtendedPoint#toRawBytes()`
510
+ - Have `assertValidity()` which checks for being on-curve
511
+ - Have `toAffine()` and `x` / `y` getters which convert to 2d xy affine coordinates
512
+ - Have `isTorsionFree()`, `clearCofactor()` and `isSmallOrder()` utilities to handle torsions
513
+
514
+ **EdDSA signatures:**
515
+
516
+ - `zip215: true` is default behavior. It has slightly looser verification logic
517
+ to be [consensus-friendly](https://hdevalence.ca/blog/2020-10-04-its-25519am), following [ZIP215](https://zips.z.cash/zip-0215) rules
518
+ - `zip215: false` switches verification criteria to strict
519
+ [RFC8032](https://www.rfc-editor.org/rfc/rfc8032) / [FIPS 186-5](https://csrc.nist.gov/publications/detail/fips/186/5/final)
520
+ and additionally provides [non-repudiation with SBS](https://eprint.iacr.org/2020/1244),
521
+ which is useful for:
522
+ - Contract Signing: if A signed an agreement with B using key that allows repudiation, it can later claim that it signed a different contract
523
+ - E-voting: malicious voters may pick keys that allow repudiation in order to deny results
524
+ - Blockchains: transaction of amount X might also be valid for a different amount Y
525
+ - Both modes have SUF-CMA (strong unforgeability under chosen message attacks).
526
+
527
+ Check out [RFC9496](https://datatracker.ietf.org/doc/html/rfc9496) for description of
528
+ ristretto and decaf groups which we implement.
669
529
 
670
530
  ### montgomery: Montgomery curve
671
531
 
672
- ```typescript
673
- import { montgomery } from '@noble/curves/abstract/montgomery';
674
- import { Field } from '@noble/curves/abstract/modular';
675
-
676
- const x25519 = montgomery({
677
- a: 486662n,
678
- Gu: 9n,
679
- P: 2n ** 255n - 19n,
680
- montgomeryBits: 255,
681
- nByteLength: 32,
682
- // Optional param
683
- adjustScalarBytes(bytes) {
684
- bytes[0] &= 248;
685
- bytes[31] &= 127;
686
- bytes[31] |= 64;
687
- return bytes;
688
- },
689
- });
690
- ```
691
-
692
532
  The module contains methods for x-only ECDH on Curve25519 / Curve448 from RFC7748.
693
533
  Proper Elliptic Curve Points are not implemented yet.
694
534
 
695
- You must specify curve params `Fp`, `a`, `Gu` coordinate of u, `montgomeryBits` and `nByteLength`.
696
-
697
535
  ### bls: Barreto-Lynn-Scott curves
698
536
 
699
537
  The module abstracts BLS (Barreto-Lynn-Scott) pairing-friendly elliptic curve construction.
@@ -889,33 +727,37 @@ The library has been independently audited:
889
727
  - The audit has been funded by [Ryan Shea](https://www.shea.io)
890
728
 
891
729
  It is tested against property-based, cross-library and Wycheproof vectors,
892
- and has fuzzing by [Guido Vranken's cryptofuzz](https://github.com/guidovranken/cryptofuzz).
730
+ and is being fuzzed in [the separate repo](https://github.com/paulmillr/fuzzing).
893
731
 
894
732
  If you see anything unusual: investigate and report.
895
733
 
896
734
  ### Constant-timeness
897
735
 
898
- _JIT-compiler_ and _Garbage Collector_ make "constant time" extremely hard to
899
- achieve [timing attack](https://en.wikipedia.org/wiki/Timing_attack) resistance
736
+ We're targetting algorithmic constant time. _JIT-compiler_ and _Garbage Collector_ make "constant time"
737
+ extremely hard to achieve [timing attack](https://en.wikipedia.org/wiki/Timing_attack) resistance
900
738
  in a scripting language. Which means _any other JS library can't have
901
739
  constant-timeness_. Even statically typed Rust, a language without GC,
902
740
  [makes it harder to achieve constant-time](https://www.chosenplaintext.ca/open-source/rust-timing-shield/security)
903
741
  for some cases. If your goal is absolute security, don't use any JS lib — including bindings to native ones.
904
- Use low-level libraries & languages. Nonetheless we're targetting algorithmic constant time.
742
+ Use low-level libraries & languages.
905
743
 
906
744
  ### Supply chain security
907
745
 
908
- - **Commits** are signed with PGP keys, to prevent forgery. Make sure to verify commit signatures.
746
+ - **Commits** are signed with PGP keys, to prevent forgery. Make sure to verify commit signatures
909
747
  - **Releases** are transparent and built on GitHub CI. Make sure to verify [provenance](https://docs.npmjs.com/generating-provenance-statements) logs
748
+ - Use GitHub CLI to verify single-file builds:
749
+ `gh attestation verify --owner paulmillr noble-curves.js`
910
750
  - **Rare releasing** is followed to ensure less re-audit need for end-users
911
- - **Dependencies** are minimized and locked-down:
912
- - If your app has 500 dependencies, any dep could get hacked and you'll be downloading
913
- malware with every install. We make sure to use as few dependencies as possible
914
- - We prevent automatic dependency updates by locking-down version ranges. Every update is checked with `npm-diff`
915
- - One dependency [noble-hashes](https://github.com/paulmillr/noble-hashes) is used, by the same author, to provide hashing functionality
916
- - **Dev Dependencies** are only used if you want to contribute to the repo. They are disabled for end-users:
917
- - scure-base, scure-bip32, scure-bip39, micro-bmark and micro-should are developed by the same author and follow identical security practices
918
- - prettier (linter), fast-check (property-based testing) and typescript are used for code quality, vector generation and ts compilation. The packages are big, which makes it hard to audit their source code thoroughly and fully
751
+ - **Dependencies** are minimized and locked-down: any dependency could get hacked and users will be downloading malware with every install.
752
+ - We make sure to use as few dependencies as possible
753
+ - Automatic dep updates are prevented by locking-down version ranges; diffs are checked with `npm-diff`
754
+ - **Dev Dependencies** are disabled for end-users; they are only used to develop / build the source code
755
+
756
+ For this package, there is 1 dependency; and a few dev dependencies:
757
+
758
+ - [noble-hashes](https://github.com/paulmillr/noble-hashes) provides cryptographic hashing functionality
759
+ - micro-bmark, micro-should and jsbt are used for benchmarking / testing / build tooling and developed by the same author
760
+ - prettier, fast-check and typescript are used for code quality / test generation / ts compilation. It's hard to audit their source code thoroughly and fully because of their size
919
761
 
920
762
  ### Randomness
921
763
 
@@ -939,96 +781,114 @@ NIST prohibits classical cryptography (RSA, DSA, ECDSA, ECDH) [after 2035](https
939
781
 
940
782
  ## Speed
941
783
 
942
- Benchmark results on Apple M2 with node v22:
943
-
944
- ```
945
- secp256k1
946
- init x 68 ops/sec @ 14ms/op
947
- getPublicKey x 6,839 ops/sec @ 146μs/op
948
- sign x 5,226 ops/sec @ 191μs/op
949
- verify x 893 ops/sec @ 1ms/op
950
- getSharedSecret x 538 ops/sec @ 1ms/op
951
- recoverPublicKey x 923 ops/sec @ 1ms/op
952
- schnorr.sign x 700 ops/sec @ 1ms/op
953
- schnorr.verify x 919 ops/sec @ 1ms/op
954
-
955
- ed25519
956
- init x 51 ops/sec @ 19ms/op
957
- getPublicKey x 9,809 ops/sec @ 101μs/op
958
- sign x 4,976 ops/sec @ 200μs/op
959
- verify x 1,018 ops/sec @ 981μs/op
960
-
961
- ed448
962
- init x 19 ops/sec @ 50ms/op
963
- getPublicKey x 3,723 ops/sec @ 268μs/op
964
- sign x 1,759 ops/sec @ 568μs/op
965
- verify x 344 ops/sec @ 2ms/op
966
-
967
- p256
968
- init x 39 ops/sec @ 25ms/op
969
- getPublicKey x 6,518 ops/sec @ 153μs/op
970
- sign x 5,148 ops/sec @ 194μs/op
971
- verify x 609 ops/sec @ 1ms/op
972
-
973
- p384
974
- init x 17 ops/sec @ 57ms/op
975
- getPublicKey x 2,933 ops/sec @ 340μs/op
976
- sign x 2,327 ops/sec @ 429μs/op
977
- verify x 244 ops/sec @ 4ms/op
978
-
979
- p521
980
- init x 8 ops/sec @ 112ms/op
981
- getPublicKey x 1,484 ops/sec @ 673μs/op
982
- sign x 1,264 ops/sec @ 790μs/op
983
- verify x 124 ops/sec @ 8ms/op
984
-
985
- ristretto255
986
- add x 680,735 ops/sec @ 1μs/op
987
- multiply x 10,766 ops/sec @ 92μs/op
988
- encode x 15,835 ops/sec @ 63μs/op
989
- decode x 15,972 ops/sec @ 62μs/op
990
-
991
- decaf448
992
- add x 345,303 ops/sec @ 2μs/op
993
- multiply x 300 ops/sec @ 3ms/op
994
- encode x 5,987 ops/sec @ 167μs/op
995
- decode x 5,892 ops/sec @ 169μs/op
996
-
997
- ecdh
998
- ├─x25519 x 1,477 ops/sec @ 676μs/op
999
- ├─secp256k1 x 537 ops/sec @ 1ms/op
1000
- ├─p256 x 512 ops/sec @ 1ms/op
1001
- ├─p384 x 198 ops/sec @ 5ms/op
1002
- ├─p521 x 99 ops/sec @ 10ms/op
1003
- └─x448 x 504 ops/sec @ 1ms/op
1004
-
1005
- bls12-381
1006
- init x 36 ops/sec @ 27ms/op
1007
- getPublicKey x 960 ops/sec @ 1ms/op
1008
- sign x 60 ops/sec @ 16ms/op
1009
- verify x 47 ops/sec @ 21ms/op
1010
- pairing x 125 ops/sec @ 7ms/op
1011
- pairing10 x 40 ops/sec @ 24ms/op ± 23.27% (min: 21ms, max: 48ms)
1012
- MSM 4096 scalars x points x 0 ops/sec @ 4655ms/op
1013
- aggregatePublicKeys/8 x 129 ops/sec @ 7ms/op
1014
- aggregatePublicKeys/32 x 34 ops/sec @ 28ms/op
1015
- aggregatePublicKeys/128 x 8 ops/sec @ 113ms/op
1016
- aggregatePublicKeys/512 x 2 ops/sec @ 449ms/op
1017
- aggregatePublicKeys/2048 x 0 ops/sec @ 1792ms/op
1018
- aggregateSignatures/8 x 62 ops/sec @ 15ms/op
1019
- aggregateSignatures/32 x 16 ops/sec @ 60ms/op
1020
- aggregateSignatures/128 x 4 ops/sec @ 238ms/op
1021
- aggregateSignatures/512 x 1 ops/sec @ 946ms/op
1022
- aggregateSignatures/2048 x 0 ops/sec @ 3774ms/op
1023
-
1024
- hash-to-curve
1025
- hash_to_field x 91,600 ops/sec @ 10μs/op
1026
- secp256k1 x 2,373 ops/sec @ 421μs/op
1027
- p256 x 4,310 ops/sec @ 231μs/op
1028
- p384 x 1,664 ops/sec @ 600μs/op
1029
- p521 x 807 ops/sec @ 1ms/op
1030
- ed25519 x 3,088 ops/sec @ 323μs/op
1031
- ed448 x 1,247 ops/sec @ 801μs/op
784
+ ```sh
785
+ npm run bench:install && npm run bench
786
+ ```
787
+
788
+ During first call of most methods, `init` is done, which calculates base point precomputes.
789
+ The method consumes 20MB+ of memory and takes some time.
790
+ You can adjust how many precomputes are generated,
791
+ by using `_setWindowSize`. Check out the source code.
792
+
793
+ Benchmark results on Apple M4:
794
+
795
+ ```
796
+ # secp256k1
797
+ init 10ms
798
+ getPublicKey x 9,099 ops/sec @ 109μs/op
799
+ sign x 7,182 ops/sec @ 139μs/op
800
+ verify x 1,188 ops/sec @ 841μs/op
801
+ getSharedSecret x 735 ops/sec @ 1ms/op
802
+ recoverPublicKey x 1,265 ops/sec @ 790μs/op
803
+ schnorr.sign x 957 ops/sec @ 1ms/op
804
+ schnorr.verify x 1,210 ops/sec @ 825μs/op
805
+
806
+ # ed25519
807
+ init 14ms
808
+ getPublicKey x 14,216 ops/sec @ 70μs/op
809
+ sign x 6,849 ops/sec @ 145μs/op
810
+ verify x 1,400 ops/sec @ 713μs/op
811
+
812
+ # ed448
813
+ init 37ms
814
+ getPublicKey x 5,273 ops/sec @ 189μs/op
815
+ sign x 2,494 ops/sec @ 400μs/op
816
+ verify x 476 ops/sec @ 2ms/op
817
+
818
+ # p256
819
+ init 17ms
820
+ getPublicKey x 8,977 ops/sec @ 111μs/op
821
+ sign x 7,236 ops/sec @ 138μs/op
822
+ verify x 877 ops/sec @ 1ms/op
823
+
824
+ # p384
825
+ init 42ms
826
+ getPublicKey x 4,084 ops/sec @ 244μs/op
827
+ sign x 3,247 ops/sec @ 307μs/op
828
+ verify x 331 ops/sec @ 3ms/op
829
+
830
+ # p521
831
+ init 83ms
832
+ getPublicKey x 2,049 ops/sec @ 487μs/op
833
+ sign x 1,748 ops/sec @ 571μs/op
834
+ verify x 170 ops/sec @ 5ms/op
835
+
836
+ # ristretto255
837
+ add x 931,966 ops/sec @ 1μs/op
838
+ multiply x 15,444 ops/sec @ 64μs/op
839
+ encode x 21,367 ops/sec @ 46μs/op
840
+ decode x 21,715 ops/sec @ 46μs/op
841
+
842
+ # decaf448
843
+ add x 478,011 ops/sec @ 2μs/op
844
+ multiply x 416 ops/sec @ 2ms/op
845
+ encode x 8,562 ops/sec @ 116μs/op
846
+ decode x 8,636 ops/sec @ 115μs/op
847
+
848
+ # ECDH
849
+ x25519 x 1,981 ops/sec @ 504μs/op
850
+ x448 x 743 ops/sec @ 1ms/op
851
+ secp256k1 x 728 ops/sec @ 1ms/op
852
+ p256 x 705 ops/sec @ 1ms/op
853
+ p384 x 268 ops/sec @ 3ms/op
854
+ p521 x 137 ops/sec @ 7ms/op
855
+
856
+ # hash-to-curve
857
+ hashToPrivateScalar x 1,754,385 ops/sec @ 570ns/op
858
+ hash_to_field x 135,703 ops/sec @ 7μs/op
859
+ hashToCurve secp256k1 x 3,194 ops/sec @ 313μs/op
860
+ hashToCurve p256 x 5,962 ops/sec @ 167μs/op
861
+ hashToCurve p384 x 2,230 ops/sec @ 448μs/op
862
+ hashToCurve p521 x 1,063 ops/sec @ 940μs/op
863
+ hashToCurve ed25519 x 4,047 ops/sec @ 247μs/op
864
+ hashToCurve ed448 x 1,691 ops/sec @ 591μs/op
865
+ hash_to_ristretto255 x 8,733 ops/sec @ 114μs/op
866
+ hash_to_decaf448 x 3,882 ops/sec @ 257μs/op
867
+
868
+ # modular over secp256k1 P field
869
+ invert a x 866,551 ops/sec @ 1μs/op
870
+ invert b x 693,962 ops/sec @ 1μs/op
871
+ sqrt p = 3 mod 4 x 25,738 ops/sec @ 38μs/op
872
+ sqrt tonneli-shanks x 847 ops/sec @ 1ms/op
873
+
874
+ # bls12-381
875
+ init 22ms
876
+ getPublicKey x 1,325 ops/sec @ 754μs/op
877
+ sign x 80 ops/sec @ 12ms/op
878
+ verify x 62 ops/sec @ 15ms/op
879
+ pairing x 166 ops/sec @ 6ms/op
880
+ pairing10 x 54 ops/sec @ 18ms/op ± 23.48% (15ms..36ms)
881
+ MSM 4096 scalars x points 3286ms
882
+ aggregatePublicKeys/8 x 173 ops/sec @ 5ms/op
883
+ aggregatePublicKeys/32 x 46 ops/sec @ 21ms/op
884
+ aggregatePublicKeys/128 x 11 ops/sec @ 84ms/op
885
+ aggregatePublicKeys/512 x 2 ops/sec @ 335ms/op
886
+ aggregatePublicKeys/2048 x 0 ops/sec @ 1346ms/op
887
+ aggregateSignatures/8 x 82 ops/sec @ 12ms/op
888
+ aggregateSignatures/32 x 21 ops/sec @ 45ms/op
889
+ aggregateSignatures/128 x 5 ops/sec @ 178ms/op
890
+ aggregateSignatures/512 x 1 ops/sec @ 705ms/op
891
+ aggregateSignatures/2048 x 0 ops/sec @ 2823ms/op
1032
892
  ```
1033
893
 
1034
894
  ## Upgrading
@@ -1092,10 +952,10 @@ Upgrading from [@noble/bls12-381](https://github.com/paulmillr/noble-bls12-381):
1092
952
 
1093
953
  ## Contributing & testing
1094
954
 
1095
- * `npm install && npm run build && npm test` will build the code and run tests.
1096
- * `npm run lint` / `npm run format` will run linter / fix linter issues.
1097
- * `npm run bench` will run benchmarks, which may need their deps first (`npm run bench:install`)
1098
- * `cd build && npm install && npm run build:release` will build single file
955
+ - `npm install && npm run build && npm test` will build the code and run tests.
956
+ - `npm run lint` / `npm run format` will run linter / fix linter issues.
957
+ - `npm run bench` will run benchmarks, which may need their deps first (`npm run bench:install`)
958
+ - `npm run build:release` will build single file
1099
959
 
1100
960
  Check out [github.com/paulmillr/guidelines](https://github.com/paulmillr/guidelines)
1101
961
  for general coding practices and rules.