@noble/curves 0.6.4 → 0.7.1

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 (172) hide show
  1. package/README.md +486 -298
  2. package/{lib/_shortw_utils.d.ts → _shortw_utils.d.ts} +1 -1
  3. package/_shortw_utils.d.ts.map +1 -0
  4. package/{lib/_shortw_utils.js → _shortw_utils.js} +2 -0
  5. package/_shortw_utils.js.map +1 -0
  6. package/{lib/abstract → abstract}/bls.d.ts +4 -9
  7. package/abstract/bls.d.ts.map +1 -0
  8. package/{lib/abstract → abstract}/bls.js +13 -26
  9. package/abstract/bls.js.map +1 -0
  10. package/{lib/abstract → abstract}/curve.d.ts +1 -0
  11. package/abstract/curve.d.ts.map +1 -0
  12. package/{lib/abstract → abstract}/curve.js +1 -0
  13. package/abstract/curve.js.map +1 -0
  14. package/{lib/abstract → abstract}/edwards.d.ts +1 -0
  15. package/abstract/edwards.d.ts.map +1 -0
  16. package/{lib/abstract → abstract}/edwards.js +9 -15
  17. package/abstract/edwards.js.map +1 -0
  18. package/{lib/abstract → abstract}/hash-to-curve.d.ts +5 -5
  19. package/abstract/hash-to-curve.d.ts.map +1 -0
  20. package/{lib/abstract → abstract}/hash-to-curve.js +41 -38
  21. package/abstract/hash-to-curve.js.map +1 -0
  22. package/{lib/abstract → abstract}/modular.d.ts +1 -0
  23. package/abstract/modular.d.ts.map +1 -0
  24. package/{lib/abstract → abstract}/modular.js +2 -1
  25. package/abstract/modular.js.map +1 -0
  26. package/{lib/abstract → abstract}/montgomery.d.ts +4 -3
  27. package/abstract/montgomery.d.ts.map +1 -0
  28. package/{lib/abstract → abstract}/montgomery.js +12 -9
  29. package/abstract/montgomery.js.map +1 -0
  30. package/{lib/abstract → abstract}/poseidon.d.ts +1 -0
  31. package/abstract/poseidon.d.ts.map +1 -0
  32. package/{lib/abstract → abstract}/poseidon.js +1 -0
  33. package/abstract/poseidon.js.map +1 -0
  34. package/{lib/abstract → abstract}/utils.d.ts +12 -1
  35. package/abstract/utils.d.ts.map +1 -0
  36. package/{lib/abstract → abstract}/utils.js +96 -10
  37. package/abstract/utils.js.map +1 -0
  38. package/{lib/abstract → abstract}/weierstrass.d.ts +6 -6
  39. package/abstract/weierstrass.d.ts.map +1 -0
  40. package/{lib/abstract → abstract}/weierstrass.js +74 -115
  41. package/abstract/weierstrass.js.map +1 -0
  42. package/{lib/bls12-381.d.ts → bls12-381.d.ts} +1 -0
  43. package/bls12-381.d.ts.map +1 -0
  44. package/{lib/bls12-381.js → bls12-381.js} +41 -7
  45. package/bls12-381.js.map +1 -0
  46. package/{lib/bn.d.ts → bn.d.ts} +1 -0
  47. package/bn.d.ts.map +1 -0
  48. package/{lib/bn.js → bn.js} +1 -0
  49. package/bn.js.map +1 -0
  50. package/{lib/ed25519.d.ts → ed25519.d.ts} +2 -1
  51. package/ed25519.d.ts.map +1 -0
  52. package/{lib/ed25519.js → ed25519.js} +6 -5
  53. package/ed25519.js.map +1 -0
  54. package/{lib/ed448.d.ts → ed448.d.ts} +2 -1
  55. package/ed448.d.ts.map +1 -0
  56. package/{lib/ed448.js → ed448.js} +4 -3
  57. package/ed448.js.map +1 -0
  58. package/{lib/esm → esm}/_shortw_utils.js +2 -0
  59. package/esm/_shortw_utils.js.map +1 -0
  60. package/{lib/esm → esm}/abstract/bls.js +14 -27
  61. package/esm/abstract/bls.js.map +1 -0
  62. package/{lib/esm → esm}/abstract/curve.js +1 -0
  63. package/esm/abstract/curve.js.map +1 -0
  64. package/{lib/esm → esm}/abstract/edwards.js +9 -15
  65. package/esm/abstract/edwards.js.map +1 -0
  66. package/{lib/esm → esm}/abstract/hash-to-curve.js +40 -36
  67. package/esm/abstract/hash-to-curve.js.map +1 -0
  68. package/{lib/esm → esm}/abstract/modular.js +2 -1
  69. package/esm/abstract/modular.js.map +1 -0
  70. package/{lib/esm → esm}/abstract/montgomery.js +12 -9
  71. package/esm/abstract/montgomery.js.map +1 -0
  72. package/{lib/esm → esm}/abstract/poseidon.js +1 -0
  73. package/esm/abstract/poseidon.js.map +1 -0
  74. package/{lib/esm → esm}/abstract/utils.js +93 -9
  75. package/esm/abstract/utils.js.map +1 -0
  76. package/{lib/esm → esm}/abstract/weierstrass.js +74 -115
  77. package/esm/abstract/weierstrass.js.map +1 -0
  78. package/{lib/esm → esm}/bls12-381.js +41 -7
  79. package/esm/bls12-381.js.map +1 -0
  80. package/{lib/esm → esm}/bn.js +1 -0
  81. package/esm/bn.js.map +1 -0
  82. package/{lib/esm → esm}/ed25519.js +7 -6
  83. package/esm/ed25519.js.map +1 -0
  84. package/{lib/esm → esm}/ed448.js +4 -3
  85. package/esm/ed448.js.map +1 -0
  86. package/{lib → esm}/index.js +1 -0
  87. package/esm/index.js.map +1 -0
  88. package/{lib/esm → esm}/jubjub.js +1 -0
  89. package/esm/jubjub.js.map +1 -0
  90. package/{lib/esm → esm}/p192.js +1 -0
  91. package/esm/p192.js.map +1 -0
  92. package/{lib/esm → esm}/p224.js +1 -0
  93. package/esm/p224.js.map +1 -0
  94. package/{lib/esm → esm}/p256.js +2 -1
  95. package/esm/p256.js.map +1 -0
  96. package/{lib/esm → esm}/p384.js +2 -1
  97. package/esm/p384.js.map +1 -0
  98. package/{lib/esm → esm}/p521.js +2 -1
  99. package/esm/p521.js.map +1 -0
  100. package/{lib/esm → esm}/package.json +0 -0
  101. package/{lib/esm → esm}/pasta.js +1 -0
  102. package/esm/pasta.js.map +1 -0
  103. package/{lib/esm → esm}/secp256k1.js +51 -50
  104. package/esm/secp256k1.js.map +1 -0
  105. package/{lib/esm → esm}/stark.js +5 -4
  106. package/esm/stark.js.map +1 -0
  107. package/index.d.ts +1 -0
  108. package/index.d.ts.map +1 -0
  109. package/index.js +3 -0
  110. package/index.js.map +1 -0
  111. package/{lib/jubjub.d.ts → jubjub.d.ts} +1 -0
  112. package/jubjub.d.ts.map +1 -0
  113. package/{lib/jubjub.js → jubjub.js} +1 -0
  114. package/jubjub.js.map +1 -0
  115. package/{lib/p192.d.ts → p192.d.ts} +1 -2
  116. package/p192.d.ts.map +1 -0
  117. package/{lib/p192.js → p192.js} +1 -0
  118. package/p192.js.map +1 -0
  119. package/{lib/p224.d.ts → p224.d.ts} +1 -2
  120. package/p224.d.ts.map +1 -0
  121. package/{lib/p224.js → p224.js} +1 -0
  122. package/p224.js.map +1 -0
  123. package/{lib/p256.d.ts → p256.d.ts} +2 -3
  124. package/p256.d.ts.map +1 -0
  125. package/{lib/p256.js → p256.js} +2 -1
  126. package/p256.js.map +1 -0
  127. package/{lib/p384.d.ts → p384.d.ts} +2 -3
  128. package/p384.d.ts.map +1 -0
  129. package/{lib/p384.js → p384.js} +2 -1
  130. package/p384.js.map +1 -0
  131. package/{lib/p521.d.ts → p521.d.ts} +2 -3
  132. package/p521.d.ts.map +1 -0
  133. package/{lib/p521.js → p521.js} +2 -1
  134. package/p521.js.map +1 -0
  135. package/package.json +84 -79
  136. package/{lib/pasta.d.ts → pasta.d.ts} +1 -0
  137. package/pasta.d.ts.map +1 -0
  138. package/{lib/pasta.js → pasta.js} +1 -0
  139. package/pasta.js.map +1 -0
  140. package/{lib/secp256k1.d.ts → secp256k1.d.ts} +20 -6
  141. package/secp256k1.d.ts.map +1 -0
  142. package/{lib/secp256k1.js → secp256k1.js} +48 -47
  143. package/secp256k1.js.map +1 -0
  144. package/src/_shortw_utils.ts +20 -0
  145. package/src/abstract/bls.ts +376 -0
  146. package/src/abstract/curve.ts +199 -0
  147. package/src/abstract/edwards.ts +479 -0
  148. package/src/abstract/hash-to-curve.ts +220 -0
  149. package/src/abstract/modular.ts +417 -0
  150. package/src/abstract/montgomery.ts +186 -0
  151. package/src/abstract/poseidon.ts +119 -0
  152. package/src/abstract/utils.ts +246 -0
  153. package/src/abstract/weierstrass.ts +1177 -0
  154. package/src/bls12-381.ts +1274 -0
  155. package/src/bn.ts +21 -0
  156. package/src/ed25519.ts +428 -0
  157. package/src/ed448.ts +241 -0
  158. package/{lib/esm/index.js → src/index.ts} +0 -1
  159. package/src/jubjub.ts +58 -0
  160. package/src/p192.ts +25 -0
  161. package/src/p224.ts +25 -0
  162. package/src/p256.ts +53 -0
  163. package/src/p384.ts +57 -0
  164. package/src/p521.ts +57 -0
  165. package/src/pasta.ts +31 -0
  166. package/src/secp256k1.ts +270 -0
  167. package/src/stark.ts +356 -0
  168. package/{lib/stark.d.ts → stark.d.ts} +1 -1
  169. package/stark.d.ts.map +1 -0
  170. package/{lib/stark.js → stark.js} +5 -4
  171. package/stark.js.map +1 -0
  172. package/lib/index.d.ts +0 -0
