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