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