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