package/README.md CHANGED
@@ -1,36 +1,35 @@
1
1
  # noble-curves
2
2
 
3
- Minimal, auditable JS implementation of elliptic curve cryptography.
3
+ Audited & minimal JS implementation of elliptic curve cryptography.
4
4
 
5
+ - **noble** family, zero dependencies
5
6
  - Short Weierstrass, Edwards, Montgomery curves
6
7
  - ECDSA, EdDSA, Schnorr, BLS signature schemes, ECDH key agreement
7
- - [hash to curve](https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/)
8
- for encoding or hashing an arbitrary string to a point on an elliptic curve
9
- - [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash
8
+ - #️⃣ [hash to curve](https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/)
9
+ for encoding or hashing an arbitrary string to an elliptic curve point
10
+ - 🧜‍♂️ [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash
10
11
  - 🏎 [Ultra-fast](#speed), hand-optimized for caveats of JS engines
11
12
  - 🔍 Unique tests ensure correctness. Wycheproof vectors included
12
13
  - 🔻 Tree-shaking-friendly: there is no entry point, which ensures small size of your app
13
14
 
14
15
  Package consists of two parts:
15
16
 
16
- 1. `abstract/` directory specifies zero-dependency EC algorithms
17
- 2. root directory utilizes one dependency `@noble/hashes` and provides ready-to-use:
17
+ 1. [Abstract](#abstract-api), zero-dependency EC algorithms
18
+ 2. [Implementations](#implementations), utilizing one dependency `@noble/hashes`, providing ready-to-use:
18
19
  - NIST curves secp192r1/P192, secp224r1/P224, secp256r1/P256, secp384r1/P384, secp521r1/P521
19
20
  - SECG curve secp256k1
21
+ - ed25519/curve25519/x25519/ristretto255, edwards448/curve448/x448 RFC7748 / RFC8032 / ZIP215 stuff
20
22
  - pairing-friendly curves bls12-381, bn254
21
- - ed25519/curve25519/x25519/ristretto, edwards448/curve448/x448 RFC7748 / RFC8032 / ZIP215 stuff
22
23
 
23
- Curves incorporate work from previous noble packages
24
- ([secp256k1](https://github.com/paulmillr/noble-secp256k1),
25
- [ed25519](https://github.com/paulmillr/noble-ed25519)),
26
- which had security audits and were developed from 2019 to 2022.
27
- Check out [Upgrading](#upgrading) section if you've used them before.
24
+ Check out [Upgrading](#upgrading) if you've previously used single-feature noble packages
25
+ ([secp256k1](https://github.com/paulmillr/noble-secp256k1), [ed25519](https://github.com/paulmillr/noble-ed25519)).
26
+ See [Resources](#resouces) for articles and real-world software that uses curves.
28
27
 
29
28
  ### This library belongs to _noble_ crypto
30
29
 
31
30
  > **noble-crypto** — high-security, easily auditable set of contained cryptographic libraries and tools.
32
31
 
33
- - Protection against supply chain attacks
32
+ - No dependencies, protection against supply chain attacks
34
33
  - Easily auditable TypeScript/JS code
35
34
  - Supported in all major browsers and stable node.js versions
36
35
  - All releases are signed with PGP keys
@@ -42,15 +41,41 @@ Check out [Upgrading](#upgrading) section if you've used them before.
42
41
 
43
42
  ## Usage
44
43
 
45
- Use NPM in node.js / browser, or include single file from
46
- [GitHub's releases page](https://github.com/paulmillr/noble-curves/releases):
44
+ Use NPM for browser / node.js:
47
45
 
48
46
  > npm install @noble/curves
49
47
 
50
- The library does not have an entry point. It allows you to select specific primitives and drop everything else. If you only want to use secp256k1, just use the library with rollup or other bundlers. This is done to make your bundles tiny. All curves:
48
+ For [Deno](https://deno.land), use it with [npm specifier](https://deno.land/manual@v1.28.0/node/npm_specifiers). In browser, you could also include the single file from
49
+ [GitHub's releases page](https://github.com/paulmillr/noble-curves/releases).
50
+
51
+ The library is tree-shaking-friendly and does not expose root entry point as `import * from '@noble/curves'`.
52
+ Instead, you need to import specific primitives. This is done to ensure small size of your apps.
53
+
54
+ ### Implementations
55
+
56
+ Each curve can be used in the following way:
51
57
 
52
58
  ```ts
53
- import { secp256k1 } from '@noble/curves/secp256k1';
59
+ import { secp256k1 } from '@noble/curves/secp256k1'; // ECMAScript Modules (ESM) and Common.js
60
+ // import { secp256k1 } from 'npm:@noble/curves@1.2.0/secp256k1'; // Deno
61
+ const priv = secp256k1.utils.randomPrivateKey();
62
+ const pub = secp256k1.getPublicKey(priv);
63
+ const msg = new Uint8Array(32).fill(1);
64
+ const sig = secp256k1.sign(msg, priv);
65
+ secp256k1.verify(sig, msg, pub) === true;
66
+
67
+ const privHex = '46c930bc7bb4db7f55da20798697421b98c4175a52c630294d75a84b9c126236';
68
+ const pub2 = secp256k1.getPublicKey(privHex); // keys & other inputs can be Uint8Array-s or hex strings
69
+
70
+ // Follows hash-to-curve specification to encode arbitrary hashes to EC points
71
+ import { hashToCurve, encodeToCurve } from '@noble/curves/secp256k1';
72
+ hashToCurve('0102abcd');
73
+ ```
74
+
75
+ All curves:
76
+
77
+ ```typescript
78
+ import { secp256k1, schnorr } from '@noble/curves/secp256k1';
54
79
  import { ed25519, ed25519ph, ed25519ctx, x25519, RistrettoPoint } from '@noble/curves/ed25519';
55
80
  import { ed448, ed448ph, ed448ctx, x448 } from '@noble/curves/ed448';
56
81
  import { p256 } from '@noble/curves/p256';
@@ -63,63 +88,214 @@ import { bn254 } from '@noble/curves/bn';
63
88
  import { jubjub } from '@noble/curves/jubjub';
64
89
  ```
65
90
 
66
- Every curve can be used in the following way:
91
+ Weierstrass curves feature recovering public keys from signatures and ECDH key agreement:
67
92
 
68
93
  ```ts
69
- import { secp256k1 } from '@noble/curves/secp256k1'; // Common.js and ECMAScript Modules (ESM)
70
-
71
- const key = secp256k1.utils.randomPrivateKey();
72
- const pub = secp256k1.getPublicKey(key);
73
- const msg = new Uint8Array(32).fill(1);
74
- const sig = secp256k1.sign(msg, key);
75
- // weierstrass curves should use extraEntropy: https://moderncrypto.org/mail-archive/curves/2017/000925.html
76
- const sigImprovedSecurity = secp256k1.sign(msg, key, { extraEntropy: true });
77
- secp256k1.verify(sig, msg, pub) === true;
78
- // secp, p*, pasta curves allow pub recovery
79
- sig.recoverPublicKey(msg) === pub;
94
+ // extraEntropy https://moderncrypto.org/mail-archive/curves/2017/000925.html
95
+ const sigImprovedSecurity = secp256k1.sign(msg, priv, { extraEntropy: true });
96
+ sig.recoverPublicKey(msg) === pub; // public key recovery
80
97
  const someonesPub = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
81
- const shared = secp256k1.getSharedSecret(key, someonesPub);
98
+ const shared = secp256k1.getSharedSecret(priv, someonesPub); // ECDH (elliptic curve diffie-hellman)
99
+ ```
100
+
101
+ secp256k1 has schnorr signature implementation which follows
102
+ [BIP340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki):
103
+
104
+ ```ts
105
+ import { schnorr } from '@noble/curves/secp256k1';
106
+ const priv = schnorr.utils.randomPrivateKey();
107
+ const pub = schnorr.getPublicKey(priv);
108
+ const msg = new TextEncoder().encode('hello');
109
+ const sig = schnorr.sign(msg, priv);
110
+ const isValid = schnorr.verify(sig, msg, pub);
111
+ console.log(isValid);
82
112
  ```
83
113
 
84
- To define a custom curve, check out docs below.
114
+ ed25519 module has ed25519ctx / ed25519ph variants,
115
+ x25519 ECDH and [ristretto255](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448).
116
+ It follows [ZIP215](https://zips.z.cash/zip-0215) and [can be used in consensus-critical applications](https://hdevalence.ca/blog/2020-10-04-its-25519am):
85
117
 
86
- ## API
118
+ ```ts
119
+ import { ed25519 } from '@noble/curves/ed25519';
120
+
121
+ // Variants from RFC8032: with context, prehashed
122
+ import { ed25519ctx, ed25519ph } from '@noble/curves/ed25519';
123
+
124
+ // ECDH using curve25519 aka x25519
125
+ import { x25519 } from '@noble/curves/ed25519';
126
+ const priv = 'a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4';
127
+ const pub = 'e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c';
128
+ x25519.getSharedSecret(priv, pub) === x25519.scalarMult(priv, pub); // aliases
129
+ x25519.getPublicKey(priv) === x25519.scalarMultBase(priv);
130
+
131
+ // hash-to-curve
132
+ import { hashToCurve, encodeToCurve } from '@noble/curves/ed25519';
133
+
134
+ import { RistrettoPoint } from '@noble/curves/ed25519';
135
+ const rp = RistrettoPoint.fromHex(
136
+ '6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919'
137
+ );
138
+ RistrettoPoint.hashToCurve('Ristretto is traditionally a short shot of espresso coffee');
139
+ // also has add(), equals(), multiply(), toRawBytes() methods
140
+ ```
87
141
 
88
- - [Overview](#overview)
142
+ ed448 module is basically the same:
143
+
144
+ ```ts
145
+ import { ed448, ed448ph, ed448ctx, x448 } from '@noble/curves/ed448';
146
+ import { hashToCurve, encodeToCurve } from '@noble/curves/ed448';
147
+ ```
148
+
149
+ BLS12-381 pairing-friendly Barreto-Lynn-Scott elliptic curve construction allows to
150
+ construct [zk-SNARKs](https://z.cash/technology/zksnarks/) at the 128-bit security
151
+ and use aggregated, batch-verifiable
152
+ [threshold signatures](https://medium.com/snigirev.stepan/bls-signatures-better-than-schnorr-5a7fe30ea716),
153
+ using Boneh-Lynn-Shacham signature scheme.
154
+
155
+ ```ts
156
+ import { bls12_381 as bls } from '@noble/curves/bls12-381';
157
+ const privateKey = '67d53f170b908cabb9eb326c3c337762d59289a8fec79f7bc9254b584b73265c';
158
+ const message = '64726e3da8';
159
+ const publicKey = bls.getPublicKey(privateKey);
160
+ const signature = bls.sign(message, privateKey);
161
+ const isValid = bls.verify(signature, message, publicKey);
162
+ console.log({ publicKey, signature, isValid });
163
+
164
+ // Sign 1 msg with 3 keys
165
+ const privateKeys = [
166
+ '18f020b98eb798752a50ed0563b079c125b0db5dd0b1060d1c1b47d4a193e1e4',
167
+ 'ed69a8c50cf8c9836be3b67c7eeff416612d45ba39a5c099d48fa668bf558c9c',
168
+ '16ae669f3be7a2121e17d0c68c05a8f3d6bef21ec0f2315f1d7aec12484e4cf5',
169
+ ];
170
+ const messages = ['d2', '0d98', '05caf3'];
171
+ const publicKeys = privateKeys.map(bls.getPublicKey);
172
+ const signatures2 = privateKeys.map((p) => bls.sign(message, p));
173
+ const aggPubKey2 = bls.aggregatePublicKeys(publicKeys);
174
+ const aggSignature2 = bls.aggregateSignatures(signatures2);
175
+ const isValid2 = bls.verify(aggSignature2, message, aggPubKey2);
176
+ console.log({ signatures2, aggSignature2, isValid2 });
177
+
178
+ // Sign 3 msgs with 3 keys
179
+ const signatures3 = privateKeys.map((p, i) => bls.sign(messages[i], p));
180
+ const aggSignature3 = bls.aggregateSignatures(signatures3);
181
+ const isValid3 = bls.verifyBatch(aggSignature3, messages, publicKeys);
182
+ console.log({ publicKeys, signatures3, aggSignature3, isValid3 });
183
+
184
+ // Pairings
185
+ // bls.pairing(PointG1, PointG2)
186
+ // Also, check out hash-to-curve examples below.
187
+ ```
188
+
189
+ ## Abstract API
190
+
191
+ Abstract API allows to define custom curves. All arithmetics is done with JS bigints over finite fields,
192
+ which is defined from `modular` sub-module. For scalar multiplication, we use [precomputed tables with w-ary non-adjacent form (wNAF)](https://paulmillr.com/posts/noble-secp256k1-fast-ecc/).
193
+ Precomputes are enabled for weierstrass and edwards BASE points of a curve. You could precompute any
194
+ other point (e.g. for ECDH) using `utils.precompute()` method: check out examples.
195
+
196
+ There are following zero-dependency algorithms:
197
+
198
+ - [abstract/weierstrass: Short Weierstrass curve](#abstractweierstrass-short-weierstrass-curve)
89
199
  - [abstract/edwards: Twisted Edwards curve](#abstractedwards-twisted-edwards-curve)
90
200
  - [abstract/montgomery: Montgomery curve](#abstractmontgomery-montgomery-curve)
91
- - [abstract/weierstrass: Short Weierstrass curve](#abstractweierstrass-short-weierstrass-curve)
92
201
  - [abstract/hash-to-curve: Hashing strings to curve points](#abstracthash-to-curve-hashing-strings-to-curve-points)
93
202
  - [abstract/poseidon: Poseidon hash](#abstractposeidon-poseidon-hash)
94
- - [abstract/modular](#abstractmodular)
95
- - [abstract/utils](#abstractutils)
96
-
97
- ### Overview
203
+ - [abstract/modular: Modular arithmetics utilities](#abstractmodular-modular-arithmetics-utilities)
204
+ - [abstract/utils: General utilities](#abstractutils-general-utilities)
98
205
 
99
- There are following zero-dependency abstract algorithms:
206
+ ### abstract/weierstrass: Short Weierstrass curve
100
207
 
101
208
  ```ts
102
- import { bls } from '@noble/curves/abstract/bls';
103
- import { twistedEdwards } from '@noble/curves/abstract/edwards';
104
- import { montgomery } from '@noble/curves/abstract/montgomery';
105
209
  import { weierstrass } from '@noble/curves/abstract/weierstrass';
106
- import * as mod from '@noble/curves/abstract/modular';
107
- import * as utils from '@noble/curves/abstract/utils';
108
210
  ```
109
211
 
110
- They allow to define a new curve in a few lines of code:
212
+ Short Weierstrass curve's formula is `y² = + ax + b`. `weierstrass` expects arguments `a`, `b`, field `Fp`, curve order `n`, cofactor `h`
213
+ and coordinates `Gx`, `Gy` of generator point.
214
+
215
+ **`k` generation** is done deterministically, following [RFC6979](https://www.rfc-editor.org/rfc/rfc6979).
216
+ For this you will need `hmac` & `hash`, which in our implementations is provided by noble-hashes.
217
+ If you're using different hashing library, make sure to wrap it in the following interface:
111
218
 
112
219
  ```ts
113
- import { Field } from '@noble/curves/abstract/modular';
114
- import { weierstrass } from '@noble/curves/abstract/weierstrass';
115
- import { hmac } from '@noble/hashes/hmac';
116
- import { sha256 } from '@noble/hashes/sha256';
117
- import { concatBytes, randomBytes } from '@noble/hashes/utils';
220
+ type CHash = {
221
+ (message: Uint8Array): Uint8Array;
222
+ blockLen: number;
223
+ outputLen: number;
224
+ create(): any;
225
+ };
226
+ ```
227
+
228
+ **Weierstrass points:**
229
+
230
+ 1. Exported as `ProjectivePoint`
231
+ 2. Represented in projective (homogeneous) coordinates: (x, y, z) ∋ (x=x/z, y=y/z)
232
+ 3. Use complete exception-free formulas for addition and doubling
233
+ 4. Can be decoded/encoded from/to Uint8Array / hex strings using `ProjectivePoint.fromHex` and `ProjectivePoint#toRawBytes()`
234
+ 5. Have `assertValidity()` which checks for being on-curve
235
+ 6. Have `toAffine()` and `x` / `y` getters which convert to 2d xy affine coordinates
118
236
 
119
- // secq (NOT secp) 256k1: cycle of secp256k1 with Fp/N flipped.
120
- // https://zcash.github.io/halo2/background/curves.html#cycles-of-curves
121
- // https://personaelabs.org/posts/spartan-ecdsa
237
+ ```ts
238
+ // T is usually bigint, but can be something else like complex numbers in BLS curves
239
+ interface ProjPointType<T> extends Group<ProjPointType<T>> {
240
+ readonly px: T;
241
+ readonly py: T;
242
+ readonly pz: T;
243
+ multiply(scalar: bigint): ProjPointType<T>;
244
+ multiplyUnsafe(scalar: bigint): ProjPointType<T>;
245
+ multiplyAndAddUnsafe(Q: ProjPointType<T>, a: bigint, b: bigint): ProjPointType<T> | undefined;
246
+ toAffine(iz?: T): AffinePoint<T>;
247
+ isTorsionFree(): boolean;
248
+ clearCofactor(): ProjPointType<T>;
249
+ assertValidity(): void;
250
+ hasEvenY(): boolean;
251
+ toRawBytes(isCompressed?: boolean): Uint8Array;
252
+ toHex(isCompressed?: boolean): string;
253
+ }
254
+ // Static methods for 3d XYZ points
255
+ interface ProjConstructor<T> extends GroupConstructor<ProjPointType<T>> {
256
+ new (x: T, y: T, z: T): ProjPointType<T>;
257
+ fromAffine(p: AffinePoint<T>): ProjPointType<T>;
258
+ fromHex(hex: Hex): ProjPointType<T>;
259
+ fromPrivateKey(privateKey: PrivKey): ProjPointType<T>;
260
+ }
261
+ ```
262
+
263
+ **ECDSA signatures** are represented by `Signature` instances and can be described by the interface:
264
+
265
+ ```ts
266
+ interface SignatureType {
267
+ readonly r: bigint;
268
+ readonly s: bigint;
269
+ readonly recovery?: number;
270
+ assertValidity(): void;
271
+ addRecoveryBit(recovery: number): SignatureType;
272
+ hasHighS(): boolean;
273
+ normalizeS(): SignatureType;
274
+ recoverPublicKey(msgHash: Hex): ProjPointType<bigint>;
275
+ toCompactRawBytes(): Uint8Array;
276
+ toCompactHex(): string;
277
+ // DER-encoded
278
+ toDERRawBytes(): Uint8Array;
279
+ toDERHex(): string;
280
+ }
281
+ type SignatureConstructor = {
282
+ new (r: bigint, s: bigint): SignatureType;
283
+ fromCompact(hex: Hex): SignatureType;
284
+ fromDER(hex: Hex): SignatureType;
285
+ };
286
+ ```
287
+
288
+ Example implementing [secq256k1](https://personaelabs.org/posts/spartan-ecdsa) (NOT secp256k1)
289
+ [cycle](https://zcash.github.io/halo2/background/curves.html#cycles-of-curves) of secp256k1 with Fp/N flipped.
290
+
291
+ ```typescript
292
+ import { weierstrass } from '@noble/curves/abstract/weierstrass';
293
+ import { Field } from '@noble/curves/abstract/modular'; // finite field, mod arithmetics done over it
294
+ import { sha256 } from '@noble/hashes/sha256'; // 3rd-party sha256() of type utils.CHash, with blockLen/outputLen
295
+ import { hmac } from '@noble/hashes/hmac'; // 3rd-party hmac() that will accept sha256()
296
+ import { concatBytes, randomBytes } from '@noble/hashes/utils'; // 3rd-party utilities
122
297
  const secq256k1 = weierstrass({
298
+ // secq256k1: cycle of secp256k1 with Fp/N flipped.
123
299
  a: 0n,
124
300
  b: 7n,
125
301
  Fp: Field(2n ** 256n - 432420386565659656852420866394968145599n),
@@ -130,50 +306,110 @@ const secq256k1 = weierstrass({
130
306
  hmac: (key: Uint8Array, ...msgs: Uint8Array[]) => hmac(sha256, key, concatBytes(...msgs)),
131
307
  randomBytes,
132
308
  });
309
+
310
+ // All curves expose same generic interface.
311
+ const priv = secq256k1.utils.randomPrivateKey();
312
+ secq256k1.getPublicKey(priv); // Convert private key to public.
313
+ const sig = secq256k1.sign(msg, priv); // Sign msg with private key.
314
+ secq256k1.verify(sig, msg, priv); // Verify if sig is correct.
315
+
316
+ const Point = secq256k1.ProjectivePoint;
317
+ const point = Point.BASE; // Elliptic curve Point class and BASE point static var.
318
+ point.add(point).equals(point.double()); // add(), equals(), double() methods
319
+ point.subtract(point).equals(Point.ZERO); // subtract() method, ZERO static var
320
+ point.negate(); // Flips point over x/y coordinate.
321
+ point.multiply(31415n); // Multiplication of Point by scalar.
322
+
323
+ point.assertValidity(); // Checks for being on-curve
324
+ point.toAffine(); // Converts to 2d affine xy coordinates
325
+
326
+ secq256k1.CURVE.n;
327
+ secq256k1.CURVE.Fp.mod();
328
+ secq256k1.CURVE.hash();
329
+
330
+ // precomputes
331
+ const fast = secq256k1.utils.precompute(8, Point.fromHex(someonesPubKey));
332
+ fast.multiply(privKey); // much faster ECDH now
133
333
  ```
134
334
 
135
- - To initialize new curve, you must specify its variables, order (number of points on curve), field prime (over which the modular division would be done)
136
- - All curves expose same generic interface:
137
- - `getPublicKey()`, `sign()`, `verify()` functions
138
- - `Point` conforming to `Group` interface with add/multiply/double/negate/add/equals methods
139
- - `CURVE` object with curve variables like `Gx`, `Gy`, `Fp` (field), `n` (order)
140
- - `utils` object with `randomPrivateKey()`, `mod()`, `invert()` methods (`mod CURVE.P`)
141
- - All arithmetics is done with JS bigints over finite fields, which is defined from `modular` sub-module
142
- - Many features require hashing, which is not provided. `@noble/hashes` can be used for this purpose.
143
- Any other library must conform to the CHash interface:
144
- ```ts
145
- export type CHash = {
146
- (message: Uint8Array): Uint8Array;
147
- blockLen: number;
148
- outputLen: number;
149
- create(): any;
335
+ `weierstrass()` returns `CurveFn`:
336
+
337
+ ```ts
338
+ type SignOpts = { lowS?: boolean; prehash?: boolean; extraEntropy: boolean | Uint8Array };
339
+ type CurveFn = {
340
+ CURVE: ReturnType<typeof validateOpts>;
341
+ getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
342
+ getSharedSecret: (privateA: PrivKey, publicB: Hex, isCompressed?: boolean) => Uint8Array;
343
+ sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) => SignatureType;
344
+ verify: (
345
+ signature: Hex | SignatureType,
346
+ msgHash: Hex,
347
+ publicKey: Hex,
348
+ opts?: { lowS?: boolean; prehash?: boolean }
349
+ ) => boolean;
350
+ ProjectivePoint: ProjectivePointConstructor;
351
+ Signature: SignatureConstructor;
352
+ utils: {
353
+ normPrivateKeyToScalar: (key: PrivKey) => bigint;
354
+ isValidPrivateKey(key: PrivKey): boolean;
355
+ randomPrivateKey: () => Uint8Array;
356
+ precompute: (windowSize?: number, point?: ProjPointType<bigint>) => ProjPointType<bigint>;
150
357
  };
151
- ```
152
- - w-ary non-adjacent form (wNAF) method with constant-time adjustments is used for point multiplication.
153
- It is possible to enable precomputes for edwards & weierstrass curves.
154
- Precomputes are calculated once (takes ~20-40ms), after that most `G` base point multiplications:
155
- for example, `getPublicKey()`, `sign()` and similar methods - would be much faster.
156
- Use `curve.utils.precompute()` to adjust precomputation window size
157
- - You could use optional special params to tune performance:
158
- - `Fp({sqrt})` square root calculation, used for point decompression
159
- - `endo` endomorphism options for Koblitz curves
358
+ };
359
+ ```
160
360
 
161
361
  ### abstract/edwards: Twisted Edwards curve
162
362
 
163
- Twisted Edwards curve's formula is: ax² + y² = 1 + dx²y².
363
+ Twisted Edwards curve's formula is `ax² + y² = 1 + dx²y²`. You must specify `a`, `d`, field `Fp`, order `n`, cofactor `h`
364
+ and coordinates `Gx`, `Gy` of generator point.
164
365
 
165
- - You must specify curve params `a`, `d`, field `Fp`, order `n`, cofactor `h` and coordinates `Gx`, `Gy` of generator point
166
- - For EdDSA signatures, params `hash` is also required. `adjustScalarBytes` which instructs how to change private scalars could be specified
366
+ For EdDSA signatures, `hash` param required. `adjustScalarBytes` which instructs how to change private scalars could be specified.
167
367
 
168
- ```typescript
368
+ **Edwards points:**
369
+
370
+ 1. Exported as `ExtendedPoint`
371
+ 2. Represented in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z)
372
+ 3. Use complete exception-free formulas for addition and doubling
373
+ 4. Can be decoded/encoded from/to Uint8Array / hex strings using `ExtendedPoint.fromHex` and `ExtendedPoint#toRawBytes()`
374
+ 5. Have `assertValidity()` which checks for being on-curve
375
+ 6. Have `toAffine()` and `x` / `y` getters which convert to 2d xy affine coordinates
376
+ 7. Have `isTorsionFree()`, `clearCofactor()` and `isSmallOrder()` utilities to handle torsions
377
+
378
+ ```ts
379
+ interface ExtPointType extends Group<ExtPointType> {
380
+ readonly ex: bigint;
381
+ readonly ey: bigint;
382
+ readonly ez: bigint;
383
+ readonly et: bigint;
384
+ assertValidity(): void;
385
+ multiply(scalar: bigint): ExtPointType;
386
+ multiplyUnsafe(scalar: bigint): ExtPointType;
387
+ isSmallOrder(): boolean;
388
+ isTorsionFree(): boolean;
389
+ clearCofactor(): ExtPointType;
390
+ toAffine(iz?: bigint): AffinePoint<bigint>;
391
+ }
392
+ // Static methods of Extended Point with coordinates in X, Y, Z, T
393
+ interface ExtPointConstructor extends GroupConstructor<ExtPointType> {
394
+ new (x: bigint, y: bigint, z: bigint, t: bigint): ExtPointType;
395
+ fromAffine(p: AffinePoint<bigint>): ExtPointType;
396
+ fromHex(hex: Hex): ExtPointType;
397
+ fromPrivateKey(privateKey: Hex): ExtPointType;
398
+ }
399
+ ```
400
+
401
+ Example implementing edwards25519:
402
+
403
+ ```ts
169
404
  import { twistedEdwards } from '@noble/curves/abstract/edwards';
170
- import { div } from '@noble/curves/abstract/modular';
405
+ import { Field, div } from '@noble/curves/abstract/modular';
171
406
  import { sha512 } from '@noble/hashes/sha512';
172
407
 
408
+ const Fp = Field(2n ** 255n - 19n);
173
409
  const ed25519 = twistedEdwards({
174
410
  a: -1n,
175
- d: div(-121665n, 121666n, 2n ** 255n - 19n), // -121665n/121666n
176
- P: 2n ** 255n - 19n,
411
+ d: Fp.div(-121665n, 121666n), // -121665n/121666n mod p
412
+ Fp,
177
413
  n: 2n ** 252n + 27742317777372353535851937790883648493n,
178
414
  h: 8n,
179
415
  Gx: 15112221349535400772501151409588531511454012693041857206046113283949847762202n,
@@ -181,31 +417,24 @@ const ed25519 = twistedEdwards({
181
417
  hash: sha512,
182
418
  randomBytes,
183
419
  adjustScalarBytes(bytes) {
184
- // optional in general, mandatory in ed25519
420
+ // optional; but mandatory in ed25519
185
421
  bytes[0] &= 248;
186
422
  bytes[31] &= 127;
187
423
  bytes[31] |= 64;
188
424
  return bytes;
189
425
  },
190
426
  } as const);
191
- const key = ed25519.utils.randomPrivateKey();
192
- const pub = ed25519.getPublicKey(key);
193
- const msg = new TextEncoder().encode('hello world'); // strings not accepted, must be Uint8Array
194
- const sig = ed25519.sign(msg, key);
195
- ed25519.verify(sig, msg, pub) === true;
196
427
  ```
197
428
 
198
429
  `twistedEdwards()` returns `CurveFn` of following type:
199
430
 
200
431
  ```ts
201
- export type CurveFn = {
432
+ type CurveFn = {
202
433
  CURVE: ReturnType<typeof validateOpts>;
203
- getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
204
- sign: (message: Hex, privateKey: Hex) => Uint8Array;
205
- verify: (sig: SigType, message: Hex, publicKey: PubKey) => boolean;
206
- Point: PointConstructor;
207
- ExtendedPoint: ExtendedPointConstructor;
208
- Signature: SignatureConstructor;
434
+ getPublicKey: (privateKey: Hex) => Uint8Array;
435
+ sign: (message: Hex, privateKey: Hex, context?: Hex) => Uint8Array;
436
+ verify: (sig: SigType, message: Hex, publicKey: Hex, context?: Hex) => boolean;
437
+ ExtendedPoint: ExtPointConstructor;
209
438
  utils: {
210
439
  randomPrivateKey: () => Uint8Array;
211
440
  getExtendedPublicKey: (key: PrivKey) => {
@@ -221,26 +450,20 @@ export type CurveFn = {
221
450
 
222
451
  ### abstract/montgomery: Montgomery curve
223
452
 
224
- For now the module only contains methods for x-only ECDH on Curve25519 / Curve448 from RFC7748.
453
+ The module contains methods for x-only ECDH on Curve25519 / Curve448 from RFC7748. Proper Elliptic Curve Points are not implemented yet.
225
454
 
226
- Proper Elliptic Curve Points are not implemented yet.
227
-
228
- You must specify curve field, `a24` special variable, `montgomeryBits`, `nByteLength`, and coordinate `u` of generator point.
455
+ You must specify curve params `Fp`, `a`, `Gu` coordinate of u, `montgomeryBits` and `nByteLength`.
229
456
 
230
457
  ```typescript
231
458
  import { montgomery } from '@noble/curves/abstract/montgomery';
232
459
 
233
460
  const x25519 = montgomery({
234
- P: 2n ** 255n - 19n,
235
- a24: 121665n, // TODO: change to a
461
+ Fp: Field(2n ** 255n - 19n),
462
+ a: 486662n,
463
+ Gu: 9n,
236
464
  montgomeryBits: 255,
237
465
  nByteLength: 32,
238
- Gu: '0900000000000000000000000000000000000000000000000000000000000000',
239
-
240
- // Optional params
241
- powPminus2: (x: bigint): bigint => {
242
- return mod.pow(x, P - 2, P);
243
- },
466
+ // Optional param
244
467
  adjustScalarBytes(bytes) {
245
468
  bytes[0] &= 248;
246
469
  bytes[31] &= 127;
@@ -250,145 +473,61 @@ const x25519 = montgomery({
250
473
  });
251
474
  ```
252
475
 
253
- ### abstract/weierstrass: Short Weierstrass curve
254
-
255
- Short Weierstrass curve's formula is: y² = x³ + ax + b. Uses deterministic ECDSA from RFC6979. You can also specify `extraEntropy` in `sign()`.
256
-
257
- - You must specify curve params: `a`, `b`, field `Fp`, order `n`, cofactor `h` and coordinates `Gx`, `Gy` of generator point
258
- - For ECDSA, you must specify `hash`, `hmac`. It is also possible to recover keys from signatures
259
- - For ECDH, use `getSharedSecret(privKeyA, pubKeyB)`
260
- - Optional params are `lowS` (default value) and `endo` (endomorphism)
476
+ ### abstract/hash-to-curve: Hashing strings to curve points
261
477
 
262
- ```typescript
263
- import { Fp } from '@noble/curves/abstract/modular';
264
- import { weierstrass } from '@noble/curves/abstract/weierstrass'; // Short Weierstrass curve
265
- import { sha256 } from '@noble/hashes/sha256';
266
- import { hmac } from '@noble/hashes/hmac';
267
- import { concatBytes, randomBytes } from '@noble/hashes/utils';
478
+ The module allows to hash arbitrary strings to elliptic curve points. Implements [hash-to-curve v11](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11).
268
479
 
269
- const secp256k1 = weierstrass({
270
- a: 0n,
271
- b: 7n,
272
- Fp: Fp(2n ** 256n - 2n ** 32n - 2n ** 9n - 2n ** 8n - 2n ** 7n - 2n ** 6n - 2n ** 4n - 1n),
273
- n: 2n ** 256n - 432420386565659656852420866394968145599n,
274
- Gx: 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
275
- Gy: 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
276
- hash: sha256,
277
- hmac: (k: Uint8Array, ...msgs: Uint8Array[]) => hmac(sha256, key, concatBytes(...msgs)),
278
- randomBytes,
480
+ Every curve has exported `hashToCurve` and `encodeToCurve` methods:
279
481
 
280
- // Optional params
281
- h: 1n, // Cofactor
282
- lowS: true, // Allow only low-S signatures by default in sign() and verify()
283
- endo: {
284
- // Endomorphism options for Koblitz curve
285
- // Beta param
286
- beta: 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501een,
287
- // Split scalar k into k1, k2
288
- splitScalar: (k: bigint) => {
289
- // return { k1neg: true, k1: 512n, k2neg: false, k2: 448n };
290
- },
291
- },
292
- });
482
+ ```ts
483
+ import { hashToCurve, encodeToCurve } from '@noble/curves/secp256k1';
484
+ import { randomBytes } from '@noble/hashes/utils';
485
+ console.log(hashToCurve(randomBytes()));
486
+ console.log(encodeToCurve(randomBytes()));
293
487
 
294
- // Usage
295
- const key = secp256k1.utils.randomPrivateKey();
296
- const pub = secp256k1.getPublicKey(key);
297
- const msg = randomBytes(32);
298
- const sig = secp256k1.sign(msg, key);
299
- secp256k1.verify(sig, msg, pub); // true
300
- sig.recoverPublicKey(msg); // == pub
301
- const someonesPubkey = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
302
- const shared = secp256k1.getSharedSecret(key, someonesPubkey);
488
+ import { bls12_381 } from '@noble/curves/bls12-381';
489
+ bls12_381.G1.hashToCurve(randomBytes(), { DST: 'another' });
490
+ bls12_381.G2.hashToCurve(randomBytes(), { DST: 'custom' });
303
491
  ```
304
492
 
305
- `weierstrass()` returns `CurveFn`:
493
+ If you need low-level methods from spec:
494
+
495
+ `expand_message_xmd` [(spec)](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.4.1) produces a uniformly random byte string using a cryptographic hash function H that outputs b bits.
306
496
 
307
497
  ```ts
308
- export type CurveFn = {
309
- CURVE: ReturnType<typeof validateOpts>;
310
- getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
311
- getSharedSecret: (privateA: PrivKey, publicB: Hex, isCompressed?: boolean) => Uint8Array;
312
- sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) => SignatureType;
313
- verify: (
314
- signature: Hex | SignatureType,
315
- msgHash: Hex,
316
- publicKey: Hex,
317
- opts?: { lowS?: boolean }
318
- ) => boolean;
319
- Point: PointConstructor;
320
- ProjectivePoint: ProjectivePointConstructor;
321
- Signature: SignatureConstructor;
322
- utils: {
323
- isValidPrivateKey(privateKey: PrivKey): boolean;
324
- hashToPrivateKey: (hash: Hex) => Uint8Array;
325
- randomPrivateKey: () => Uint8Array;
326
- };
327
- };
498
+ function expand_message_xmd(
499
+ msg: Uint8Array,
500
+ DST: Uint8Array,
501
+ lenInBytes: number,
502
+ H: CHash
503
+ ): Uint8Array;
504
+ function expand_message_xof(
505
+ msg: Uint8Array,
506
+ DST: Uint8Array,
507
+ lenInBytes: number,
508
+ k: number,
509
+ H: CHash
510
+ ): Uint8Array;
328
511
  ```
329
512
 
330
- ### abstract/hash-to-curve: Hashing strings to curve points
513
+ `hash_to_field(msg, count, options)` [(spec)](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3)
514
+ hashes arbitrary-length byte strings to a list of one or more elements of a finite field F.
515
+ _ `msg` a byte string containing the message to hash
516
+ _ `count` the number of elements of F to output
517
+ _ `options` `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`
518
+ _ Returns `[u_0, ..., u_(count - 1)]`, a list of field elements.
331
519
 
332
- The module allows to hash arbitrary strings to elliptic curve points.
333
-
334
- - `expand_message_xmd` [(spec)](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.4.1) produces a uniformly random byte string using a cryptographic hash function H that outputs b bits..
335
-
336
- ```ts
337
- function expand_message_xmd(
338
- msg: Uint8Array,
339
- DST: Uint8Array,
340
- lenInBytes: number,
341
- H: CHash
342
- ): Uint8Array;
343
- function expand_message_xof(
344
- msg: Uint8Array,
345
- DST: Uint8Array,
346
- lenInBytes: number,
347
- k: number,
348
- H: CHash
349
- ): Uint8Array;
350
- ```
351
-
352
- - `hash_to_field(msg, count, options)` [(spec)](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3)
353
- hashes arbitrary-length byte strings to a list of one or more elements of a finite field F.
354
- _ `msg` a byte string containing the message to hash
355
- _ `count` the number of elements of F to output
356
- _ `options` `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`
357
- _ Returns `[u_0, ..., u_(count - 1)]`, a list of field elements.
358
-
359
- ```ts
360
- function hash_to_field(msg: Uint8Array, count: number, options: htfOpts): bigint[][];
361
- type htfOpts = {
362
- // DST: a domain separation tag
363
- // defined in section 2.2.5
364
- DST: string;
365
- // p: the characteristic of F
366
- // where F is a finite field of characteristic p and order q = p^m
367
- p: bigint;
368
- // m: the extension degree of F, m >= 1
369
- // where F is a finite field of characteristic p and order q = p^m
370
- m: number;
371
- // k: the target security level for the suite in bits
372
- // defined in section 5.1
373
- k: number;
374
- // option to use a message that has already been processed by
375
- // expand_message_xmd
376
- expand?: 'xmd' | 'xof';
377
- // Hash functions for: expand_message_xmd is appropriate for use with a
378
- // wide range of hash functions, including SHA-2, SHA-3, BLAKE2, and others.
379
- // BBS+ uses blake2: https://github.com/hyperledger/aries-framework-go/issues/2247
380
- // TODO: verify that hash is shake if expand==='xof' via types
381
- hash: CHash;
382
- };
383
- ```
520
+ ```ts
521
+ function hash_to_field(msg: Uint8Array, count: number, options: htfOpts): bigint[][];
522
+ ```
384
523
 
385
524
  ### abstract/poseidon: Poseidon hash
386
525
 
387
526
  Implements [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash.
388
527
 
389
- There are many poseidon instances with different constants. We don't provide them,
390
- but we provide ability to specify them manually. For actual usage, check out
391
- stark curve source code.
528
+ There are many poseidon variants with different constants.
529
+ We don't provide them: you should construct them manually.
530
+ The only variant provided resides in `stark` module: inspect it for proper usage.
392
531
 
393
532
  ```ts
394
533
  import { poseidon } from '@noble/curves/abstract/poseidon';
@@ -406,27 +545,54 @@ type PoseidonOpts = {
406
545
  const instance = poseidon(opts: PoseidonOpts);
407
546
  ```
408
547
 
409
- ### abstract/modular
548
+ ### abstract/bls
410
549
 
411
- Modular arithmetics utilities.
550
+ The module abstracts BLS (Barreto-Lynn-Scott) primitives. In theory you should be able to write BLS12-377, BLS24,
551
+ and others with it.
412
552
 
413
- ```typescript
414
- import { Fp, mod, invert, div, invertBatch, sqrt } from '@noble/curves/abstract/modular';
415
- const fp = Fp(2n ** 255n - 19n); // Finite field over 2^255-19
416
- fp.mul(591n, 932n);
417
- fp.pow(481n, 11024858120n);
553
+ ### abstract/modular: Modular arithmetics utilities
554
+
555
+ ```ts
556
+ import * as mod from '@noble/curves/abstract/modular';
557
+ const fp = mod.Field(2n ** 255n - 19n); // Finite field over 2^255-19
558
+ fp.mul(591n, 932n); // multiplication
559
+ fp.pow(481n, 11024858120n); // exponentiation
560
+ fp.div(5n, 17n); // division: 5/17 mod 2^255-19 == 5 * invert(17)
561
+ fp.sqrt(21n); // square root
418
562
 
419
563
  // Generic non-FP utils are also available
420
- mod(21n, 10n); // 21 mod 10 == 1n; fixed version of 21 % 10
421
- invert(17n, 10n); // invert(17) mod 10; modular multiplicative inverse
422
- div(5n, 17n, 10n); // 5/17 mod 10 == 5 * invert(17) mod 10; division
423
- invertBatch([1n, 2n, 4n], 21n); // => [1n, 11n, 16n] in one inversion
424
- sqrt(21n, 73n); // √21 mod 73; square root
564
+ mod.mod(21n, 10n); // 21 mod 10 == 1n; fixed version of 21 % 10
565
+ mod.invert(17n, 10n); // invert(17) mod 10; modular multiplicative inverse
566
+ mod.invertBatch([1n, 2n, 4n], 21n); // => [1n, 11n, 16n] in one inversion
425
567
  ```
426
568
 
427
- ### abstract/utils
569
+ #### Creating private keys from hashes
428
570
 
429
- ```typescript
571
+ Suppose you have `sha256(something)` (e.g. from HMAC) and you want to make a private key from it.
572
+ Even though p256 or secp256k1 may have 32-byte private keys,
573
+ and sha256 output is also 32-byte, you can't just use it and reduce it modulo `CURVE.n`.
574
+
575
+ Doing so will make the result key [biased](https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/).
576
+
577
+ To avoid the bias, we implement FIPS 186 B.4.1, which allows to take arbitrary
578
+ byte array and produce valid scalars / private keys with bias being neglible.
579
+
580
+ Use [hash-to-curve](#abstracthash-to-curve-hashing-strings-to-curve-points) if you need
581
+ hashing to **public keys**; the function in the module instead operates on **private keys**.
582
+
583
+ ```ts
584
+ import { p256 } from '@noble/curves/p256';
585
+ import { sha256 } from '@noble/hashes/sha256';
586
+ import { hkdf } from '@noble/hashes/hkdf';
587
+ const someKey = new Uint8Array(32).fill(2); // Needs to actually be random, not .fill(2)
588
+ const derived = hkdf(sha256, someKey, undefined, 'application', 40); // 40 bytes
589
+ const validPrivateKey = mod.hashToPrivateScalar(derived, p256.CURVE.n);
590
+ ```
591
+
592
+
593
+ ### abstract/utils: General utilities
594
+
595
+ ```ts
430
596
  import * as utils from '@noble/curves/abstract/utils';
431
597
 
432
598
  utils.bytesToHex(Uint8Array.from([0xde, 0xad, 0xbe, 0xef]));
@@ -434,12 +600,11 @@ utils.hexToBytes('deadbeef');
434
600
  utils.hexToNumber();
435
601
  utils.bytesToNumberBE(Uint8Array.from([0xde, 0xad, 0xbe, 0xef]));
436
602
  utils.bytesToNumberLE(Uint8Array.from([0xde, 0xad, 0xbe, 0xef]));
437
- utils.numberToBytesBE(123n);
438
- utils.numberToBytesLE(123n);
603
+ utils.numberToBytesBE(123n, 32);
604
+ utils.numberToBytesLE(123n, 64);
439
605
  utils.numberToHexUnpadded(123n);
440
606
  utils.concatBytes(Uint8Array.from([0xde, 0xad]), Uint8Array.from([0xbe, 0xef]));
441
607
  utils.nLength(255n);
442
- utils.hashToPrivateScalar(sha512_of_something, secp256r1.n);
443
608
  utils.equalBytes(Uint8Array.from([0xde]), Uint8Array.from([0xde]));
444
609
  ```
445
610
 
@@ -447,80 +612,103 @@ utils.equalBytes(Uint8Array.from([0xde]), Uint8Array.from([0xde]));
447
612
 
448
613
  The library had no prior security audit.
449
614
 
450
- [Timing attack](https://en.wikipedia.org/wiki/Timing_attack) considerations: _JIT-compiler_ and _Garbage Collector_ make "constant time" extremely hard to achieve in a scripting language. Which means _any other JS library can't have constant-timeness_. Even statically typed Rust, a language without GC, [makes it harder to achieve constant-time](https://www.chosenplaintext.ca/open-source/rust-timing-shield/security) for some cases. If your goal is absolute security, don't use any JS lib — including bindings to native ones. Use low-level libraries & languages. Nonetheless we're targetting algorithmic constant time.
615
+ [Timing attack](https://en.wikipedia.org/wiki/Timing_attack) considerations: we are using non-CT bigints. However, _JIT-compiler_ and _Garbage Collector_ make "constant time" extremely hard to achieve in a scripting language. Which means _any other JS library can't have constant-timeness_. Even statically typed Rust, a language without GC, [makes it harder to achieve constant-time](https://www.chosenplaintext.ca/open-source/rust-timing-shield/security) for some cases. If your goal is absolute security, don't use any JS lib — including bindings to native ones. Use low-level libraries & languages. Nonetheless we're targetting algorithmic constant time.
616
+
617
+ We consider infrastructure attacks like rogue NPM modules very important; that's why it's crucial to minimize the amount of 3rd-party dependencies & native bindings. If your app uses 500 dependencies, any dep could get hacked and you'll be downloading malware with every `npm install`. Our goal is to minimize this attack vector. As for devDependencies used by the library:
451
618
 
452
- We consider infrastructure attacks like rogue NPM modules very important; that's why it's crucial to minimize the amount of 3rd-party dependencies & native bindings. If your app uses 500 dependencies, any dep could get hacked and you'll be downloading malware with every `npm install`. Our goal is to minimize this attack vector.
619
+ - `@scure` base, bip32, bip39 (used in tests), micro-bmark (benchmark), micro-should (testing) are developed by us
620
+ and follow the same practices such as: minimal library size, auditability, signed releases
621
+ - prettier (linter), fast-check (property-based testing),
622
+ typescript versions are locked and rarely updated. Every update is checked with `npm-diff`.
623
+ The packages are big, which makes it hard to audit their source code thoroughly and fully.
624
+ - They are only used if you clone the git repo and want to add some feature to it. End-users won't use them.
453
625
 
454
626
  ## Speed
455
627
 
456
- Benchmark results on Apple M2 with node v18.10:
628
+ Benchmark results on Apple M2 with node v19:
457
629
 
458
630
  ```
459
631
  secp256k1
460
- init x 57 ops/sec @ 17ms/op
461
- getPublicKey x 4,946 ops/sec @ 202μs/op
462
- sign x 3,914 ops/sec @ 255μs/op
463
- verify x 682 ops/sec @ 1ms/op
464
- getSharedSecret x 427 ops/sec @ 2ms/op
465
- recoverPublicKey x 683 ops/sec @ 1ms/op
466
- schnorr.sign x 539 ops/sec @ 1ms/op
467
- schnorr.verify x 716 ops/sec @ 1ms/op
632
+ init x 58 ops/sec @ 17ms/op
633
+ getPublicKey x 5,640 ops/sec @ 177μs/op
634
+ sign x 3,909 ops/sec @ 255μs/op
635
+ verify x 780 ops/sec @ 1ms/op
636
+ getSharedSecret x 465 ops/sec @ 2ms/op
637
+ recoverPublicKey x 740 ops/sec @ 1ms/op
638
+ schnorr.sign x 597 ops/sec @ 1ms/op
639
+ schnorr.verify x 775 ops/sec @ 1ms/op
468
640
 
469
641
  P256
470
- init x 30 ops/sec @ 32ms/op
471
- getPublicKey x 5,008 ops/sec @ 199μs/op
472
- sign x 3,970 ops/sec @ 251μs/op
473
- verify x 515 ops/sec @ 1ms/op
642
+ init x 31 ops/sec @ 31ms/op
643
+ getPublicKey x 5,607 ops/sec @ 178μs/op
644
+ sign x 3,930 ops/sec @ 254μs/op
645
+ verify x 540 ops/sec @ 1ms/op
474
646
 
475
647
  P384
476
- init x 14 ops/sec @ 66ms/op
477
- getPublicKey x 2,434 ops/sec @ 410μs/op
478
- sign x 1,942 ops/sec @ 514μs/op
479
- verify x 206 ops/sec @ 4ms/op
648
+ init x 15 ops/sec @ 63ms/op
649
+ getPublicKey x 2,622 ops/sec @ 381μs/op
650
+ sign x 1,913 ops/sec @ 522μs/op
651
+ verify x 222 ops/sec @ 4ms/op
480
652
 
481
653
  P521
482
- init x 7 ops/sec @ 126ms/op
483
- getPublicKey x 1,282 ops/sec @ 779μs/op
484
- sign x 1,077 ops/sec @ 928μs/op
485
- verify x 110 ops/sec @ 9ms/op
654
+ init x 8 ops/sec @ 119ms/op
655
+ getPublicKey x 1,371 ops/sec @ 729μs/op
656
+ sign x 1,090 ops/sec @ 917μs/op
657
+ verify x 118 ops/sec @ 8ms/op
486
658
 
487
659
  ed25519
488
- init x 37 ops/sec @ 26ms/op
489
- getPublicKey x 8,147 ops/sec @ 122μs/op
490
- sign x 3,979 ops/sec @ 251μs/op
491
- verify x 848 ops/sec @ 1ms/op
660
+ init x 47 ops/sec @ 20ms/op
661
+ getPublicKey x 9,414 ops/sec @ 106μs/op
662
+ sign x 4,516 ops/sec @ 221μs/op
663
+ verify x 912 ops/sec @ 1ms/op
492
664
 
493
665
  ed448
494
- init x 17 ops/sec @ 58ms/op
495
- getPublicKey x 3,083 ops/sec @ 324μs/op
496
- sign x 1,473 ops/sec @ 678μs/op
497
- verify x 323 ops/sec @ 3ms/op
498
-
499
- bls12-381
500
- init x 30 ops/sec @ 33ms/op
501
- getPublicKey x 788 ops/sec @ 1ms/op
502
- sign x 45 ops/sec @ 21ms/op
503
- verify x 32 ops/sec @ 30ms/op
504
- pairing x 88 ops/sec @ 11ms/op
666
+ init x 17 ops/sec @ 56ms/op
667
+ getPublicKey x 3,363 ops/sec @ 297μs/op
668
+ sign x 1,615 ops/sec @ 619μs/op
669
+ verify x 319 ops/sec @ 3ms/op
505
670
 
506
671
  stark
507
- init x 31 ops/sec @ 31ms/op
508
- pedersen
509
- ├─old x 84 ops/sec @ 11ms/op
510
- └─noble x 802 ops/sec @ 1ms/op
511
- poseidon x 7,466 ops/sec @ 133μs/op
512
- verify
513
- ├─old x 300 ops/sec @ 3ms/op
514
- └─noble x 474 ops/sec @ 2ms/op
672
+ init x 35 ops/sec @ 28ms/op
673
+ pedersen x 884 ops/sec @ 1ms/op
674
+ poseidon x 8,598 ops/sec @ 116μs/op
675
+ verify x 528 ops/sec @ 1ms/op
676
+
677
+ bls12-381
678
+ init x 32 ops/sec @ 30ms/op
679
+ getPublicKey 1-bit x 858 ops/sec @ 1ms/op
680
+ getPublicKey x 858 ops/sec @ 1ms/op
681
+ sign x 49 ops/sec @ 20ms/op
682
+ verify x 34 ops/sec @ 28ms/op
683
+ pairing x 94 ops/sec @ 10ms/op
684
+ aggregatePublicKeys/8 x 116 ops/sec @ 8ms/op
685
+ aggregatePublicKeys/32 x 31 ops/sec @ 31ms/op
686
+ aggregatePublicKeys/128 x 7 ops/sec @ 125ms/op
687
+ aggregateSignatures/8 x 45 ops/sec @ 22ms/op
688
+ aggregateSignatures/32 x 11 ops/sec @ 84ms/op
689
+ aggregateSignatures/128 x 3 ops/sec @ 332ms/opp
515
690
  ```
516
691
 
692
+ ## Resources
693
+
694
+ Article about some of library's features: [Learning fast elliptic-curve cryptography](https://paulmillr.com/posts/noble-secp256k1-fast-ecc/). Elliptic curve calculator: [paulmillr.com/ecc](https://paulmillr.com/ecc)
695
+
696
+ - secp256k1
697
+ - [btc-signer](https://github.com/paulmillr/micro-btc-signer), [eth-signer](https://github.com/paulmillr/micro-eth-signer)
698
+ - ed25519
699
+ - [sol-signer](https://github.com/paulmillr/micro-sol-signer)
700
+ - BLS12-381
701
+ - Check out `bls12-381.ts` for articles about the curve
702
+ - Threshold sigs demo [genthresh.com](https://genthresh.com)
703
+ - BBS signatures [github.com/Wind4Greg/BBS-Draft-Checks](https://github.com/Wind4Greg/BBS-Draft-Checks) following [draft-irtf-cfrg-bbs-signatures-latest](https://identity.foundation/bbs-signature/draft-irtf-cfrg-bbs-signatures.html)
704
+
517
705
  ## Upgrading
518
706
 
519
- If you're coming from single-curve noble packages, the following changes need to be kept in mind:
707
+ If you're coming from single-feature noble packages, the following changes need to be kept in mind:
520
708
 
521
709
  - 2d affine (x, y) points have been removed to reduce complexity and improve speed
522
- - Removed `number` support as a type for private keys. `bigint` is still supported
523
- - `mod`, `invert` are no longer present in `utils`. Use `@noble/curves/abstract/modular.js` now.
710
+ - Removed `number` support as a type for private keys, `bigint` is still supported
711
+ - `mod`, `invert` are no longer present in `utils`: use `@noble/curves/abstract/modular`
524
712
 
525
713
  Upgrading from @noble/secp256k1 1.7:
526
714