@noble/curves 1.0.0 → 1.2.0
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.
- package/README.md +399 -247
- package/_shortw_utils.d.ts +1 -1
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +2 -2
- package/abstract/bls.js.map +1 -1
- package/abstract/edwards.d.ts +7 -2
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +7 -2
- package/abstract/edwards.js.map +1 -1
- package/abstract/hash-to-curve.d.ts +1 -1
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +14 -8
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.d.ts +55 -13
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +82 -22
- package/abstract/modular.js.map +1 -1
- package/abstract/poseidon.d.ts.map +1 -1
- package/abstract/poseidon.js +39 -41
- package/abstract/poseidon.js.map +1 -1
- package/abstract/utils.d.ts +43 -5
- package/abstract/utils.d.ts.map +1 -1
- package/abstract/utils.js +70 -26
- package/abstract/utils.js.map +1 -1
- package/abstract/weierstrass.d.ts +18 -2
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +40 -22
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +11 -11
- package/bls12-381.js.map +1 -1
- package/ed25519.d.ts +33 -20
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +60 -38
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +53 -4
- package/ed448.d.ts.map +1 -1
- package/ed448.js +217 -38
- package/ed448.js.map +1 -1
- package/esm/abstract/bls.js +3 -3
- package/esm/abstract/bls.js.map +1 -1
- package/esm/abstract/edwards.js +7 -2
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/hash-to-curve.js +14 -8
- package/esm/abstract/hash-to-curve.js.map +1 -1
- package/esm/abstract/modular.js +78 -21
- package/esm/abstract/modular.js.map +1 -1
- package/esm/abstract/poseidon.js +39 -41
- package/esm/abstract/poseidon.js.map +1 -1
- package/esm/abstract/utils.js +70 -26
- package/esm/abstract/utils.js.map +1 -1
- package/esm/abstract/weierstrass.js +40 -22
- package/esm/abstract/weierstrass.js.map +1 -1
- package/esm/bls12-381.js +11 -11
- package/esm/bls12-381.js.map +1 -1
- package/esm/ed25519.js +60 -38
- package/esm/ed25519.js.map +1 -1
- package/esm/ed448.js +217 -38
- package/esm/ed448.js.map +1 -1
- package/esm/jubjub.js +1 -1
- package/esm/jubjub.js.map +1 -1
- package/esm/p256.js +10 -9
- package/esm/p256.js.map +1 -1
- package/esm/p384.js +7 -6
- package/esm/p384.js.map +1 -1
- package/esm/p521.js +7 -6
- package/esm/p521.js.map +1 -1
- package/esm/package.json +1 -4
- package/esm/secp256k1.js +11 -9
- package/esm/secp256k1.js.map +1 -1
- package/jubjub.js.map +1 -1
- package/p256.d.ts +4 -5
- package/p256.d.ts.map +1 -1
- package/p256.js +10 -10
- package/p256.js.map +1 -1
- package/p384.d.ts +4 -5
- package/p384.d.ts.map +1 -1
- package/p384.js +7 -7
- package/p384.js.map +1 -1
- package/p521.d.ts +4 -5
- package/p521.d.ts.map +1 -1
- package/p521.js +7 -7
- package/p521.js.map +1 -1
- package/package.json +7 -9
- package/secp256k1.d.ts +5 -5
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +11 -10
- package/secp256k1.js.map +1 -1
- package/src/abstract/bls.ts +3 -3
- package/src/abstract/edwards.ts +13 -4
- package/src/abstract/hash-to-curve.ts +14 -8
- package/src/abstract/modular.ts +84 -27
- package/src/abstract/poseidon.ts +39 -40
- package/src/abstract/utils.ts +77 -33
- package/src/abstract/weierstrass.ts +51 -29
- package/src/bls12-381.ts +12 -17
- package/src/ed25519.ts +105 -75
- package/src/ed448.ts +286 -64
- package/src/jubjub.ts +1 -1
- package/src/p256.ts +13 -14
- package/src/p384.ts +12 -13
- package/src/p521.ts +12 -13
- package/src/secp256k1.ts +60 -55
package/README.md
CHANGED
|
@@ -5,73 +5,83 @@ Audited & minimal JS implementation of elliptic curve cryptography.
|
|
|
5
5
|
- 🔒 [**Audited**](#security) by an independent security firm
|
|
6
6
|
- 🔻 Tree-shaking-friendly: use only what's necessary, other code won't be included
|
|
7
7
|
- 🏎 Ultra-fast, hand-optimized for caveats of JS engines
|
|
8
|
-
- 🔍 Unique tests ensure correctness: property-based, cross-library and Wycheproof vectors, fuzzing
|
|
8
|
+
- 🔍 Unique tests ensure correctness: property-based, cross-library and Wycheproof vectors, fuzzing
|
|
9
9
|
- ➰ Short Weierstrass, Edwards, Montgomery curves
|
|
10
10
|
- ✍️ ECDSA, EdDSA, Schnorr, BLS signature schemes, ECDH key agreement
|
|
11
|
-
-
|
|
12
|
-
|
|
11
|
+
- 🔖 SUF-CMA and SBS (non-repudiation) for ed25519, ed448 and others
|
|
12
|
+
- #️⃣ hash-to-curve for encoding or hashing an arbitrary string to an elliptic curve point
|
|
13
13
|
- 🧜♂️ Poseidon ZK-friendly hash
|
|
14
14
|
|
|
15
|
-
Check out [Upgrading](#upgrading) if you've previously used single-feature noble
|
|
16
|
-
packages. See [Resources](#resources) for articles and real-world software that uses curves.
|
|
17
|
-
|
|
18
15
|
### This library belongs to _noble_ crypto
|
|
19
16
|
|
|
20
17
|
> **noble-crypto** — high-security, easily auditable set of contained cryptographic libraries and tools.
|
|
21
18
|
|
|
22
19
|
- No dependencies, protection against supply chain attacks
|
|
23
20
|
- Auditable TypeScript / JS code
|
|
24
|
-
- Supported
|
|
25
|
-
-
|
|
21
|
+
- Supported on all major platforms
|
|
22
|
+
- Releases are signed with PGP keys and built transparently with NPM provenance
|
|
26
23
|
- Check out [homepage](https://paulmillr.com/noble/) & all libraries:
|
|
27
|
-
[
|
|
28
|
-
|
|
29
|
-
[
|
|
30
|
-
[
|
|
24
|
+
[ciphers](https://github.com/paulmillr/noble-ciphers),
|
|
25
|
+
[curves](https://github.com/paulmillr/noble-curves),
|
|
26
|
+
[hashes](https://github.com/paulmillr/noble-hashes),
|
|
27
|
+
4kb [secp256k1](https://github.com/paulmillr/noble-secp256k1) /
|
|
28
|
+
[ed25519](https://github.com/paulmillr/noble-ed25519)
|
|
31
29
|
|
|
32
30
|
## Usage
|
|
33
31
|
|
|
34
|
-
Browser, deno and node.js are supported:
|
|
35
|
-
|
|
36
32
|
> npm install @noble/curves
|
|
37
33
|
|
|
38
|
-
|
|
39
|
-
[npm specifier](https://deno.land/manual@v1.28.0/node/npm_specifiers).
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
34
|
+
We support all major platforms and runtimes.
|
|
35
|
+
For [Deno](https://deno.land), ensure to use [npm specifier](https://deno.land/manual@v1.28.0/node/npm_specifiers).
|
|
36
|
+
For React Native, you may need a [polyfill for crypto.getRandomValues](https://github.com/LinusU/react-native-get-random-values).
|
|
37
|
+
If you don't like NPM, a standalone [noble-curves.js](https://github.com/paulmillr/noble-curves/releases) is also available.
|
|
38
|
+
|
|
39
|
+
- [Implementations](#implementations)
|
|
40
|
+
- [ECDSA signature scheme](#ecdsa-signature-scheme)
|
|
41
|
+
- [ECDSA public key recovery & extra entropy](#ecdsa-public-key-recovery--extra-entropy)
|
|
42
|
+
- [ECDH (Elliptic Curve Diffie-Hellman)](#ecdh-elliptic-curve-diffie-hellman)
|
|
43
|
+
- [Schnorr signatures over secp256k1, BIP340](#schnorr-signatures-over-secp256k1-bip340)
|
|
44
|
+
- [ed25519, X25519, ristretto255](#ed25519-x25519-ristretto255)
|
|
45
|
+
- [ed448, X448, decaf448](#ed448-x448-decaf448)
|
|
46
|
+
- [bls12-381](#bls12-381)
|
|
47
|
+
- [All available imports](#all-available-imports)
|
|
48
|
+
- [Accessing a curve's variables](#accessing-a-curves-variables)
|
|
49
|
+
- [Abstract API](#abstract-api)
|
|
50
|
+
- [abstract/weierstrass: Short Weierstrass curve](#abstractweierstrass-short-weierstrass-curve)
|
|
51
|
+
- [abstract/edwards: Twisted Edwards curve](#abstractedwards-twisted-edwards-curve)
|
|
52
|
+
- [abstract/montgomery: Montgomery curve](#abstractmontgomery-montgomery-curve)
|
|
53
|
+
- [abstract/bls: Barreto-Lynn-Scott curves](#abstractbls-barreto-lynn-scott-curves)
|
|
54
|
+
- [abstract/hash-to-curve: Hashing strings to curve points](#abstracthash-to-curve-hashing-strings-to-curve-points)
|
|
55
|
+
- [abstract/poseidon: Poseidon hash](#abstractposeidon-poseidon-hash)
|
|
56
|
+
- [abstract/modular: Modular arithmetics utilities](#abstractmodular-modular-arithmetics-utilities)
|
|
57
|
+
- [Creating private keys from hashes](#creating-private-keys-from-hashes)
|
|
58
|
+
- [abstract/utils: Useful utilities](#abstractutils-useful-utilities)
|
|
59
|
+
- [Security](#security)
|
|
60
|
+
- [Speed](#speed)
|
|
61
|
+
- [Contributing & testing](#contributing--testing)
|
|
62
|
+
- [Upgrading](#upgrading)
|
|
63
|
+
- [Resources](#resources)
|
|
64
|
+
- [Demos](#demos)
|
|
65
|
+
- [Projects using curves](#projects-using-curves)
|
|
66
|
+
- [License](#license)
|
|
63
67
|
|
|
64
68
|
### Implementations
|
|
65
69
|
|
|
66
|
-
|
|
70
|
+
Implementations are utilizing [noble-hashes](https://github.com/paulmillr/noble-hashes).
|
|
71
|
+
[Abstract API](#abstract-api) doesn't depend on them: you can use a different hashing library.
|
|
72
|
+
|
|
73
|
+
#### ECDSA signature scheme
|
|
74
|
+
|
|
75
|
+
Generic example that works for all curves, shown for secp256k1:
|
|
67
76
|
|
|
68
77
|
```ts
|
|
78
|
+
// import * from '@noble/curves'; // Error: use sub-imports, to ensure small app size
|
|
69
79
|
import { secp256k1 } from '@noble/curves/secp256k1'; // ESM and Common.js
|
|
70
80
|
// import { secp256k1 } from 'npm:@noble/curves@1.2.0/secp256k1'; // Deno
|
|
71
81
|
const priv = secp256k1.utils.randomPrivateKey();
|
|
72
82
|
const pub = secp256k1.getPublicKey(priv);
|
|
73
|
-
const msg = new Uint8Array(32).fill(1);
|
|
74
|
-
const sig = secp256k1.sign(msg, priv);
|
|
83
|
+
const msg = new Uint8Array(32).fill(1); // message hash (not message) in ecdsa
|
|
84
|
+
const sig = secp256k1.sign(msg, priv); // `{prehash: true}` option is available
|
|
75
85
|
const isValid = secp256k1.verify(sig, msg, pub) === true;
|
|
76
86
|
|
|
77
87
|
// hex strings are also supported besides Uint8Arrays:
|
|
@@ -79,33 +89,25 @@ const privHex = '46c930bc7bb4db7f55da20798697421b98c4175a52c630294d75a84b9c12623
|
|
|
79
89
|
const pub2 = secp256k1.getPublicKey(privHex);
|
|
80
90
|
```
|
|
81
91
|
|
|
82
|
-
|
|
92
|
+
#### ECDSA public key recovery & extra entropy
|
|
83
93
|
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
import { p384 } from '@noble/curves/p384';
|
|
90
|
-
import { p521 } from '@noble/curves/p521';
|
|
91
|
-
import { pallas, vesta } from '@noble/curves/pasta';
|
|
92
|
-
import { bls12_381 } from '@noble/curves/bls12-381';
|
|
93
|
-
import { bn254 } from '@noble/curves/bn254';
|
|
94
|
-
import { jubjub } from '@noble/curves/jubjub';
|
|
94
|
+
```ts
|
|
95
|
+
sig.recoverPublicKey(msg).toRawBytes(); // === pub; // public key recovery
|
|
96
|
+
|
|
97
|
+
// extraEntropy https://moderncrypto.org/mail-archive/curves/2017/000925.html
|
|
98
|
+
const sigImprovedSecurity = secp256k1.sign(msg, priv, { extraEntropy: true });
|
|
95
99
|
```
|
|
96
100
|
|
|
97
|
-
|
|
101
|
+
#### ECDH (Elliptic Curve Diffie-Hellman)
|
|
98
102
|
|
|
99
103
|
```ts
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
sig.recoverPublicKey(msg) === pub; // public key recovery
|
|
104
|
+
// 1. The output includes parity byte. Strip it using shared.slice(1)
|
|
105
|
+
// 2. The output is not hashed. More secure way is sha256(shared) or hkdf(shared)
|
|
103
106
|
const someonesPub = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
|
|
104
|
-
const shared = secp256k1.getSharedSecret(priv, someonesPub);
|
|
107
|
+
const shared = secp256k1.getSharedSecret(priv, someonesPub);
|
|
105
108
|
```
|
|
106
109
|
|
|
107
|
-
Schnorr signatures over secp256k1
|
|
108
|
-
[BIP340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki):
|
|
110
|
+
#### Schnorr signatures over secp256k1 (BIP340)
|
|
109
111
|
|
|
110
112
|
```ts
|
|
111
113
|
import { schnorr } from '@noble/curves/secp256k1';
|
|
@@ -116,12 +118,7 @@ const sig = schnorr.sign(msg, priv);
|
|
|
116
118
|
const isValid = schnorr.verify(sig, msg, pub);
|
|
117
119
|
```
|
|
118
120
|
|
|
119
|
-
ed25519
|
|
120
|
-
x25519 ECDH and [ristretto255](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448).
|
|
121
|
-
|
|
122
|
-
Default `verify` behavior follows [ZIP215](https://zips.z.cash/zip-0215) and
|
|
123
|
-
[can be used in consensus-critical applications](https://hdevalence.ca/blog/2020-10-04-its-25519am).
|
|
124
|
-
`zip215: false` option switches verification criteria to RFC8032 / FIPS 186-5.
|
|
121
|
+
#### ed25519, X25519, ristretto255
|
|
125
122
|
|
|
126
123
|
```ts
|
|
127
124
|
import { ed25519 } from '@noble/curves/ed25519';
|
|
@@ -131,7 +128,18 @@ const msg = new TextEncoder().encode('hello');
|
|
|
131
128
|
const sig = ed25519.sign(msg, priv);
|
|
132
129
|
ed25519.verify(sig, msg, pub); // Default mode: follows ZIP215
|
|
133
130
|
ed25519.verify(sig, msg, pub, { zip215: false }); // RFC8032 / FIPS 186-5
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Default `verify` behavior follows [ZIP215](https://zips.z.cash/zip-0215) and
|
|
134
|
+
[can be used in consensus-critical applications](https://hdevalence.ca/blog/2020-10-04-its-25519am).
|
|
135
|
+
It has SUF-CMA (strong unforgeability under chosen message attacks).
|
|
136
|
+
`zip215: false` option switches verification criteria to strict
|
|
137
|
+
[RFC8032](https://www.rfc-editor.org/rfc/rfc8032) / [FIPS 186-5](https://csrc.nist.gov/publications/detail/fips/186/5/final)
|
|
138
|
+
and additionally provides non-repudiation with SBS [(Strongly Binding Signatures)](https://eprint.iacr.org/2020/1244).
|
|
139
|
+
|
|
140
|
+
X25519 follows [RFC7748](https://www.rfc-editor.org/rfc/rfc7748).
|
|
134
141
|
|
|
142
|
+
```ts
|
|
135
143
|
// Variants from RFC8032: with context, prehashed
|
|
136
144
|
import { ed25519ctx, ed25519ph } from '@noble/curves/ed25519';
|
|
137
145
|
|
|
@@ -141,31 +149,119 @@ const priv = 'a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4';
|
|
|
141
149
|
const pub = 'e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c';
|
|
142
150
|
x25519.getSharedSecret(priv, pub) === x25519.scalarMult(priv, pub); // aliases
|
|
143
151
|
x25519.getPublicKey(priv) === x25519.scalarMultBase(priv);
|
|
152
|
+
x25519.getPublicKey(x25519.utils.randomPrivateKey());
|
|
153
|
+
|
|
154
|
+
// ed25519 => x25519 conversion
|
|
155
|
+
import { edwardsToMontgomeryPub, edwardsToMontgomeryPriv } from '@noble/curves/ed25519';
|
|
156
|
+
edwardsToMontgomeryPub(ed25519.getPublicKey(ed25519.utils.randomPrivateKey()));
|
|
157
|
+
edwardsToMontgomeryPriv(ed25519.utils.randomPrivateKey());
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
ristretto255 follows [irtf draft](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448).
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
// hash-to-curve, ristretto255
|
|
164
|
+
import { utf8ToBytes } from '@noble/hashes/utils';
|
|
165
|
+
import { sha512 } from '@noble/hashes/sha512';
|
|
166
|
+
import {
|
|
167
|
+
hashToCurve,
|
|
168
|
+
encodeToCurve,
|
|
169
|
+
RistrettoPoint,
|
|
170
|
+
hashToRistretto255,
|
|
171
|
+
} from '@noble/curves/ed25519';
|
|
144
172
|
|
|
145
|
-
|
|
146
|
-
|
|
173
|
+
const msg = utf8ToBytes('Ristretto is traditionally a short shot of espresso coffee');
|
|
174
|
+
hashToCurve(msg);
|
|
147
175
|
|
|
148
|
-
import { RistrettoPoint } from '@noble/curves/ed25519';
|
|
149
176
|
const rp = RistrettoPoint.fromHex(
|
|
150
177
|
'6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919'
|
|
151
178
|
);
|
|
152
|
-
RistrettoPoint.
|
|
153
|
-
|
|
179
|
+
RistrettoPoint.BASE.multiply(2n).add(rp).subtract(RistrettoPoint.BASE).toRawBytes();
|
|
180
|
+
RistrettoPoint.ZERO.equals(dp) === false;
|
|
181
|
+
// pre-hashed hash-to-curve
|
|
182
|
+
RistrettoPoint.hashToCurve(sha512(msg));
|
|
183
|
+
// full hash-to-curve including domain separation tag
|
|
184
|
+
hashToRistretto255(msg, { DST: 'ristretto255_XMD:SHA-512_R255MAP_RO_' });
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
#### ed448, X448, decaf448
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
import { ed448 } from '@noble/curves/ed448';
|
|
191
|
+
const priv = ed448.utils.randomPrivateKey();
|
|
192
|
+
const pub = ed448.getPublicKey(priv);
|
|
193
|
+
const msg = new TextEncoder().encode('whatsup');
|
|
194
|
+
const sig = ed448.sign(msg, priv);
|
|
195
|
+
ed448.verify(sig, msg, pub);
|
|
196
|
+
|
|
197
|
+
// Variants from RFC8032: prehashed
|
|
198
|
+
import { ed448ph } from '@noble/curves/ed448';
|
|
154
199
|
```
|
|
155
200
|
|
|
156
|
-
|
|
201
|
+
ECDH using Curve448 aka X448, follows [RFC7748](https://www.rfc-editor.org/rfc/rfc7748).
|
|
157
202
|
|
|
158
203
|
```ts
|
|
204
|
+
import { x448 } from '@noble/curves/ed448';
|
|
205
|
+
x448.getSharedSecret(priv, pub) === x448.scalarMult(priv, pub); // aliases
|
|
206
|
+
x448.getPublicKey(priv) === x448.scalarMultBase(priv);
|
|
207
|
+
|
|
208
|
+
// ed448 => x448 conversion
|
|
209
|
+
import { edwardsToMontgomeryPub } from '@noble/curves/ed448';
|
|
210
|
+
edwardsToMontgomeryPub(ed448.getPublicKey(ed448.utils.randomPrivateKey()));
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
decaf448 follows [irtf draft](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448).
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
import { utf8ToBytes } from '@noble/hashes/utils';
|
|
217
|
+
import { shake256 } from '@noble/hashes/sha3';
|
|
218
|
+
import { hashToCurve, encodeToCurve, DecafPoint, hashToDecaf448 } from '@noble/curves/ed448';
|
|
219
|
+
|
|
220
|
+
const msg = utf8ToBytes('Ristretto is traditionally a short shot of espresso coffee');
|
|
221
|
+
hashToCurve(msg);
|
|
222
|
+
|
|
223
|
+
const dp = DecafPoint.fromHex(
|
|
224
|
+
'c898eb4f87f97c564c6fd61fc7e49689314a1f818ec85eeb3bd5514ac816d38778f69ef347a89fca817e66defdedce178c7cc709b2116e75'
|
|
225
|
+
);
|
|
226
|
+
DecafPoint.BASE.multiply(2n).add(dp).subtract(DecafPoint.BASE).toRawBytes();
|
|
227
|
+
DecafPoint.ZERO.equals(dp) === false;
|
|
228
|
+
// pre-hashed hash-to-curve
|
|
229
|
+
DecafPoint.hashToCurve(shake256(msg, { dkLen: 112 }));
|
|
230
|
+
// full hash-to-curve including domain separation tag
|
|
231
|
+
hashToDecaf448(msg, { DST: 'decaf448_XOF:SHAKE256_D448MAP_RO_' });
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Same RFC7748 / RFC8032 / IRTF draft are followed.
|
|
235
|
+
|
|
236
|
+
#### bls12-381
|
|
237
|
+
|
|
238
|
+
See [abstract/bls](#abstractbls-barreto-lynn-scott-curves).
|
|
239
|
+
|
|
240
|
+
#### All available imports
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
import { secp256k1, schnorr } from '@noble/curves/secp256k1';
|
|
244
|
+
import { ed25519, ed25519ph, ed25519ctx, x25519, RistrettoPoint } from '@noble/curves/ed25519';
|
|
159
245
|
import { ed448, ed448ph, ed448ctx, x448 } from '@noble/curves/ed448';
|
|
160
|
-
import {
|
|
161
|
-
|
|
246
|
+
import { p256 } from '@noble/curves/p256';
|
|
247
|
+
import { p384 } from '@noble/curves/p384';
|
|
248
|
+
import { p521 } from '@noble/curves/p521';
|
|
249
|
+
import { pallas, vesta } from '@noble/curves/pasta';
|
|
250
|
+
import { bls12_381 } from '@noble/curves/bls12-381';
|
|
251
|
+
import { bn254 } from '@noble/curves/bn254'; // also known as alt_bn128
|
|
252
|
+
import { jubjub } from '@noble/curves/jubjub';
|
|
253
|
+
import { bytesToHex, hexToBytes, concatBytes, utf8ToBytes } from '@noble/curves/abstract/utils';
|
|
162
254
|
```
|
|
163
255
|
|
|
164
|
-
|
|
256
|
+
#### Accessing a curve's variables
|
|
165
257
|
|
|
166
258
|
```ts
|
|
167
|
-
import { secp256k1 } from '@noble/curves/secp256k1';
|
|
168
|
-
|
|
259
|
+
import { secp256k1 } from '@noble/curves/secp256k1';
|
|
260
|
+
// Every curve has `CURVE` object that contains its parameters, field, and others
|
|
261
|
+
console.log(secp256k1.CURVE.p); // field modulus
|
|
262
|
+
console.log(secp256k1.CURVE.n); // curve order
|
|
263
|
+
console.log(secp256k1.CURVE.a, secp256k1.CURVE.b); // equation params
|
|
264
|
+
console.log(secp256k1.CURVE.Gx, secp256k1.CURVE.Gy); // base point coordinates
|
|
169
265
|
```
|
|
170
266
|
|
|
171
267
|
## Abstract API
|
|
@@ -178,17 +274,6 @@ Precomputes are enabled for weierstrass and edwards BASE points of a curve. You
|
|
|
178
274
|
could precompute any other point (e.g. for ECDH) using `utils.precompute()`
|
|
179
275
|
method: check out examples.
|
|
180
276
|
|
|
181
|
-
There are following zero-dependency algorithms:
|
|
182
|
-
|
|
183
|
-
- [abstract/weierstrass: Short Weierstrass curve](#abstractweierstrass-short-weierstrass-curve)
|
|
184
|
-
- [abstract/edwards: Twisted Edwards curve](#abstractedwards-twisted-edwards-curve)
|
|
185
|
-
- [abstract/montgomery: Montgomery curve](#abstractmontgomery-montgomery-curve)
|
|
186
|
-
- [abstract/bls: Barreto-Lynn-Scott curves](#abstractbls-barreto-lynn-scott-curves)
|
|
187
|
-
- [abstract/hash-to-curve: Hashing strings to curve points](#abstracthash-to-curve-hashing-strings-to-curve-points)
|
|
188
|
-
- [abstract/poseidon: Poseidon hash](#abstractposeidon-poseidon-hash)
|
|
189
|
-
- [abstract/modular: Modular arithmetics utilities](#abstractmodular-modular-arithmetics-utilities)
|
|
190
|
-
- [abstract/utils: General utilities](#abstractutils-general-utilities)
|
|
191
|
-
|
|
192
277
|
### abstract/weierstrass: Short Weierstrass curve
|
|
193
278
|
|
|
194
279
|
```ts
|
|
@@ -212,7 +297,7 @@ const secq256k1 = weierstrass({
|
|
|
212
297
|
randomBytes,
|
|
213
298
|
});
|
|
214
299
|
|
|
215
|
-
// Replace weierstrass with weierstrassPoints if you don't need ECDSA, hash, hmac, randomBytes
|
|
300
|
+
// Replace weierstrass() with weierstrassPoints() if you don't need ECDSA, hash, hmac, randomBytes
|
|
216
301
|
```
|
|
217
302
|
|
|
218
303
|
Short Weierstrass curve's formula is `y² = x³ + ax + b`. `weierstrass`
|
|
@@ -233,6 +318,11 @@ type CHash = {
|
|
|
233
318
|
};
|
|
234
319
|
```
|
|
235
320
|
|
|
321
|
+
**Message hash** is expected instead of message itself:
|
|
322
|
+
|
|
323
|
+
- `sign(msgHash, privKey)` is default behavior, assuming you pre-hash msg with sha2, or other hash
|
|
324
|
+
- `sign(msg, privKey, {prehash: true})` option can be used if you want to pass the message itself
|
|
325
|
+
|
|
236
326
|
**Weierstrass points:**
|
|
237
327
|
|
|
238
328
|
1. Exported as `ProjectivePoint`
|
|
@@ -328,6 +418,7 @@ More examples:
|
|
|
328
418
|
const priv = secq256k1.utils.randomPrivateKey();
|
|
329
419
|
secq256k1.getPublicKey(priv); // Convert private key to public.
|
|
330
420
|
const sig = secq256k1.sign(msg, priv); // Sign msg with private key.
|
|
421
|
+
const sig2 = secq256k1.sign(msg, priv, { prehash: true }); // hash(msg)
|
|
331
422
|
secq256k1.verify(sig, msg, priv); // Verify if sig is correct.
|
|
332
423
|
|
|
333
424
|
const Point = secq256k1.ProjectivePoint;
|
|
@@ -475,6 +566,8 @@ use aggregated, batch-verifiable
|
|
|
475
566
|
[threshold signatures](https://medium.com/snigirev.stepan/bls-signatures-better-than-schnorr-5a7fe30ea716),
|
|
476
567
|
using Boneh-Lynn-Shacham signature scheme.
|
|
477
568
|
|
|
569
|
+
The module doesn't expose `CURVE` property: use `G1.CURVE`, `G2.CURVE` instead.
|
|
570
|
+
|
|
478
571
|
Main methods and properties are:
|
|
479
572
|
|
|
480
573
|
- `getPublicKey(privateKey)`
|
|
@@ -518,7 +611,12 @@ const aggSignature3 = bls.aggregateSignatures(signatures3);
|
|
|
518
611
|
const isValid3 = bls.verifyBatch(aggSignature3, messages, publicKeys);
|
|
519
612
|
console.log({ publicKeys, signatures3, aggSignature3, isValid3 });
|
|
520
613
|
|
|
521
|
-
//
|
|
614
|
+
// Pairings, with and without final exponentiation
|
|
615
|
+
// bls.pairing(PointG1, PointG2);
|
|
616
|
+
// bls.pairing(PointG1, PointG2, false);
|
|
617
|
+
// bls.fields.Fp12.finalExponentiate(bls.fields.Fp12.mul(eGS, ePHm));
|
|
618
|
+
|
|
619
|
+
// Others
|
|
522
620
|
// bls.G1.ProjectivePoint.BASE, bls.G2.ProjectivePoint.BASE
|
|
523
621
|
// bls.fields.Fp, bls.fields.Fp2, bls.fields.Fp12, bls.fields.Fr
|
|
524
622
|
|
|
@@ -554,7 +652,7 @@ aggregateSignatures: {
|
|
|
554
652
|
millerLoop: (ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]) => Fp12;
|
|
555
653
|
pairing: (P: ProjPointType<Fp>, Q: ProjPointType<Fp2>, withFinalExponent?: boolean) => Fp12;
|
|
556
654
|
G1: CurvePointsRes<Fp> & ReturnType<typeof htf.createHasher<Fp>>;
|
|
557
|
-
G2: CurvePointsRes<Fp2> & ReturnType<typeof htf.createHasher<Fp2>>;
|
|
655
|
+
G2: CurvePointsRes<Fp2> & ReturnType<typeof htf.createHasher<Fp2>>;
|
|
558
656
|
Signature: SignatureCoder<Fp2>;
|
|
559
657
|
params: {
|
|
560
658
|
x: bigint;
|
|
@@ -567,7 +665,7 @@ fields: {
|
|
|
567
665
|
Fp2: IField<Fp2>;
|
|
568
666
|
Fp6: IField<Fp6>;
|
|
569
667
|
Fp12: IField<Fp12>;
|
|
570
|
-
Fr: IField<bigint>;
|
|
668
|
+
Fr: IField<bigint>;
|
|
571
669
|
};
|
|
572
670
|
utils: {
|
|
573
671
|
randomPrivateKey: () => Uint8Array;
|
|
@@ -577,7 +675,7 @@ utils: {
|
|
|
577
675
|
|
|
578
676
|
### abstract/hash-to-curve: Hashing strings to curve points
|
|
579
677
|
|
|
580
|
-
The module allows to hash arbitrary strings to elliptic curve points. Implements [
|
|
678
|
+
The module allows to hash arbitrary strings to elliptic curve points. Implements [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380).
|
|
581
679
|
|
|
582
680
|
Every curve has exported `hashToCurve` and `encodeToCurve` methods. You should always prefer `hashToCurve` for security:
|
|
583
681
|
|
|
@@ -593,19 +691,17 @@ bls12_381.G1.hashToCurve(randomBytes(), { DST: 'another' });
|
|
|
593
691
|
bls12_381.G2.hashToCurve(randomBytes(), { DST: 'custom' });
|
|
594
692
|
```
|
|
595
693
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
`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.
|
|
599
|
-
|
|
600
|
-
Hash must conform to `CHash` interface (see [weierstrass section](#abstractweierstrass-short-weierstrass-curve)).
|
|
694
|
+
Low-level methods from the spec:
|
|
601
695
|
|
|
602
696
|
```ts
|
|
697
|
+
// produces a uniformly random byte string using a cryptographic hash function H that outputs b bits.
|
|
603
698
|
function expand_message_xmd(
|
|
604
699
|
msg: Uint8Array,
|
|
605
700
|
DST: Uint8Array,
|
|
606
701
|
lenInBytes: number,
|
|
607
|
-
H: CHash
|
|
702
|
+
H: CHash // For CHash see abstract/weierstrass docs section
|
|
608
703
|
): Uint8Array;
|
|
704
|
+
// produces a uniformly random byte string using an extendable-output function (XOF) H.
|
|
609
705
|
function expand_message_xof(
|
|
610
706
|
msg: Uint8Array,
|
|
611
707
|
DST: Uint8Array,
|
|
@@ -613,13 +709,9 @@ function expand_message_xof(
|
|
|
613
709
|
k: number,
|
|
614
710
|
H: CHash
|
|
615
711
|
): Uint8Array;
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
`hash_to_field(msg, count, options)`
|
|
619
|
-
[(spec)](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3)
|
|
620
|
-
hashes arbitrary-length byte strings to a list of one or more elements of a finite field F.
|
|
712
|
+
// Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F
|
|
713
|
+
function hash_to_field(msg: Uint8Array, count: number, options: Opts): bigint[][];
|
|
621
714
|
|
|
622
|
-
```ts
|
|
623
715
|
/**
|
|
624
716
|
* * `DST` is a domain separation tag, defined in section 2.2.5
|
|
625
717
|
* * `p` characteristic of F, where F is a finite field of characteristic p and order q = p^m
|
|
@@ -630,23 +722,13 @@ hashes arbitrary-length byte strings to a list of one or more elements of a fini
|
|
|
630
722
|
*/
|
|
631
723
|
type UnicodeOrBytes = string | Uint8Array;
|
|
632
724
|
type Opts = {
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
725
|
+
DST: UnicodeOrBytes;
|
|
726
|
+
p: bigint;
|
|
727
|
+
m: number;
|
|
728
|
+
k: number;
|
|
729
|
+
expand?: 'xmd' | 'xof';
|
|
730
|
+
hash: CHash;
|
|
639
731
|
};
|
|
640
|
-
|
|
641
|
-
/**
|
|
642
|
-
* Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F
|
|
643
|
-
* https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3
|
|
644
|
-
* @param msg a byte string containing the message to hash
|
|
645
|
-
* @param count the number of elements of F to output
|
|
646
|
-
* @param options `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`, see above
|
|
647
|
-
* @returns [u_0, ..., u_(count - 1)], a list of field elements.
|
|
648
|
-
*/
|
|
649
|
-
function hash_to_field(msg: Uint8Array, count: number, options: Opts): bigint[][];
|
|
650
732
|
```
|
|
651
733
|
|
|
652
734
|
### abstract/poseidon: Poseidon hash
|
|
@@ -689,30 +771,40 @@ mod.invert(17n, 10n); // invert(17) mod 10; modular multiplicative inverse
|
|
|
689
771
|
mod.invertBatch([1n, 2n, 4n], 21n); // => [1n, 11n, 16n] in one inversion
|
|
690
772
|
```
|
|
691
773
|
|
|
692
|
-
|
|
774
|
+
Field operations are not constant-time: they are using JS bigints, see [security](#security).
|
|
775
|
+
The fact is mostly irrelevant, but the important method to keep in mind is `pow`,
|
|
776
|
+
which may leak exponent bits, when used naïvely.
|
|
693
777
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
778
|
+
`mod.Field` is always **field over prime**. Non-prime fields aren't supported for now.
|
|
779
|
+
We don't test for prime-ness for speed and because algorithms are probabilistic anyway.
|
|
780
|
+
Initializing a non-prime field could make your app suspectible to
|
|
781
|
+
DoS (infilite loop) on Tonelli-Shanks square root calculation.
|
|
782
|
+
|
|
783
|
+
Unlike `mod.invert`, `mod.invertBatch` won't throw on `0`: make sure to throw an error yourself.
|
|
784
|
+
|
|
785
|
+
#### Creating private keys from hashes
|
|
697
786
|
|
|
698
|
-
|
|
787
|
+
You can't simply make a 32-byte private key from a 32-byte hash.
|
|
788
|
+
Doing so will make the key [biased](https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/).
|
|
699
789
|
|
|
700
|
-
To
|
|
701
|
-
|
|
790
|
+
To make the bias negligible, we follow [FIPS 186-5 A.2](https://csrc.nist.gov/publications/detail/fips/186/5/final)
|
|
791
|
+
and [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380#section-5.2).
|
|
792
|
+
This means, for 32-byte key, we would need 48-byte hash to get 2^-128 bias, which matches curve security level.
|
|
702
793
|
|
|
703
|
-
|
|
704
|
-
|
|
794
|
+
`hashToPrivateScalar()` that hashes to **private key** was created for this purpose.
|
|
795
|
+
Use [abstract/hash-to-curve](#abstracthash-to-curve-hashing-strings-to-curve-points)
|
|
796
|
+
if you need to hash to **public key**.
|
|
705
797
|
|
|
706
798
|
```ts
|
|
707
799
|
import { p256 } from '@noble/curves/p256';
|
|
708
800
|
import { sha256 } from '@noble/hashes/sha256';
|
|
709
801
|
import { hkdf } from '@noble/hashes/hkdf';
|
|
710
802
|
const someKey = new Uint8Array(32).fill(2); // Needs to actually be random, not .fill(2)
|
|
711
|
-
const derived = hkdf(sha256, someKey, undefined, 'application',
|
|
803
|
+
const derived = hkdf(sha256, someKey, undefined, 'application', 48); // 48 bytes for 32-byte priv
|
|
712
804
|
const validPrivateKey = mod.hashToPrivateScalar(derived, p256.CURVE.n);
|
|
713
805
|
```
|
|
714
806
|
|
|
715
|
-
### abstract/utils:
|
|
807
|
+
### abstract/utils: Useful utilities
|
|
716
808
|
|
|
717
809
|
```ts
|
|
718
810
|
import * as utils from '@noble/curves/abstract/utils';
|
|
@@ -734,96 +826,122 @@ utils.equalBytes(Uint8Array.from([0xde]), Uint8Array.from([0xde]));
|
|
|
734
826
|
|
|
735
827
|
## Security
|
|
736
828
|
|
|
737
|
-
1. The library has been audited
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
829
|
+
1. The library has been independently audited:
|
|
830
|
+
|
|
831
|
+
- in Feb 2023 by [Trail of Bits](https://www.trailofbits.com):
|
|
832
|
+
[PDF](https://github.com/trailofbits/publications/blob/master/reviews/2023-01-ryanshea-noblecurveslibrary-securityreview.pdf).
|
|
833
|
+
The audit has been funded by [Ryan Shea](https://www.shea.io).
|
|
834
|
+
Audit scope was abstract modules `curve`, `hash-to-curve`, `modular`, `poseidon`, `utils`, `weierstrass`,
|
|
835
|
+
and top-level modules `_shortw_utils` and `secp256k1`.
|
|
836
|
+
See [changes since v0.7.3 audit](https://github.com/paulmillr/noble-curves/compare/0.7.3..main).
|
|
837
|
+
|
|
838
|
+
2. The library has been fuzzed by [Guido Vranken's cryptofuzz](https://github.com/guidovranken/cryptofuzz).
|
|
839
|
+
You can run the fuzzer by yourself to check it.
|
|
840
|
+
3. [Timing attack](https://en.wikipedia.org/wiki/Timing_attack) considerations:
|
|
841
|
+
_JIT-compiler_ and _Garbage Collector_ make "constant time" extremely hard to
|
|
842
|
+
achieve in a scripting language. Which means _any other JS library can't have
|
|
843
|
+
constant-timeness_. Even statically typed Rust, a language without GC,
|
|
844
|
+
[makes it harder to achieve constant-time](https://www.chosenplaintext.ca/open-source/rust-timing-shield/security)
|
|
845
|
+
for some cases. If your goal is absolute security, don't use any JS lib — including bindings to native ones.
|
|
846
|
+
Use low-level libraries & languages. Nonetheless we're targetting algorithmic constant time.
|
|
847
|
+
|
|
848
|
+
We consider infrastructure attacks like rogue NPM modules very important;
|
|
849
|
+
that's why it's crucial to minimize the amount of 3rd-party dependencies & native bindings.
|
|
850
|
+
If your app uses 500 dependencies, any dep could get hacked and you'll be
|
|
851
|
+
downloading malware with every `npm install`. Our goal is to minimize this attack vector.
|
|
852
|
+
As for devDependencies used by the library:
|
|
853
|
+
|
|
854
|
+
- `@scure` base, bip32, bip39 (used in tests), micro-bmark (benchmark), micro-should (testing)
|
|
855
|
+
are developed by us and follow the same practices such as: minimal library size, auditability,
|
|
856
|
+
signed releases
|
|
857
|
+
- prettier (linter), fast-check (property-based testing), typescript versions
|
|
858
|
+
are locked and rarely updated. Every update is checked with `npm-diff`.
|
|
749
859
|
The packages are big, which makes it hard to audit their source code thoroughly and fully.
|
|
750
860
|
- They are only used if you clone the git repo and want to add some feature to it. End-users won't use them.
|
|
751
861
|
|
|
862
|
+
As for key generation, we're deferring to built-in
|
|
863
|
+
[crypto.getRandomValues](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues)
|
|
864
|
+
which is considered cryptographically secure (CSPRNG).
|
|
865
|
+
|
|
752
866
|
## Speed
|
|
753
867
|
|
|
754
|
-
Benchmark results on Apple M2 with node
|
|
868
|
+
Benchmark results on Apple M2 with node v20:
|
|
755
869
|
|
|
756
870
|
```
|
|
757
871
|
secp256k1
|
|
758
|
-
init x
|
|
759
|
-
getPublicKey x
|
|
760
|
-
sign x
|
|
761
|
-
verify x
|
|
762
|
-
getSharedSecret x
|
|
763
|
-
recoverPublicKey x
|
|
764
|
-
schnorr.sign x
|
|
765
|
-
schnorr.verify x
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
init x
|
|
769
|
-
getPublicKey x
|
|
770
|
-
sign x
|
|
771
|
-
verify x
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
init x
|
|
775
|
-
getPublicKey x 2,
|
|
776
|
-
sign x 2,
|
|
777
|
-
verify x
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
init x
|
|
781
|
-
getPublicKey x 1,
|
|
782
|
-
sign x 1,
|
|
783
|
-
verify x
|
|
872
|
+
init x 68 ops/sec @ 14ms/op
|
|
873
|
+
getPublicKey x 6,750 ops/sec @ 148μs/op
|
|
874
|
+
sign x 5,206 ops/sec @ 192μs/op
|
|
875
|
+
verify x 880 ops/sec @ 1ms/op
|
|
876
|
+
getSharedSecret x 536 ops/sec @ 1ms/op
|
|
877
|
+
recoverPublicKey x 852 ops/sec @ 1ms/op
|
|
878
|
+
schnorr.sign x 685 ops/sec @ 1ms/op
|
|
879
|
+
schnorr.verify x 908 ops/sec @ 1ms/op
|
|
880
|
+
|
|
881
|
+
p256
|
|
882
|
+
init x 38 ops/sec @ 26ms/op
|
|
883
|
+
getPublicKey x 6,530 ops/sec @ 153μs/op
|
|
884
|
+
sign x 5,074 ops/sec @ 197μs/op
|
|
885
|
+
verify x 626 ops/sec @ 1ms/op
|
|
886
|
+
|
|
887
|
+
p384
|
|
888
|
+
init x 17 ops/sec @ 57ms/op
|
|
889
|
+
getPublicKey x 2,883 ops/sec @ 346μs/op
|
|
890
|
+
sign x 2,358 ops/sec @ 424μs/op
|
|
891
|
+
verify x 245 ops/sec @ 4ms/op
|
|
892
|
+
|
|
893
|
+
p521
|
|
894
|
+
init x 9 ops/sec @ 109ms/op
|
|
895
|
+
getPublicKey x 1,516 ops/sec @ 659μs/op
|
|
896
|
+
sign x 1,271 ops/sec @ 786μs/op
|
|
897
|
+
verify x 123 ops/sec @ 8ms/op
|
|
784
898
|
|
|
785
899
|
ed25519
|
|
786
|
-
init x
|
|
787
|
-
getPublicKey x
|
|
788
|
-
sign x
|
|
789
|
-
verify x
|
|
900
|
+
init x 54 ops/sec @ 18ms/op
|
|
901
|
+
getPublicKey x 10,269 ops/sec @ 97μs/op
|
|
902
|
+
sign x 5,110 ops/sec @ 195μs/op
|
|
903
|
+
verify x 1,049 ops/sec @ 952μs/op
|
|
790
904
|
|
|
791
905
|
ed448
|
|
792
|
-
init x
|
|
793
|
-
getPublicKey x 3,
|
|
794
|
-
sign x 1,
|
|
795
|
-
verify x
|
|
906
|
+
init x 19 ops/sec @ 51ms/op
|
|
907
|
+
getPublicKey x 3,775 ops/sec @ 264μs/op
|
|
908
|
+
sign x 1,771 ops/sec @ 564μs/op
|
|
909
|
+
verify x 351 ops/sec @ 2ms/op
|
|
796
910
|
|
|
797
911
|
ecdh
|
|
798
|
-
├─x25519 x 1,
|
|
799
|
-
├─secp256k1 x
|
|
800
|
-
├─
|
|
801
|
-
├─
|
|
802
|
-
├─
|
|
803
|
-
└─x448 x
|
|
912
|
+
├─x25519 x 1,466 ops/sec @ 682μs/op
|
|
913
|
+
├─secp256k1 x 539 ops/sec @ 1ms/op
|
|
914
|
+
├─p256 x 511 ops/sec @ 1ms/op
|
|
915
|
+
├─p384 x 199 ops/sec @ 5ms/op
|
|
916
|
+
├─p521 x 103 ops/sec @ 9ms/op
|
|
917
|
+
└─x448 x 548 ops/sec @ 1ms/op
|
|
804
918
|
|
|
805
919
|
bls12-381
|
|
806
|
-
init x
|
|
807
|
-
getPublicKey 1-bit x
|
|
808
|
-
getPublicKey x
|
|
809
|
-
sign x
|
|
810
|
-
verify x
|
|
811
|
-
pairing x
|
|
812
|
-
aggregatePublicKeys/8 x
|
|
813
|
-
aggregatePublicKeys/32 x
|
|
814
|
-
aggregatePublicKeys/128 x
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
aggregateSignatures/
|
|
920
|
+
init x 36 ops/sec @ 27ms/op
|
|
921
|
+
getPublicKey 1-bit x 973 ops/sec @ 1ms/op
|
|
922
|
+
getPublicKey x 970 ops/sec @ 1ms/op
|
|
923
|
+
sign x 55 ops/sec @ 17ms/op
|
|
924
|
+
verify x 39 ops/sec @ 25ms/op
|
|
925
|
+
pairing x 106 ops/sec @ 9ms/op
|
|
926
|
+
aggregatePublicKeys/8 x 129 ops/sec @ 7ms/op
|
|
927
|
+
aggregatePublicKeys/32 x 34 ops/sec @ 28ms/op
|
|
928
|
+
aggregatePublicKeys/128 x 8 ops/sec @ 112ms/op
|
|
929
|
+
aggregatePublicKeys/512 x 2 ops/sec @ 446ms/op
|
|
930
|
+
aggregatePublicKeys/2048 x 0 ops/sec @ 1778ms/op
|
|
931
|
+
aggregateSignatures/8 x 50 ops/sec @ 19ms/op
|
|
932
|
+
aggregateSignatures/32 x 13 ops/sec @ 74ms/op
|
|
933
|
+
aggregateSignatures/128 x 3 ops/sec @ 296ms/op
|
|
934
|
+
aggregateSignatures/512 x 0 ops/sec @ 1180ms/op
|
|
935
|
+
aggregateSignatures/2048 x 0 ops/sec @ 4715ms/op
|
|
818
936
|
|
|
819
937
|
hash-to-curve
|
|
820
|
-
hash_to_field x
|
|
821
|
-
secp256k1 x 2,
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
ed25519 x
|
|
826
|
-
ed448 x 1,
|
|
938
|
+
hash_to_field x 91,600 ops/sec @ 10μs/op
|
|
939
|
+
secp256k1 x 2,373 ops/sec @ 421μs/op
|
|
940
|
+
p256 x 4,310 ops/sec @ 231μs/op
|
|
941
|
+
p384 x 1,664 ops/sec @ 600μs/op
|
|
942
|
+
p521 x 807 ops/sec @ 1ms/op
|
|
943
|
+
ed25519 x 3,088 ops/sec @ 323μs/op
|
|
944
|
+
ed448 x 1,247 ops/sec @ 801μs/op
|
|
827
945
|
```
|
|
828
946
|
|
|
829
947
|
## Contributing & testing
|
|
@@ -836,33 +954,37 @@ ed448 x 1,146 ops/sec @ 871μs/op
|
|
|
836
954
|
## Upgrading
|
|
837
955
|
|
|
838
956
|
Previously, the library was split into single-feature packages
|
|
839
|
-
noble-secp256k1
|
|
840
|
-
|
|
841
|
-
|
|
957
|
+
[noble-secp256k1](https://github.com/paulmillr/noble-secp256k1),
|
|
958
|
+
[noble-ed25519](https://github.com/paulmillr/noble-ed25519) and
|
|
959
|
+
[noble-bls12-381](https://github.com/paulmillr/noble-bls12-381).
|
|
842
960
|
|
|
843
|
-
|
|
961
|
+
Curves continue their original work. The single-feature packages changed their
|
|
962
|
+
direction towards providing minimal 4kb implementations of cryptography,
|
|
963
|
+
which means they have less features.
|
|
844
964
|
|
|
845
|
-
Upgrading from
|
|
965
|
+
Upgrading from noble-secp256k1 2.0 or noble-ed25519 2.0: no changes, libraries are compatible.
|
|
966
|
+
|
|
967
|
+
Upgrading from noble-secp256k1 1.7:
|
|
846
968
|
|
|
847
969
|
- `getPublicKey`
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
970
|
+
- now produce 33-byte compressed signatures by default
|
|
971
|
+
- to use old behavior, which produced 65-byte uncompressed keys, set
|
|
972
|
+
argument `isCompressed` to `false`: `getPublicKey(priv, false)`
|
|
851
973
|
- `sign`
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
974
|
+
- is now sync; use `signAsync` for async version
|
|
975
|
+
- now returns `Signature` instance with `{ r, s, recovery }` properties
|
|
976
|
+
- `canonical` option was renamed to `lowS`
|
|
977
|
+
- `recovered` option has been removed because recovery bit is always returned now
|
|
978
|
+
- `der` option has been removed. There are 2 options:
|
|
979
|
+
1. Use compact encoding: `fromCompact`, `toCompactRawBytes`, `toCompactHex`.
|
|
980
|
+
Compact encoding is simply a concatenation of 32-byte r and 32-byte s.
|
|
981
|
+
2. If you must use DER encoding, switch to noble-curves (see above).
|
|
860
982
|
- `verify`
|
|
861
|
-
|
|
983
|
+
- `strict` option was renamed to `lowS`
|
|
862
984
|
- `getSharedSecret`
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
985
|
+
- now produce 33-byte compressed signatures by default
|
|
986
|
+
- to use old behavior, which produced 65-byte uncompressed keys, set
|
|
987
|
+
argument `isCompressed` to `false`: `getSharedSecret(a, b, false)`
|
|
866
988
|
- `recoverPublicKey(msg, sig, rec)` was changed to `sig.recoverPublicKey(msg)`
|
|
867
989
|
- `number` type for private keys have been removed: use `bigint` instead
|
|
868
990
|
- `Point` (2d xy) has been changed to `ProjectivePoint` (3d xyz)
|
|
@@ -878,40 +1000,70 @@ Upgrading from [@noble/ed25519](https://github.com/paulmillr/noble-ed25519) 1.7:
|
|
|
878
1000
|
- `utils` were split into `utils` (same api as in noble-curves) and
|
|
879
1001
|
`etc` (`sha512Sync` and others)
|
|
880
1002
|
- `getSharedSecret` was moved to `x25519` module
|
|
1003
|
+
- `toX25519` has been moved to `edwardsToMontgomeryPub` and `edwardsToMontgomeryPriv` methods
|
|
881
1004
|
|
|
882
1005
|
Upgrading from [@noble/bls12-381](https://github.com/paulmillr/noble-bls12-381):
|
|
883
1006
|
|
|
884
1007
|
- Methods and classes were renamed:
|
|
885
|
-
|
|
886
|
-
|
|
1008
|
+
- PointG1 -> G1.Point, PointG2 -> G2.Point
|
|
1009
|
+
- PointG2.fromSignature -> Signature.decode, PointG2.toSignature -> Signature.encode
|
|
887
1010
|
- Fp2 ORDER was corrected
|
|
888
1011
|
|
|
889
1012
|
## Resources
|
|
890
1013
|
|
|
891
|
-
Useful articles about the library or its primitives:
|
|
892
|
-
|
|
893
1014
|
- [Learning fast elliptic-curve cryptography](https://paulmillr.com/posts/noble-secp256k1-fast-ecc/)
|
|
1015
|
+
- EdDSA
|
|
1016
|
+
- [A Deep dive into Ed25519 Signatures](https://cendyne.dev/posts/2022-03-06-ed25519-signatures.html)
|
|
1017
|
+
- [Ed25519 Deep Dive Addendum](https://cendyne.dev/posts/2022-09-11-ed25519-deep-dive-addendum.html)
|
|
1018
|
+
- [It’s 255:19AM. Do you know what your validation criteria are?](https://hdevalence.ca/blog/2020-10-04-its-25519am)
|
|
1019
|
+
- [Taming the many EdDSAs](https://csrc.nist.gov/csrc/media/Presentations/2023/crclub-2023-03-08/images-media/20230308-crypto-club-slides--taming-the-many-EdDSAs.pdf)
|
|
1020
|
+
that describes concepts of Strong UnForgeability under Chosen Message Attacks and Strongly Binding Signatures
|
|
1021
|
+
- [Cofactor Explained: Clearing Elliptic Curves’ dirty little secret](https://loup-vaillant.fr/tutorials/cofactor)
|
|
1022
|
+
- [Surrounded by Elligators](https://loup-vaillant.fr/articles/implementing-elligator)
|
|
894
1023
|
- Pairings and BLS
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
1024
|
+
- [BLS signatures for busy people](https://gist.github.com/paulmillr/18b802ad219b1aee34d773d08ec26ca2)
|
|
1025
|
+
- [BLS12-381 for the rest of us](https://hackmd.io/@benjaminion/bls12-381)
|
|
1026
|
+
- [Key concepts of pairings](https://medium.com/@alonmuroch_65570/bls-signatures-part-2-key-concepts-of-pairings-27a8a9533d0c)
|
|
1027
|
+
- Pairing over bls12-381:
|
|
1028
|
+
[fields](https://research.nccgroup.com/2020/07/06/pairing-over-bls12-381-part-1-fields/),
|
|
1029
|
+
[curves](https://research.nccgroup.com/2020/07/13/pairing-over-bls12-381-part-2-curves/),
|
|
1030
|
+
[pairings](https://research.nccgroup.com/2020/08/13/pairing-over-bls12-381-part-3-pairing/)
|
|
1031
|
+
- [Estimating the bit security of pairing-friendly curves](https://research.nccgroup.com/2022/02/03/estimating-the-bit-security-of-pairing-friendly-curves/)
|
|
1032
|
+
|
|
1033
|
+
### Demos
|
|
1034
|
+
|
|
1035
|
+
- [Elliptic Curve Calculator](https://paulmillr.com/noble): add / multiply points, sign messages
|
|
1036
|
+
- [BLS threshold signatures](https://genthresh.com)
|
|
1037
|
+
|
|
1038
|
+
### Projects using curves
|
|
1039
|
+
|
|
1040
|
+
- HDkey libraries: [scure-bip32](https://github.com/paulmillr/scure-bip32), [bip32](https://github.com/bitcoinjs/bip32)
|
|
1041
|
+
- Social networks: [nostr](https://github.com/nbd-wtf/nostr-tools), [bluesky](https://github.com/bluesky-social/atproto)
|
|
1042
|
+
- Ethereum libraries:
|
|
1043
|
+
- [ethereum-cryptography](https://github.com/ethereum/js-ethereum-cryptography)
|
|
1044
|
+
- [micro-eth-signer](https://github.com/paulmillr/micro-eth-signer),
|
|
1045
|
+
[ethers](https://github.com/ethers-io/ethers.js) (old noble),
|
|
1046
|
+
[viem.sh](https://viem.sh),
|
|
1047
|
+
[@ethereumjs](https://github.com/ethereumjs/ethereumjs-monorepo)
|
|
1048
|
+
- [metamask's eth-sig-util](https://github.com/MetaMask/eth-sig-util)
|
|
1049
|
+
- [gridplus lattice sdk](https://github.com/GridPlus/lattice-eth2-utils)
|
|
1050
|
+
- Bitcoin libraries:
|
|
1051
|
+
- [scure-btc-signer](https://github.com/paulmillr/scure-btc-signer)
|
|
1052
|
+
- [tapscript](https://github.com/cmdruid/tapscript)
|
|
1053
|
+
- Solana libraries: [micro-sol-signer](https://github.com/paulmillr/micro-sol-signer), [solana-web3.js](https://github.com/solana-labs/solana-web3.js)
|
|
1054
|
+
- Other web3 stuff:
|
|
1055
|
+
- [scure-starknet](https://github.com/paulmillr/scure-starknet)
|
|
1056
|
+
- [aztec](https://github.com/AztecProtocol/aztec-packages)
|
|
1057
|
+
- [polkadot.js](https://github.com/polkadot-js/common), [drand-client](https://github.com/drand/drand-client), [moneroj](https://github.com/beritani/moneroj), [tronlib](https://github.com/CoinSpace/tronlib)
|
|
1058
|
+
- [protonmail](https://github.com/ProtonMail/WebClients) (old noble for now)
|
|
1059
|
+
- [did-jwt](https://github.com/decentralized-identity/did-jwt), [hpke-js](https://github.com/dajiaji/hpke-js),
|
|
1060
|
+
[js-libp2p-noise](https://github.com/ChainSafe/js-libp2p-noise)
|
|
910
1061
|
- [ed25519-keygen](https://github.com/paulmillr/ed25519-keygen) SSH, PGP, TOR key generation
|
|
911
|
-
- [
|
|
912
|
-
-
|
|
913
|
-
- BLS BBS signatures
|
|
1062
|
+
- [secp256k1 compatibility layer](https://github.com/ethereum/js-ethereum-cryptography/blob/2.0.0/src/secp256k1-compat.ts)
|
|
1063
|
+
for users who want to switch from secp256k1-node or tiny-secp256k1. Allows to see which methods map to corresponding noble code.
|
|
1064
|
+
- [BLS BBS signatures](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)
|
|
914
1065
|
- [KZG trusted setup ceremony](https://github.com/dsrvlabs/czg-keremony)
|
|
1066
|
+
- See [full list of projects on GitHub](https://github.com/paulmillr/noble-curves/network/dependents).
|
|
915
1067
|
|
|
916
1068
|
## License
|
|
917
1069
|
|