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