@noble/curves 1.9.6 → 2.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +267 -421
- package/abstract/bls.d.ts +49 -111
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +108 -152
- package/abstract/bls.js.map +1 -1
- package/abstract/curve.d.ts +4 -45
- package/abstract/curve.d.ts.map +1 -1
- package/abstract/curve.js +22 -47
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.d.ts +11 -68
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +62 -134
- package/abstract/edwards.js.map +1 -1
- package/abstract/fft.js +14 -27
- package/abstract/fft.js.map +1 -1
- package/abstract/hash-to-curve.d.ts +11 -24
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +30 -35
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.d.ts +5 -17
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +166 -167
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts +4 -9
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +15 -18
- package/abstract/montgomery.js.map +1 -1
- package/abstract/oprf.d.ts +282 -0
- package/abstract/oprf.d.ts.map +1 -0
- package/abstract/oprf.js +297 -0
- package/abstract/oprf.js.map +1 -0
- package/abstract/poseidon.js +20 -24
- package/abstract/poseidon.js.map +1 -1
- package/abstract/tower.d.ts.map +1 -1
- package/abstract/tower.js +43 -19
- package/abstract/tower.js.map +1 -1
- package/abstract/weierstrass.d.ts +11 -145
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +122 -331
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts +2 -2
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +171 -180
- package/bls12-381.js.map +1 -1
- package/bn254.d.ts +58 -10
- package/bn254.d.ts.map +1 -1
- package/bn254.js +69 -97
- package/bn254.js.map +1 -1
- package/ed25519.d.ts +12 -31
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +95 -137
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +11 -29
- package/ed448.d.ts.map +1 -1
- package/ed448.js +85 -123
- package/ed448.js.map +1 -1
- package/index.js +1 -1
- package/misc.d.ts +10 -14
- package/misc.d.ts.map +1 -1
- package/misc.js +51 -60
- package/misc.js.map +1 -1
- package/nist.d.ts +11 -14
- package/nist.d.ts.map +1 -1
- package/nist.js +46 -55
- package/nist.js.map +1 -1
- package/package.json +8 -223
- package/secp256k1.d.ts +7 -23
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +47 -60
- package/secp256k1.js.map +1 -1
- package/src/abstract/bls.ts +197 -344
- package/src/abstract/curve.ts +7 -80
- package/src/abstract/edwards.ts +49 -171
- package/src/abstract/hash-to-curve.ts +32 -45
- package/src/abstract/modular.ts +144 -130
- package/src/abstract/montgomery.ts +19 -20
- package/src/abstract/oprf.ts +600 -0
- package/src/abstract/tower.ts +0 -3
- package/src/abstract/weierstrass.ts +69 -438
- package/src/bls12-381.ts +143 -138
- package/src/bn254.ts +65 -89
- package/src/ed25519.ts +53 -105
- package/src/ed448.ts +32 -77
- package/src/index.ts +1 -1
- package/src/misc.ts +66 -49
- package/src/nist.ts +48 -57
- package/src/secp256k1.ts +32 -65
- package/src/utils.ts +41 -61
- package/src/webcrypto.ts +362 -0
- package/utils.d.ts +28 -19
- package/utils.d.ts.map +1 -1
- package/utils.js +45 -121
- package/utils.js.map +1 -1
- package/webcrypto.d.ts +47 -0
- package/webcrypto.d.ts.map +1 -0
- package/webcrypto.js +231 -0
- package/webcrypto.js.map +1 -0
- package/esm/_shortw_utils.d.ts +0 -19
- package/esm/_shortw_utils.d.ts.map +0 -1
- package/esm/_shortw_utils.js +0 -16
- package/esm/_shortw_utils.js.map +0 -1
- package/esm/abstract/bls.d.ts +0 -190
- package/esm/abstract/bls.d.ts.map +0 -1
- package/esm/abstract/bls.js +0 -408
- package/esm/abstract/bls.js.map +0 -1
- package/esm/abstract/curve.d.ts +0 -231
- package/esm/abstract/curve.d.ts.map +0 -1
- package/esm/abstract/curve.js +0 -465
- package/esm/abstract/curve.js.map +0 -1
- package/esm/abstract/edwards.d.ts +0 -243
- package/esm/abstract/edwards.d.ts.map +0 -1
- package/esm/abstract/edwards.js +0 -627
- package/esm/abstract/edwards.js.map +0 -1
- package/esm/abstract/fft.d.ts +0 -122
- package/esm/abstract/fft.d.ts.map +0 -1
- package/esm/abstract/fft.js +0 -425
- package/esm/abstract/fft.js.map +0 -1
- package/esm/abstract/hash-to-curve.d.ts +0 -102
- package/esm/abstract/hash-to-curve.d.ts.map +0 -1
- package/esm/abstract/hash-to-curve.js +0 -203
- package/esm/abstract/hash-to-curve.js.map +0 -1
- package/esm/abstract/modular.d.ts +0 -171
- package/esm/abstract/modular.d.ts.map +0 -1
- package/esm/abstract/modular.js +0 -530
- package/esm/abstract/modular.js.map +0 -1
- package/esm/abstract/montgomery.d.ts +0 -30
- package/esm/abstract/montgomery.d.ts.map +0 -1
- package/esm/abstract/montgomery.js +0 -157
- package/esm/abstract/montgomery.js.map +0 -1
- package/esm/abstract/poseidon.d.ts +0 -68
- package/esm/abstract/poseidon.d.ts.map +0 -1
- package/esm/abstract/poseidon.js +0 -296
- package/esm/abstract/poseidon.js.map +0 -1
- package/esm/abstract/tower.d.ts +0 -95
- package/esm/abstract/tower.d.ts.map +0 -1
- package/esm/abstract/tower.js +0 -714
- package/esm/abstract/tower.js.map +0 -1
- package/esm/abstract/utils.d.ts +0 -5
- package/esm/abstract/utils.d.ts.map +0 -1
- package/esm/abstract/utils.js +0 -7
- package/esm/abstract/utils.js.map +0 -1
- package/esm/abstract/weierstrass.d.ts +0 -413
- package/esm/abstract/weierstrass.d.ts.map +0 -1
- package/esm/abstract/weierstrass.js +0 -1413
- package/esm/abstract/weierstrass.js.map +0 -1
- package/esm/bls12-381.d.ts +0 -16
- package/esm/bls12-381.d.ts.map +0 -1
- package/esm/bls12-381.js +0 -705
- package/esm/bls12-381.js.map +0 -1
- package/esm/bn254.d.ts +0 -18
- package/esm/bn254.d.ts.map +0 -1
- package/esm/bn254.js +0 -214
- package/esm/bn254.js.map +0 -1
- package/esm/ed25519.d.ts +0 -106
- package/esm/ed25519.d.ts.map +0 -1
- package/esm/ed25519.js +0 -467
- package/esm/ed25519.js.map +0 -1
- package/esm/ed448.d.ts +0 -100
- package/esm/ed448.d.ts.map +0 -1
- package/esm/ed448.js +0 -459
- package/esm/ed448.js.map +0 -1
- package/esm/index.d.ts +0 -2
- package/esm/index.d.ts.map +0 -1
- package/esm/index.js +0 -17
- package/esm/index.js.map +0 -1
- package/esm/jubjub.d.ts +0 -12
- package/esm/jubjub.d.ts.map +0 -1
- package/esm/jubjub.js +0 -12
- package/esm/jubjub.js.map +0 -1
- package/esm/misc.d.ts +0 -19
- package/esm/misc.d.ts.map +0 -1
- package/esm/misc.js +0 -109
- package/esm/misc.js.map +0 -1
- package/esm/nist.d.ts +0 -21
- package/esm/nist.d.ts.map +0 -1
- package/esm/nist.js +0 -132
- package/esm/nist.js.map +0 -1
- package/esm/p256.d.ts +0 -16
- package/esm/p256.d.ts.map +0 -1
- package/esm/p256.js +0 -16
- package/esm/p256.js.map +0 -1
- package/esm/p384.d.ts +0 -16
- package/esm/p384.d.ts.map +0 -1
- package/esm/p384.js +0 -16
- package/esm/p384.js.map +0 -1
- package/esm/p521.d.ts +0 -16
- package/esm/p521.d.ts.map +0 -1
- package/esm/p521.js +0 -16
- package/esm/p521.js.map +0 -1
- package/esm/package.json +0 -4
- package/esm/pasta.d.ts +0 -10
- package/esm/pasta.d.ts.map +0 -1
- package/esm/pasta.js +0 -10
- package/esm/pasta.js.map +0 -1
- package/esm/secp256k1.d.ts +0 -89
- package/esm/secp256k1.d.ts.map +0 -1
- package/esm/secp256k1.js +0 -294
- package/esm/secp256k1.js.map +0 -1
- package/esm/utils.d.ts +0 -110
- package/esm/utils.d.ts.map +0 -1
- package/esm/utils.js +0 -322
- package/esm/utils.js.map +0 -1
- package/src/_shortw_utils.ts +0 -21
- package/src/abstract/utils.ts +0 -7
- package/src/jubjub.ts +0 -12
- package/src/p256.ts +0 -15
- package/src/p384.ts +0 -15
- package/src/p521.ts +0 -15
- package/src/package.json +0 -3
- package/src/pasta.ts +0 -9
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ Audited & minimal JS implementation of elliptic curve cryptography.
|
|
|
5
5
|
- 🔒 [**Audited**](#security) by independent security firms
|
|
6
6
|
- 🔻 Tree-shakeable: unused code is excluded from your builds
|
|
7
7
|
- 🏎 Fast: hand-optimized for caveats of JS engines
|
|
8
|
-
- 🔍 Reliable:
|
|
8
|
+
- 🔍 Reliable: cross-library / wycheproof tests and fuzzing ensure correctness
|
|
9
9
|
- ➰ Weierstrass, Edwards, Montgomery curves; ECDSA, EdDSA, Schnorr, BLS signatures
|
|
10
10
|
- ✍️ ECDH, hash-to-curve, OPRF, Poseidon ZK-friendly hash
|
|
11
11
|
- 🔖 Non-repudiation (SUF-CMA, SBS) & consensus-friendliness (ZIP215) in ed25519, ed448
|
|
@@ -56,213 +56,161 @@ import { p256, p384, p521 } from '@noble/curves/nist.js';
|
|
|
56
56
|
import { bls12_381 } from '@noble/curves/bls12-381.js';
|
|
57
57
|
import { bn254 } from '@noble/curves/bn254.js';
|
|
58
58
|
import { jubjub, babyjubjub } from '@noble/curves/misc.js';
|
|
59
|
-
import { bytesToHex, hexToBytes, concatBytes, utf8ToBytes } from '@noble/curves/abstract/utils.js';
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
- [ECDSA signatures over secp256k1 and others](#ecdsa-signatures-over-secp256k1-and-others)
|
|
63
|
-
- [Hedged ECDSA with noise](#hedged-ecdsa-with-noise)
|
|
64
|
-
- [ECDH: Diffie-Hellman shared secrets](#ecdh-diffie-hellman-shared-secrets)
|
|
65
|
-
- [secp256k1 Schnorr signatures from BIP340](#secp256k1-schnorr-signatures-from-bip340)
|
|
66
|
-
- [ed25519](#ed25519) / [X25519](#x25519) / [ristretto255](#ristretto255)
|
|
67
|
-
- [ed448](#ed448) / [X448](#x448) / [decaf448](#decaf448)
|
|
68
|
-
- [bls12-381](#bls12-381)
|
|
69
|
-
- [bn254 aka alt_bn128](#bn254-aka-alt_bn128)
|
|
70
|
-
- [misc curves](#misc-curves)
|
|
71
|
-
- [Low-level methods](#low-level-methods)
|
|
72
|
-
- [Abstract API](#abstract-api)
|
|
73
|
-
- [weierstrass](#weierstrass-short-weierstrass-curve), [Projective Point](#projective-weierstrass-point), [ECDSA signatures](#ecdsa-signatures)
|
|
74
|
-
- [edwards](#edwards-twisted-edwards-curve), [Extended Point](#extended-edwards-point), [EdDSA signatures](#eddsa-signatures)
|
|
75
|
-
- [montgomery](#montgomery-montgomery-curve)
|
|
76
|
-
- [bls](#bls-barreto-lynn-scott-curves)
|
|
77
|
-
- [hash-to-curve](#hash-to-curve-hashing-strings-to-curve-points)
|
|
78
|
-
- [poseidon](#poseidon-poseidon-hash)
|
|
79
|
-
- [modular](#modular-modular-arithmetics-utilities)
|
|
80
|
-
- [fft](#fft-fast-fourier-transform)
|
|
81
|
-
- [Creating private keys from hashes](#creating-private-keys-from-hashes)
|
|
82
|
-
- [utils](#utils-useful-utilities)
|
|
83
|
-
- [Security](#security)
|
|
84
|
-
- [Speed](#speed)
|
|
85
|
-
- [Upgrading](#upgrading)
|
|
86
|
-
- [Contributing & testing](#contributing--testing)
|
|
87
|
-
- [License](#license)
|
|
88
|
-
|
|
89
|
-
### Implementations
|
|
90
|
-
|
|
91
|
-
#### ECDSA signatures over secp256k1 and others
|
|
92
59
|
|
|
93
|
-
|
|
94
|
-
import {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const pub = secp256k1.getPublicKey(priv);
|
|
99
|
-
const msg = new Uint8Array(32).fill(1); // message hash (not message) in ecdsa
|
|
100
|
-
const sig = secp256k1.sign(msg, priv); // `{prehash: true}` option is available
|
|
101
|
-
const isValid = secp256k1.verify(sig, msg, pub) === true;
|
|
60
|
+
// hash-to-curve
|
|
61
|
+
import { secp256k1_hasher } from '@noble/curves/secp256k1.js';
|
|
62
|
+
import { p256_hasher, p384_hasher, p521_hasher } from '@noble/curves/nist.js';
|
|
63
|
+
import { ristretto255_hasher } from '@noble/curves/ed25519.js';
|
|
64
|
+
import { decaf448_hasher } from '@noble/curves/ed448.js';
|
|
102
65
|
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
|
|
66
|
+
// OPRFs
|
|
67
|
+
import { p256_oprf, p384_oprf, p521_oprf } from '@noble/curves/nist.js';
|
|
68
|
+
import { ristretto255_oprf } from '@noble/curves/ed25519.js';
|
|
69
|
+
import { decaf448_orpf } from '@noble/curves/ed448.js';
|
|
106
70
|
|
|
107
|
-
//
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
71
|
+
// utils
|
|
72
|
+
import { weierstrass, ecdsa } from '@noble/curves/abstract/weierstrass.js';
|
|
73
|
+
import { edwards, eddsa } from '@noble/curves/abstract/edwards.js';
|
|
74
|
+
import { poseidon, poseidonSponge } from '@noble/curves/abstract/poseidon.js';
|
|
75
|
+
import { Field, mod, pow } from '@noble/curves/abstract/modular.js';
|
|
76
|
+
import { FFT, poly } from '@noble/curves/abstract/fft.js';
|
|
77
|
+
import { bytesToHex, hexToBytes, concatBytes, utf8ToBytes } from '@noble/curves/abstract/utils.js';
|
|
111
78
|
```
|
|
112
79
|
|
|
113
|
-
The same code would work for NIST P256 (secp256r1), P384 (secp384r1) & P521 (secp521r1).
|
|
114
|
-
|
|
115
|
-
#### Hedged ECDSA with noise
|
|
116
|
-
|
|
117
|
-
```ts
|
|
118
|
-
const noisySignature = secp256k1.sign(msg, priv, { extraEntropy: true });
|
|
119
|
-
const ent = new Uint8Array(32).fill(3); // set custom entropy
|
|
120
|
-
const noisySignature2 = secp256k1.sign(msg, priv, { extraEntropy: ent });
|
|
121
|
-
```
|
|
122
80
|
|
|
123
|
-
|
|
124
|
-
It adds noise to signatures. The technique is used by default in BIP340; we also implement them
|
|
125
|
-
optionally for ECDSA. Check out blog post
|
|
126
|
-
[Deterministic signatures are not your friends](https://paulmillr.com/posts/deterministic-signatures/)
|
|
127
|
-
and [spec draft](https://datatracker.ietf.org/doc/draft-irtf-cfrg-det-sigs-with-noise/).
|
|
81
|
+
### ECDSA, EdDSA, Schnorr signatures
|
|
128
82
|
|
|
129
|
-
####
|
|
83
|
+
#### secp256k1, p256, p384, p521, ed25519, ed448
|
|
130
84
|
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
// - `shared` is not hashed: more secure way is sha256(shared) or hkdf(shared)
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
#### secp256k1 Schnorr signatures from BIP340
|
|
140
|
-
|
|
141
|
-
```ts
|
|
142
|
-
import { schnorr } from '@noble/curves/secp256k1.js';
|
|
143
|
-
const priv = schnorr.utils.randomPrivateKey();
|
|
144
|
-
const pub = schnorr.getPublicKey(priv);
|
|
145
|
-
const msg = new TextEncoder().encode('hello');
|
|
146
|
-
const sig = schnorr.sign(msg, priv);
|
|
147
|
-
const isValid = schnorr.verify(sig, msg, pub);
|
|
148
|
-
```
|
|
85
|
+
```js
|
|
86
|
+
import { secp256k1, schnorr } from '@noble/curves/secp256k1.js';
|
|
87
|
+
import { p256, p384, p521 } from '@noble/curves/nist.js';
|
|
88
|
+
import { ed25519 } from '@noble/curves/ed25519.js';
|
|
89
|
+
import { ed448 } from '@noble/curves/ed448.js';
|
|
149
90
|
|
|
150
|
-
|
|
91
|
+
import { hexToBytes, utf8ToBytes } from '@noble/curves/utils.js';
|
|
151
92
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
const
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
ed25519.verify(sig, msg, pub, { zip215: false }); // SBS / e-voting / RFC8032 / FIPS 186-5
|
|
93
|
+
for (const curve of [secp256k1, schnorr, p256, p384, p521, ed25519, ed448]) {
|
|
94
|
+
const { secretKey, publicKey } = curve.keygen();
|
|
95
|
+
const msg = utf8ToBytes('hello noble');
|
|
96
|
+
const sig = curve.sign(msg, secretKey);
|
|
97
|
+
const isValid = curve.verify(sig, msg, publicKey);
|
|
98
|
+
console.log(curve, secretKey, publicKey, sig);
|
|
99
|
+
}
|
|
160
100
|
|
|
161
|
-
//
|
|
162
|
-
|
|
101
|
+
// Specific private key
|
|
102
|
+
const priv2 = hexToBytes('46c930bc7bb4db7f55da20798697421b98c4175a52c630294d75a84b9c126236');
|
|
103
|
+
const pub2 = secp256k1.getPublicKey(priv2);
|
|
163
104
|
```
|
|
164
105
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
106
|
+
- We provide NIST P256 (same as secp256r1 / prime256v1), P384 (secp384r1) & P521 (secp521r1),
|
|
107
|
+
their hash-to-curve methods, and OPRFs.
|
|
108
|
+
- ECDSA signatures conform to ....
|
|
109
|
+
- EdDSA conform to RFC8032.
|
|
110
|
+
- Schnorr is only available for secp256k1 and conforms to BIP340.
|
|
170
111
|
|
|
171
|
-
####
|
|
112
|
+
#### ristretto255, decaf448
|
|
172
113
|
|
|
173
114
|
```ts
|
|
174
|
-
|
|
175
|
-
import {
|
|
176
|
-
const priv = 'a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4';
|
|
177
|
-
const pub = 'e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c';
|
|
178
|
-
x25519.getSharedSecret(priv, pub) === x25519.scalarMult(priv, pub); // aliases
|
|
179
|
-
x25519.getPublicKey(priv) === x25519.scalarMultBase(priv);
|
|
180
|
-
x25519.getPublicKey(x25519.utils.randomPrivateKey());
|
|
181
|
-
|
|
182
|
-
// ed25519 => x25519 conversion
|
|
183
|
-
import { edwardsToMontgomeryPub, edwardsToMontgomeryPriv } from '@noble/curves/ed25519.js';
|
|
184
|
-
edwardsToMontgomeryPub(ed25519.getPublicKey(ed25519.utils.randomPrivateKey()));
|
|
185
|
-
edwardsToMontgomeryPriv(ed25519.utils.randomPrivateKey());
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
#### ristretto255
|
|
115
|
+
import { ristretto255, ristretto255_hasher, ristretto255_oprf } from '@noble/curves/ed25519.js';
|
|
116
|
+
import { decaf448, decaf448_hasher, decaf448_oprf } from '@noble/curves/ed448.js';
|
|
189
117
|
|
|
190
|
-
```ts
|
|
191
118
|
import { sha512 } from '@noble/hashes/sha2.js';
|
|
192
|
-
import {
|
|
193
|
-
hashToCurve,
|
|
194
|
-
encodeToCurve,
|
|
195
|
-
RistrettoPoint,
|
|
196
|
-
hashToRistretto255,
|
|
197
|
-
} from '@noble/curves/ed25519.js';
|
|
119
|
+
import { shake256 } from '@noble/hashes/sha3.js';
|
|
198
120
|
|
|
199
121
|
const msg = new TextEncoder().encode('Ristretto is traditionally a short shot of espresso coffee');
|
|
200
122
|
hashToCurve(msg);
|
|
201
123
|
|
|
202
|
-
const
|
|
203
|
-
'
|
|
124
|
+
const dp = DecafPoint.fromHex(
|
|
125
|
+
'c898eb4f87f97c564c6fd61fc7e49689314a1f818ec85eeb3bd5514ac816d38778f69ef347a89fca817e66defdedce178c7cc709b2116e75'
|
|
204
126
|
);
|
|
205
|
-
|
|
206
|
-
|
|
127
|
+
DecafPoint.BASE.multiply(2n).add(dp).subtract(DecafPoint.BASE).toBytes();
|
|
128
|
+
DecafPoint.ZERO.equals(dp) === false;
|
|
207
129
|
// pre-hashed hash-to-curve
|
|
208
|
-
|
|
130
|
+
DecafPoint.hashToCurve(shake256(msg, { dkLen: 112 }));
|
|
209
131
|
// full hash-to-curve including domain separation tag
|
|
210
|
-
|
|
132
|
+
hashToDecaf448(msg, { DST: 'decaf448_XOF:SHAKE256_D448MAP_RO_' });
|
|
211
133
|
```
|
|
212
134
|
|
|
213
|
-
Check out [RFC9496](https://www.rfc-editor.org/rfc/rfc9496) more info on ristretto255.
|
|
135
|
+
Check out [RFC9496](https://www.rfc-editor.org/rfc/rfc9496) more info on ristretto255 & decaf448.
|
|
214
136
|
|
|
215
|
-
####
|
|
137
|
+
#### Prehashed signing
|
|
216
138
|
|
|
217
|
-
|
|
218
|
-
import { ed448 } from '@noble/curves/ed448.js';
|
|
219
|
-
const priv = ed448.utils.randomPrivateKey();
|
|
220
|
-
const pub = ed448.getPublicKey(priv);
|
|
221
|
-
const msg = new TextEncoder().encode('whatsup');
|
|
222
|
-
const sig = ed448.sign(msg, priv);
|
|
223
|
-
ed448.verify(sig, msg, pub);
|
|
224
|
-
|
|
225
|
-
// Variants from RFC8032: prehashed
|
|
226
|
-
import { ed448ph } from '@noble/curves/ed448.js';
|
|
227
|
-
```
|
|
139
|
+
#### Hedged ECDSA with noise
|
|
228
140
|
|
|
229
|
-
####
|
|
141
|
+
#### Consensus-friendliness vs e-voting
|
|
142
|
+
|
|
143
|
+
#### webcrypto: Friendly wrapper
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
```js
|
|
147
|
+
const sig2 = curve.sign(msg, secretKey, { prehash: false })
|
|
148
|
+
const msg = new Uint8Array(32).fill(1); // message hash (not message) in ecdsa
|
|
149
|
+
const sig = secp256k1.sign(msg, priv); // `{prehash: true}` option is available
|
|
150
|
+
const isValid = secp256k1.verify(sig, msg, pub) === true;
|
|
151
|
+
|
|
152
|
+
const isValid = ed25519.verify(sig, msg, pub); // Default mode: follows ZIP215
|
|
153
|
+
|
|
154
|
+
// SBS / e-voting / RFC8032 / FIPS 186-5
|
|
155
|
+
const isValidRfc = ed25519.verify(sig, msg, pub, { zip215: false });
|
|
156
|
+
|
|
157
|
+
// Variants from RFC8032: with context, prehashed
|
|
158
|
+
import { ed25519ctx, ed25519ph } from '@noble/curves/ed25519.js';
|
|
230
159
|
|
|
231
|
-
```ts
|
|
232
|
-
// X448 aka ECDH on Curve448 from [RFC7748](https://www.rfc-editor.org/rfc/rfc7748)
|
|
233
|
-
import { x448 } from '@noble/curves/ed448.js';
|
|
234
|
-
x448.getSharedSecret(priv, pub) === x448.scalarMult(priv, pub); // aliases
|
|
235
|
-
x448.getPublicKey(priv) === x448.scalarMultBase(priv);
|
|
236
160
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
161
|
+
import { secp256k1 } from '@noble/curves/secp256k1.js';
|
|
162
|
+
// random entropy
|
|
163
|
+
const sigNoisy = secp256k1.sign(msg, priv, { extraEntropy: true });
|
|
164
|
+
// set custom entropy
|
|
165
|
+
const ent = new Uint8Array(32).fill(3);
|
|
166
|
+
const sigNoisy2 = secp256k1.sign(msg, priv, { extraEntropy: ent });
|
|
240
167
|
```
|
|
241
168
|
|
|
242
|
-
|
|
169
|
+
- Hedged ECDSA is add-on, providing improved protection against fault attacks.
|
|
170
|
+
It adds noise to signatures.
|
|
171
|
+
The technique is used by default in BIP340; we also implement them optionally for ECDSA.
|
|
172
|
+
Check out blog post [Deterministic signatures are not your friends](https://paulmillr.com/posts/deterministic-signatures/)
|
|
173
|
+
and [cfrg-det-sigs-with-noise draft](https://datatracker.ietf.org/doc/draft-irtf-cfrg-det-sigs-with-noise/).
|
|
174
|
+
- In ed25519 & ed448, default `verify` behavior follows ZIP215 and
|
|
175
|
+
can be used in consensus-critical applications.
|
|
176
|
+
If you need SBS (Strongly Binding Signatures) and FIPS 186-5 compliance,
|
|
177
|
+
use `zip215: false`. Check out [Edwards Signatures section for more info](#edwards-twisted-edwards-curve).
|
|
178
|
+
Both options have SUF-CMA (strong unforgeability under chosen message attacks).
|
|
243
179
|
|
|
244
|
-
|
|
245
|
-
// decaf448 from [RFC9496](https://www.rfc-editor.org/rfc/rfc9496)
|
|
246
|
-
import { shake256 } from '@noble/hashes/sha3.js';
|
|
247
|
-
import { hashToCurve, encodeToCurve, DecafPoint, hashToDecaf448 } from '@noble/curves/ed448.js';
|
|
180
|
+
### ECDH: Diffie-Hellman shared secrets
|
|
248
181
|
|
|
249
|
-
|
|
250
|
-
|
|
182
|
+
```js
|
|
183
|
+
import { secp256k1 } from '@noble/curves/secp256k1.js';
|
|
184
|
+
import { x25519 } from '@noble/curves/ed25519.js';
|
|
185
|
+
import { x448 } from '@noble/curves/ed448.js';
|
|
186
|
+
import { p256, p384, p521 } from '@noble/curves/nist.js';
|
|
251
187
|
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
);
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
188
|
+
for (const curve of [secp256k1, schnorr, x25519, x448, p256, p384, p521]) {
|
|
189
|
+
const alice = curve.keygen();
|
|
190
|
+
const bob = curve.keygen();
|
|
191
|
+
const sharedKey = curve.getSharedSecret(alice.secretKey, bob.publicKey);
|
|
192
|
+
console.log('alice', alice, 'bob', bob, 'shared', sharedKey);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
x25519.getSharedSecret(priv, pub) === x25519.scalarMult(priv, pub); // aliases
|
|
196
|
+
x25519.getPublicKey(priv) === x25519.scalarMultBase(priv);
|
|
197
|
+
// ed25519 => x25519 conversion
|
|
198
|
+
import { edwardsToMontgomeryPub, edwardsToMontgomeryPriv } from '@noble/curves/ed25519.js';
|
|
199
|
+
edwardsToMontgomeryPub(ed25519.getPublicKey(ed25519.utils.randomPrivateKey()));
|
|
200
|
+
edwardsToMontgomeryPriv(ed25519.utils.randomPrivateKey());
|
|
261
201
|
```
|
|
262
202
|
|
|
263
|
-
|
|
203
|
+
- X25519 aka ECDH on Curve25519 from [RFC7748](https://www.rfc-editor.org/rfc/rfc7748).
|
|
204
|
+
- X448 aka ECDH on Curve448 from [RFC7748](https://www.rfc-editor.org/rfc/rfc7748)
|
|
205
|
+
|
|
206
|
+
> [!NOTE]
|
|
207
|
+
> In Weierstrass curves, shared secrets include y-parity bytes. To strip it, use `key.slice(1)`.
|
|
264
208
|
|
|
265
|
-
|
|
209
|
+
> [!NOTE]
|
|
210
|
+
> In Weierstrass curves, shared secrets are not hashed: use hashing or KDF on top, like `sha256(shared)` or `hkdf(shared)`.
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
### BLS signatures, bls12-381, bn254 aka alt_bn128
|
|
266
214
|
|
|
267
215
|
```ts
|
|
268
216
|
import { bls12_381 } from '@noble/curves/bls12-381.js';
|
|
@@ -311,19 +259,11 @@ const aggregatedKey = bls12_381.longSignatures.aggregatePublicKeys([
|
|
|
311
259
|
See [abstract/bls](#bls-barreto-lynn-scott-curves).
|
|
312
260
|
For example usage, check out [the implementation of BLS EVM precompiles](https://github.com/ethereumjs/ethereumjs-monorepo/blob/361f4edbc239e795a411ac2da7e5567298b9e7e5/packages/evm/src/precompiles/bls12_381/noble.ts).
|
|
313
261
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
```ts
|
|
317
|
-
import { bn254 } from '@noble/curves/bn254.js';
|
|
318
|
-
|
|
319
|
-
console.log(bn254.G1, bn254.G2, bn254.pairing);
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
The API mirrors [BLS](#bls12-381). The curve was previously called alt_bn128.
|
|
262
|
+
The BN254 API mirrors [BLS](#bls12-381). The curve was previously called alt_bn128.
|
|
323
263
|
The implementation is compatible with [EIP-196](https://eips.ethereum.org/EIPS/eip-196) and
|
|
324
264
|
[EIP-197](https://eips.ethereum.org/EIPS/eip-197).
|
|
325
265
|
|
|
326
|
-
We don't implement Point methods
|
|
266
|
+
We don't implement Point methods toBytes.
|
|
327
267
|
To work around this limitation, has to initialize points on their own from BigInts.
|
|
328
268
|
Reason it's not implemented is because [there is no standard](https://github.com/privacy-scaling-explorations/halo2curves/issues/109).
|
|
329
269
|
Points of divergence:
|
|
@@ -334,86 +274,76 @@ Points of divergence:
|
|
|
334
274
|
|
|
335
275
|
For example usage, check out [the implementation of bn254 EVM precompiles](https://github.com/paulmillr/noble-curves/blob/3ed792f8ad9932765b84d1064afea8663a255457/test/bn254.test.js#L697).
|
|
336
276
|
|
|
337
|
-
|
|
277
|
+
### Low-level math: EC Point, modular
|
|
338
278
|
|
|
339
|
-
```
|
|
279
|
+
```js
|
|
280
|
+
import { secp256k1, schnorr } from '@noble/curves/secp256k1.js';
|
|
281
|
+
import { p256, p384, p521 } from '@noble/curves/nist.js';
|
|
282
|
+
import { ed25519, ristretto255 } from '@noble/curves/ed25519.js';
|
|
283
|
+
import { ed448, decaf448 } from '@noble/curves/ed448.js';
|
|
284
|
+
import { bls12_381 } from '@noble/curves/bls12-381.js'
|
|
285
|
+
import { bn254 } from '@noble/curves/bn254.js';
|
|
340
286
|
import { jubjub, babyjubjub } from '@noble/curves/misc.js';
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
Miscellaneous, rarely used curves are contained in the module.
|
|
344
|
-
Jubjub curves have Fp over scalar fields of other curves. They are friendly to ZK proofs.
|
|
345
|
-
jubjub Fp = bls n. babyjubjub Fp = bn254 n.
|
|
346
|
-
|
|
347
|
-
## Abstract API
|
|
348
|
-
|
|
349
|
-
Abstract API allows to define custom curves. All arithmetics is done with JS
|
|
350
|
-
bigints over finite fields, which is defined from `modular` sub-module.
|
|
351
|
-
For scalar multiplication, we use
|
|
352
|
-
[precomputed tables with w-ary non-adjacent form (wNAF)](https://paulmillr.com/posts/noble-secp256k1-fast-ecc/).
|
|
353
|
-
Precomputes are enabled for weierstrass and edwards BASE points of a curve.
|
|
354
|
-
Implementations use [noble-hashes](https://github.com/paulmillr/noble-hashes).
|
|
355
|
-
It's always possible to use different hashing library.
|
|
356
|
-
|
|
357
287
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
const
|
|
288
|
+
const curves = [
|
|
289
|
+
secp256k1, schnorr, p256, p384, p521, ed25519, ed448,
|
|
290
|
+
ristretto255, decaf448,
|
|
291
|
+
bls12_381.G1, bls12_381.G2, bn254.G1, bn254.G2,
|
|
292
|
+
jubjub, babyjubjub
|
|
293
|
+
];
|
|
294
|
+
for (const curve of curves) {
|
|
295
|
+
const { info, Point } = curve;
|
|
296
|
+
const { BASE, ZERO, Fp, Fn } = Point;
|
|
297
|
+
const p = BASE.multiply(2n);
|
|
298
|
+
|
|
299
|
+
// Initialization
|
|
300
|
+
if (info.type === 'weierstrass') {
|
|
301
|
+
// projective (homogeneous) coordinates: (X, Y, Z) ∋ (x=X/Z, y=Y/Z)
|
|
302
|
+
const p_ = new Point(BASE.X, BASE.Y, BASE.Z);
|
|
303
|
+
} else if (info.type === 'edwards') {
|
|
304
|
+
// extended coordinates: (X, Y, Z, T) ∋ (x=X/Z, y=Y/Z)
|
|
305
|
+
const p_ = new Point(BASE.X, BASE.Y, BASE.Z, BASE.T);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Math
|
|
309
|
+
const p1 = p.add(p);
|
|
310
|
+
const p2 = p.double();
|
|
311
|
+
const p3 = p.subtract(p);
|
|
312
|
+
const p4 = p.negate();
|
|
313
|
+
const p5 = p.multiply(451n);
|
|
314
|
+
|
|
315
|
+
// MSM (multi-scalar multiplication)
|
|
316
|
+
const pa = [BASE, BASE.multiply(2n), BASE.multiply(4n), BASE.multiply(8n)];
|
|
317
|
+
const p6 = Point.msm(pa, [3n, 5n, 7n, 11n]);
|
|
318
|
+
const _true3 = p6.equals(BASE.multiply(129n)); // 129*G
|
|
319
|
+
|
|
320
|
+
const pcl = p.clearCofactor();
|
|
321
|
+
console.log(p.isTorsionFree(), p.isSmallOrder());
|
|
322
|
+
|
|
323
|
+
const r1 = p.toBytes();
|
|
324
|
+
const r1_ = Point.fromBytes(r1);
|
|
325
|
+
const r2 = p.toAffine();
|
|
326
|
+
const { x, y } = r2;
|
|
327
|
+
const r2_ = Point.fromAffine(r2);
|
|
328
|
+
}
|
|
373
329
|
```
|
|
374
330
|
|
|
375
|
-
|
|
376
|
-
expects arguments `a`, `b`, field characteristic `p`, curve order `n`,
|
|
377
|
-
cofactor `h` and coordinates `Gx`, `Gy` of generator point.
|
|
378
|
-
|
|
379
|
-
#### Projective Weierstrass Point
|
|
331
|
+
#### Modular math
|
|
380
332
|
|
|
381
333
|
```js
|
|
382
|
-
|
|
383
|
-
// projective (homogeneous) coordinates: (x, y, z) ∋ (x=x/z, y=y/z)
|
|
384
|
-
// const p = new Point(x, y, z);
|
|
385
|
-
const p = Point.BASE;
|
|
386
|
-
// arithmetics
|
|
387
|
-
p.add(p).equals(p.double());
|
|
388
|
-
p.subtract(p).equals(Point.ZERO);
|
|
389
|
-
p.negate();
|
|
390
|
-
p.multiply(31415n);
|
|
391
|
-
|
|
392
|
-
// decoding, encoding
|
|
393
|
-
const b = p.toBytes();
|
|
394
|
-
const p2 = Point.fromBytes(b);
|
|
395
|
-
// affine conversion
|
|
396
|
-
const { x, y } = p.toAffine();
|
|
397
|
-
const p3 = Point.fromAffine({ x, y });
|
|
398
|
-
|
|
399
|
-
// Multi-scalar-multiplication (MSM) is basically `(Pa + Qb + Rc + ...)`.
|
|
400
|
-
// It's 10-30x faster vs naive addition for large amount of points.
|
|
401
|
-
// Pippenger algorithm is used underneath.
|
|
402
|
-
const points = [Point.BASE, Point.BASE.multiply(2n), Point.BASE.multiply(4n), Point.BASE.multiply(8n)];
|
|
403
|
-
Point.msm(points, [3n, 5n, 7n, 11n]).equals(Point.BASE.multiply(129n)); // 129*G
|
|
404
|
-
```
|
|
334
|
+
import { mod, invert, Field } from '@noble/curves/abstract/modular.js';
|
|
405
335
|
|
|
406
|
-
|
|
336
|
+
// Finite Field utils
|
|
337
|
+
const fp = Field(2n ** 255n - 19n); // Finite field over 2^255-19
|
|
338
|
+
fp.mul(591n, 932n); // multiplication
|
|
339
|
+
fp.pow(481n, 11024858120n); // exponentiation
|
|
340
|
+
fp.div(5n, 17n); // division: 5/17 mod 2^255-19 == 5 * invert(17)
|
|
341
|
+
fp.inv(5n); // modular inverse
|
|
342
|
+
fp.sqrt(21n); // square root
|
|
407
343
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
const p192 = ecdsa(p192_Point, sha256);
|
|
412
|
-
const priv = p192.utils.randomPrivateKey();
|
|
413
|
-
const pub = p192.getPublicKey(priv);
|
|
414
|
-
const msg = sha256(new TextEncoder().encode('custom curve'));
|
|
415
|
-
const sig = p192.sign(msg);
|
|
416
|
-
const isValid = p192.verify(sig, msg, pub);
|
|
344
|
+
// Non-Field generic utils are also available
|
|
345
|
+
mod(21n, 10n); // 21 mod 10 == 1n; fixed version of 21 % 10
|
|
346
|
+
invert(17n, 10n); // invert(17) mod 10; modular multiplicative inverse
|
|
417
347
|
```
|
|
418
348
|
|
|
419
349
|
ECDSA signatures:
|
|
@@ -427,61 +357,21 @@ ECDSA signatures:
|
|
|
427
357
|
- Consider [hedged ECDSA with noise](#hedged-ecdsa-with-noise) for adding randomness into
|
|
428
358
|
for signatures, to get improved security against fault attacks.
|
|
429
359
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
a: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffecn,
|
|
439
|
-
d: 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n,
|
|
440
|
-
Gx: 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an,
|
|
441
|
-
Gy: 0x6666666666666666666666666666666666666666666666666666666666666658n,
|
|
442
|
-
};
|
|
443
|
-
const ed25519_Point = edwards(ed25519_CURVE);
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
Twisted Edwards curve's formula is `ax² + y² = 1 + dx²y²`.
|
|
447
|
-
You must specify `a`, `d`, field characteristic `p`, curve order `n` (sometimes named as `L`),
|
|
448
|
-
cofactor `h` and coordinates `Gx`, `Gy` of generator point.
|
|
449
|
-
|
|
450
|
-
#### Extended Edwards Point
|
|
451
|
-
|
|
452
|
-
```js
|
|
453
|
-
const Point = ed25519_Point;
|
|
454
|
-
// extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z)
|
|
455
|
-
// const p = new Point(x, y, z, t);
|
|
456
|
-
|
|
457
|
-
const p = Point.BASE;
|
|
458
|
-
// arithmetics
|
|
459
|
-
p.add(p).equals(p.double());
|
|
460
|
-
p.subtract(p).equals(Point.ZERO);
|
|
461
|
-
p.negate();
|
|
462
|
-
p.multiply(31415n);
|
|
463
|
-
|
|
464
|
-
// decoding, encoding
|
|
465
|
-
const b = p.toBytes();
|
|
466
|
-
const p2 = Point.fromBytes(b);
|
|
467
|
-
// on-curve test
|
|
468
|
-
p.assertValidity();
|
|
469
|
-
// affine conversion
|
|
470
|
-
const { x, y } = p.toAffine();
|
|
471
|
-
const p3 = Point.fromAffine({ x, y });
|
|
472
|
-
// misc
|
|
473
|
-
const pcl = p.clearCofactor();
|
|
474
|
-
console.log(p.isTorsionFree(), p.isSmallOrder());
|
|
475
|
-
```
|
|
360
|
+
All arithmetics is done with JS
|
|
361
|
+
bigints over finite fields, which is defined from `modular` sub-module.
|
|
362
|
+
For scalar multiplication, we use
|
|
363
|
+
[precomputed tables with w-ary non-adjacent form (wNAF)](https://paulmillr.com/posts/noble-secp256k1-fast-ecc/).
|
|
364
|
+
Precomputes are enabled for weierstrass and edwards BASE points of a curve.
|
|
365
|
+
Field operations are not constant-time: they are using JS bigints, see [security](#security).
|
|
366
|
+
The fact is mostly irrelevant, but the important method to keep in mind is `pow`,
|
|
367
|
+
which may leak exponent bits, when used naïvely.
|
|
476
368
|
|
|
477
|
-
|
|
369
|
+
`mod.Field` is always **field over prime number**. Non-prime fields aren't supported for now.
|
|
370
|
+
We don't test for prime-ness for speed and because algorithms are probabilistic anyway.
|
|
371
|
+
Initializing a non-prime field could make your app suspectible to
|
|
372
|
+
DoS (infilite loop) on Tonelli-Shanks square root calculation.
|
|
478
373
|
|
|
479
|
-
|
|
480
|
-
const ed25519 = eddsa(ed25519_Point, { hash: sha512 });
|
|
481
|
-
// ed25519.getPublicKey();
|
|
482
|
-
// ed25519.sign();
|
|
483
|
-
// ed25519.verify();
|
|
484
|
-
```
|
|
374
|
+
Unlike `mod.inv`, `mod.invertBatch` won't throw on `0`: make sure to throw an error yourself.
|
|
485
375
|
|
|
486
376
|
We define ed25519, ed448; user can use custom curves with EdDSA,
|
|
487
377
|
but EdDSA in general is not defined. Check out `edwards.ts` source code.
|
|
@@ -499,84 +389,98 @@ For EdDSA signatures:
|
|
|
499
389
|
- Blockchains: transaction of amount X might also be valid for a different amount Y
|
|
500
390
|
- Both modes have SUF-CMA (strong unforgeability under chosen message attacks).
|
|
501
391
|
|
|
502
|
-
###
|
|
392
|
+
### Making custom curves
|
|
503
393
|
|
|
504
|
-
|
|
505
|
-
|
|
394
|
+
- Short Weierstrass curve's formula is `y² = x³ + ax + b`. `weierstrass`
|
|
395
|
+
expects arguments `a`, `b`, field characteristic `p`, curve order `n`,
|
|
396
|
+
cofactor `h` and coordinates `Gx`, `Gy` of generator point.
|
|
397
|
+
- Twisted Edwards curve's formula is `ax² + y² = 1 + dx²y²`.
|
|
398
|
+
You must specify `a`, `d`, field characteristic `p`, curve order `n` (sometimes named as `L`),
|
|
399
|
+
cofactor `h` and coordinates `Gx`, `Gy` of generator point.
|
|
506
400
|
|
|
507
|
-
|
|
401
|
+
#### Custom Weierstrass curve
|
|
508
402
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
403
|
+
```js
|
|
404
|
+
import { weierstrass } from '@noble/curves/abstract/weierstrass.js';
|
|
405
|
+
// NIST secp192r1 aka p192. https://www.secg.org/sec2-v2.pdf
|
|
406
|
+
const p192_CURVE = {
|
|
407
|
+
p: 0xfffffffffffffffffffffffffffffffeffffffffffffffffn,
|
|
408
|
+
n: 0xffffffffffffffffffffffff99def836146bc9b1b4d22831n,
|
|
409
|
+
h: 1n,
|
|
410
|
+
a: 0xfffffffffffffffffffffffffffffffefffffffffffffffcn,
|
|
411
|
+
b: 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1n,
|
|
412
|
+
Gx: 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012n,
|
|
413
|
+
Gy: 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811n,
|
|
414
|
+
};
|
|
415
|
+
const p192_Point = weierstrass(p192_CURVE);
|
|
416
|
+
```
|
|
514
417
|
|
|
515
|
-
|
|
516
|
-
Only BLS12-381 is currently implemented.
|
|
517
|
-
Defining BLS12-377 and BLS24 should be straightforward.
|
|
418
|
+
#### Custom Edwards curve
|
|
518
419
|
|
|
519
|
-
|
|
520
|
-
|
|
420
|
+
```js
|
|
421
|
+
import { edwards } from '@noble/curves/abstract/edwards.js';
|
|
422
|
+
const ed25519_CURVE = {
|
|
423
|
+
p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn,
|
|
424
|
+
n: 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn,
|
|
425
|
+
h: 8n,
|
|
426
|
+
a: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffecn,
|
|
427
|
+
d: 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n,
|
|
428
|
+
Gx: 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an,
|
|
429
|
+
Gy: 0x6666666666666666666666666666666666666666666666666666666666666658n,
|
|
430
|
+
};
|
|
431
|
+
const ed25519_Point = edwards(ed25519_CURVE);
|
|
432
|
+
```
|
|
521
433
|
|
|
522
|
-
|
|
434
|
+
#### Custom ECDSA, requires curve and hash
|
|
523
435
|
|
|
524
|
-
|
|
436
|
+
```js
|
|
437
|
+
import { ecdsa } from '@noble/curves/abstract/weierstrass.js';
|
|
438
|
+
import { sha256 } from '@noble/hashes/sha2.js';
|
|
439
|
+
const p192 = ecdsa(p192_Point, sha256);
|
|
440
|
+
const p192_sha224 = ecdsa(p192.Point, sha224);
|
|
441
|
+
const keys = p192.keygen();
|
|
442
|
+
const msg = new TextEncoder().encode('custom curve');
|
|
443
|
+
const sig = p192.sign(msg, keys.secretKey);
|
|
444
|
+
const isValid = p192.verify(sig, msg, keys.publicKey);
|
|
445
|
+
// const ed25519 = eddsa(ed25519_Point, { hash: sha512 });
|
|
446
|
+
```
|
|
525
447
|
|
|
526
|
-
|
|
448
|
+
### hash-to-curve: hashing to curve points
|
|
527
449
|
|
|
528
450
|
```ts
|
|
529
|
-
import {
|
|
530
|
-
import {
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
console.log(encodeToCurve(randomBytes()));
|
|
451
|
+
import { secp256k1_hasher } from '@noble/curves/secp256k1.js';
|
|
452
|
+
import { p256_hasher, p384_hasher, p521_hasher } from '@noble/curves/nist.js';
|
|
453
|
+
import { ristretto255_hasher } from '@noble/curves/ed25519.js';
|
|
454
|
+
import { decaf448_hasher } from '@noble/curves/ed448.js';
|
|
534
455
|
|
|
535
456
|
import { bls12_381 } from '@noble/curves/bls12-381.js';
|
|
536
457
|
bls12_381.G1.hashToCurve(randomBytes(), { DST: 'another' });
|
|
537
458
|
bls12_381.G2.hashToCurve(randomBytes(), { DST: 'custom' });
|
|
459
|
+
|
|
460
|
+
import { expand_message_xmd, expand_message_xof, hash_to_field } from '@noble/curves/abstract/hash-to-curve.js';
|
|
538
461
|
```
|
|
539
462
|
|
|
540
|
-
|
|
463
|
+
The module allows to hash arbitrary strings to elliptic curve points. Implements [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380).
|
|
541
464
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
// produces a uniformly random byte string using an extendable-output function (XOF) H.
|
|
551
|
-
function expand_message_xof(
|
|
552
|
-
msg: Uint8Array,
|
|
553
|
-
DST: Uint8Array,
|
|
554
|
-
lenInBytes: number,
|
|
555
|
-
k: number,
|
|
556
|
-
H: CHash
|
|
557
|
-
): Uint8Array;
|
|
558
|
-
// Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F
|
|
559
|
-
function hash_to_field(msg: Uint8Array, count: number, options: Opts): bigint[][];
|
|
560
|
-
|
|
561
|
-
/**
|
|
562
|
-
* * `DST` is a domain separation tag, defined in section 2.2.5
|
|
563
|
-
* * `p` characteristic of F, where F is a finite field of characteristic p and order q = p^m
|
|
564
|
-
* * `m` is extension degree (1 for prime fields)
|
|
565
|
-
* * `k` is the target security target in bits (e.g. 128), from section 5.1
|
|
566
|
-
* * `expand` is `xmd` (SHA2, SHA3, BLAKE) or `xof` (SHAKE, BLAKE-XOF)
|
|
567
|
-
* * `hash` conforming to `utils.CHash` interface, with `outputLen` / `blockLen` props
|
|
568
|
-
*/
|
|
569
|
-
type UnicodeOrBytes = string | Uint8Array;
|
|
570
|
-
type Opts = {
|
|
571
|
-
DST: UnicodeOrBytes;
|
|
572
|
-
p: bigint;
|
|
573
|
-
m: number;
|
|
574
|
-
k: number;
|
|
575
|
-
expand?: 'xmd' | 'xof';
|
|
576
|
-
hash: CHash;
|
|
577
|
-
};
|
|
465
|
+
Every curve has exported `hashToCurve` and `encodeToCurve` methods. You should always prefer `hashToCurve` for security:
|
|
466
|
+
|
|
467
|
+
### oprf: oblivious pseudorandom functions
|
|
468
|
+
|
|
469
|
+
```js
|
|
470
|
+
import { p256_oprf, p384_oprf, p521_oprf } from '@noble/curves/nist.js';
|
|
471
|
+
import { ristretto255_oprf } from '@noble/curves/ed25519.js';
|
|
472
|
+
import { decaf448_orpf } from '@noble/curves/ed448.js';
|
|
578
473
|
```
|
|
579
474
|
|
|
475
|
+
We provide OPRFs, conforming to [RFC 9497](https://www.rfc-editor.org/rfc/rfc9497).
|
|
476
|
+
|
|
477
|
+
OPRF allows to interactively create an `Output = PRF(Input, serverSecretKey)`:
|
|
478
|
+
|
|
479
|
+
- Server cannot calculate Output by itself: it doesn't know Input
|
|
480
|
+
- Client cannot calculate Output by itself: it doesn't know server secretKey
|
|
481
|
+
- An attacker interception the communication can't restore Input/Output/serverSecretKey and can't
|
|
482
|
+
link Input to some value.
|
|
483
|
+
|
|
580
484
|
### poseidon: Poseidon hash
|
|
581
485
|
|
|
582
486
|
Implements [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash:
|
|
@@ -611,36 +515,6 @@ const permutation = poseidon.poseidon(opts);
|
|
|
611
515
|
const sponge = poseidon.poseidonSponge(opts); // use carefully, not specced
|
|
612
516
|
```
|
|
613
517
|
|
|
614
|
-
### modular: Modular arithmetics utilities
|
|
615
|
-
|
|
616
|
-
```ts
|
|
617
|
-
import * as mod from '@noble/curves/abstract/modular.js';
|
|
618
|
-
|
|
619
|
-
// Finite Field utils
|
|
620
|
-
const fp = mod.Field(2n ** 255n - 19n); // Finite field over 2^255-19
|
|
621
|
-
fp.mul(591n, 932n); // multiplication
|
|
622
|
-
fp.pow(481n, 11024858120n); // exponentiation
|
|
623
|
-
fp.div(5n, 17n); // division: 5/17 mod 2^255-19 == 5 * invert(17)
|
|
624
|
-
fp.inv(5n); // modular inverse
|
|
625
|
-
fp.sqrt(21n); // square root
|
|
626
|
-
|
|
627
|
-
// Non-Field generic utils are also available
|
|
628
|
-
mod.mod(21n, 10n); // 21 mod 10 == 1n; fixed version of 21 % 10
|
|
629
|
-
mod.invert(17n, 10n); // invert(17) mod 10; modular multiplicative inverse
|
|
630
|
-
mod.invertBatch([1n, 2n, 4n], 21n); // => [1n, 11n, 16n] in one inversion
|
|
631
|
-
```
|
|
632
|
-
|
|
633
|
-
Field operations are not constant-time: they are using JS bigints, see [security](#security).
|
|
634
|
-
The fact is mostly irrelevant, but the important method to keep in mind is `pow`,
|
|
635
|
-
which may leak exponent bits, when used naïvely.
|
|
636
|
-
|
|
637
|
-
`mod.Field` is always **field over prime number**. Non-prime fields aren't supported for now.
|
|
638
|
-
We don't test for prime-ness for speed and because algorithms are probabilistic anyway.
|
|
639
|
-
Initializing a non-prime field could make your app suspectible to
|
|
640
|
-
DoS (infilite loop) on Tonelli-Shanks square root calculation.
|
|
641
|
-
|
|
642
|
-
Unlike `mod.inv`, `mod.invertBatch` won't throw on `0`: make sure to throw an error yourself.
|
|
643
|
-
|
|
644
518
|
### fft: Fast Fourier Transform
|
|
645
519
|
|
|
646
520
|
Experimental implementation of NTT / FFT (Fast Fourier Transform) over finite fields.
|
|
@@ -650,30 +524,7 @@ API may change at any time. The code has not been audited. Feature requests are
|
|
|
650
524
|
import * as fft from '@noble/curves/abstract/fft.js';
|
|
651
525
|
```
|
|
652
526
|
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
You can't simply make a 32-byte private key from a 32-byte hash.
|
|
656
|
-
Doing so will make the key [biased](https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/).
|
|
657
|
-
|
|
658
|
-
To make the bias negligible, we follow [FIPS 186-5 A.2](https://csrc.nist.gov/publications/detail/fips/186/5/final)
|
|
659
|
-
and [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380#section-5.2).
|
|
660
|
-
This means, for 32-byte key, we would need 48-byte hash to get 2^-128 bias, which matches curve security level.
|
|
661
|
-
|
|
662
|
-
`hashToPrivateScalar()` that hashes to **private key** was created for this purpose.
|
|
663
|
-
Use [abstract/hash-to-curve](#hash-to-curve-hashing-strings-to-curve-points)
|
|
664
|
-
if you need to hash to **public key**.
|
|
665
|
-
|
|
666
|
-
```ts
|
|
667
|
-
import { p256 } from '@noble/curves/nist.js';
|
|
668
|
-
import { sha256 } from '@noble/hashes/sha2.js';
|
|
669
|
-
import { hkdf } from '@noble/hashes/hkdf.js';
|
|
670
|
-
import * as mod from '@noble/curves/abstract/modular.js';
|
|
671
|
-
const someKey = new Uint8Array(32).fill(2); // Needs to actually be random, not .fill(2)
|
|
672
|
-
const derived = hkdf(sha256, someKey, undefined, 'application', 48); // 48 bytes for 32-byte priv
|
|
673
|
-
const validPrivateKey = mod.hashToPrivateScalar(derived, p256.CURVE.n);
|
|
674
|
-
```
|
|
675
|
-
|
|
676
|
-
### utils: Useful utilities
|
|
527
|
+
### utils: byte shuffling, conversion
|
|
677
528
|
|
|
678
529
|
```ts
|
|
679
530
|
import * as utils from '@noble/curves/abstract/utils.js';
|
|
@@ -693,11 +544,6 @@ utils.nLength(255n);
|
|
|
693
544
|
utils.equalBytes(Uint8Array.from([0xde]), Uint8Array.from([0xde]));
|
|
694
545
|
```
|
|
695
546
|
|
|
696
|
-
### Unreleased bits
|
|
697
|
-
|
|
698
|
-
- `test/unreleased-xeddsa.ts` contains implementation of XEd25519, defined by Signal
|
|
699
|
-
- `test/misc/endomorphism.js` contains tool for generation of endomorphism params for Koblitz curves
|
|
700
|
-
|
|
701
547
|
## Security
|
|
702
548
|
|
|
703
549
|
The library has been independently audited:
|
|
@@ -723,7 +569,7 @@ The library has been independently audited:
|
|
|
723
569
|
- The audit has been funded by [Ryan Shea](https://www.shea.io)
|
|
724
570
|
|
|
725
571
|
It is tested against property-based, cross-library and Wycheproof vectors,
|
|
726
|
-
and is being fuzzed in [the separate repo](https://github.com/paulmillr/
|
|
572
|
+
and is being fuzzed in [the separate repo](https://github.com/paulmillr/integration-tests).
|
|
727
573
|
|
|
728
574
|
If you see anything unusual: investigate and report.
|
|
729
575
|
|