@noble/curves 0.6.4 → 0.7.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 +429 -281
- package/{lib/_shortw_utils.d.ts → _shortw_utils.d.ts} +1 -0
- package/_shortw_utils.d.ts.map +1 -0
- package/{lib/_shortw_utils.js → _shortw_utils.js} +2 -0
- package/_shortw_utils.js.map +1 -0
- package/{lib/abstract → abstract}/bls.d.ts +4 -9
- package/abstract/bls.d.ts.map +1 -0
- package/{lib/abstract → abstract}/bls.js +12 -25
- package/abstract/bls.js.map +1 -0
- package/{lib/abstract → abstract}/curve.d.ts +1 -0
- package/abstract/curve.d.ts.map +1 -0
- package/{lib/abstract → abstract}/curve.js +1 -0
- package/abstract/curve.js.map +1 -0
- package/{lib/abstract → abstract}/edwards.d.ts +1 -0
- package/abstract/edwards.d.ts.map +1 -0
- package/{lib/abstract → abstract}/edwards.js +9 -15
- package/abstract/edwards.js.map +1 -0
- package/{lib/abstract → abstract}/hash-to-curve.d.ts +5 -5
- package/abstract/hash-to-curve.d.ts.map +1 -0
- package/{lib/abstract → abstract}/hash-to-curve.js +41 -38
- package/abstract/hash-to-curve.js.map +1 -0
- package/{lib/abstract → abstract}/modular.d.ts +1 -0
- package/abstract/modular.d.ts.map +1 -0
- package/{lib/abstract → abstract}/modular.js +2 -1
- package/abstract/modular.js.map +1 -0
- package/{lib/abstract → abstract}/montgomery.d.ts +1 -0
- package/abstract/montgomery.d.ts.map +1 -0
- package/{lib/abstract → abstract}/montgomery.js +3 -2
- package/abstract/montgomery.js.map +1 -0
- package/{lib/abstract → abstract}/poseidon.d.ts +1 -0
- package/abstract/poseidon.d.ts.map +1 -0
- package/{lib/abstract → abstract}/poseidon.js +1 -0
- package/abstract/poseidon.js.map +1 -0
- package/{lib/abstract → abstract}/utils.d.ts +12 -1
- package/abstract/utils.d.ts.map +1 -0
- package/{lib/abstract → abstract}/utils.js +96 -10
- package/abstract/utils.js.map +1 -0
- package/{lib/abstract → abstract}/weierstrass.d.ts +4 -3
- package/abstract/weierstrass.d.ts.map +1 -0
- package/{lib/abstract → abstract}/weierstrass.js +45 -91
- package/abstract/weierstrass.js.map +1 -0
- package/{lib/bls12-381.d.ts → bls12-381.d.ts} +1 -0
- package/bls12-381.d.ts.map +1 -0
- package/{lib/bls12-381.js → bls12-381.js} +41 -7
- package/bls12-381.js.map +1 -0
- package/{lib/bn.d.ts → bn.d.ts} +1 -0
- package/bn.d.ts.map +1 -0
- package/{lib/bn.js → bn.js} +1 -0
- package/bn.js.map +1 -0
- package/{lib/ed25519.d.ts → ed25519.d.ts} +2 -1
- package/ed25519.d.ts.map +1 -0
- package/{lib/ed25519.js → ed25519.js} +4 -3
- package/ed25519.js.map +1 -0
- package/{lib/ed448.d.ts → ed448.d.ts} +2 -1
- package/ed448.d.ts.map +1 -0
- package/{lib/ed448.js → ed448.js} +2 -1
- package/ed448.js.map +1 -0
- package/{lib/esm → esm}/_shortw_utils.js +2 -0
- package/esm/_shortw_utils.js.map +1 -0
- package/{lib/esm → esm}/abstract/bls.js +13 -26
- package/esm/abstract/bls.js.map +1 -0
- package/{lib/esm → esm}/abstract/curve.js +1 -0
- package/esm/abstract/curve.js.map +1 -0
- package/{lib/esm → esm}/abstract/edwards.js +9 -15
- package/esm/abstract/edwards.js.map +1 -0
- package/{lib/esm → esm}/abstract/hash-to-curve.js +40 -36
- package/esm/abstract/hash-to-curve.js.map +1 -0
- package/{lib/esm → esm}/abstract/modular.js +2 -1
- package/esm/abstract/modular.js.map +1 -0
- package/{lib/esm → esm}/abstract/montgomery.js +3 -2
- package/esm/abstract/montgomery.js.map +1 -0
- package/{lib/esm → esm}/abstract/poseidon.js +1 -0
- package/esm/abstract/poseidon.js.map +1 -0
- package/{lib/esm → esm}/abstract/utils.js +93 -9
- package/esm/abstract/utils.js.map +1 -0
- package/{lib/esm → esm}/abstract/weierstrass.js +45 -91
- package/esm/abstract/weierstrass.js.map +1 -0
- package/{lib/esm → esm}/bls12-381.js +41 -7
- package/esm/bls12-381.js.map +1 -0
- package/{lib/esm → esm}/bn.js +1 -0
- package/esm/bn.js.map +1 -0
- package/{lib/esm → esm}/ed25519.js +5 -4
- package/esm/ed25519.js.map +1 -0
- package/{lib/esm → esm}/ed448.js +2 -1
- package/esm/ed448.js.map +1 -0
- package/{lib → esm}/index.js +1 -0
- package/esm/index.js.map +1 -0
- package/{lib/esm → esm}/jubjub.js +1 -0
- package/esm/jubjub.js.map +1 -0
- package/{lib/esm → esm}/p192.js +1 -0
- package/esm/p192.js.map +1 -0
- package/{lib/esm → esm}/p224.js +1 -0
- package/esm/p224.js.map +1 -0
- package/{lib/esm → esm}/p256.js +2 -1
- package/esm/p256.js.map +1 -0
- package/{lib/esm → esm}/p384.js +2 -1
- package/esm/p384.js.map +1 -0
- package/{lib/esm → esm}/p521.js +2 -1
- package/esm/p521.js.map +1 -0
- package/{lib/esm → esm}/package.json +0 -0
- package/{lib/esm → esm}/pasta.js +1 -0
- package/esm/pasta.js.map +1 -0
- package/{lib/esm → esm}/secp256k1.js +41 -50
- package/esm/secp256k1.js.map +1 -0
- package/{lib/esm → esm}/stark.js +1 -0
- package/esm/stark.js.map +1 -0
- package/index.d.ts +1 -0
- package/index.d.ts.map +1 -0
- package/index.js +3 -0
- package/index.js.map +1 -0
- package/{lib/jubjub.d.ts → jubjub.d.ts} +1 -0
- package/jubjub.d.ts.map +1 -0
- package/{lib/jubjub.js → jubjub.js} +1 -0
- package/jubjub.js.map +1 -0
- package/{lib/p192.d.ts → p192.d.ts} +1 -0
- package/p192.d.ts.map +1 -0
- package/{lib/p192.js → p192.js} +1 -0
- package/p192.js.map +1 -0
- package/{lib/p224.d.ts → p224.d.ts} +1 -0
- package/p224.d.ts.map +1 -0
- package/{lib/p224.js → p224.js} +1 -0
- package/p224.js.map +1 -0
- package/{lib/p256.d.ts → p256.d.ts} +2 -1
- package/p256.d.ts.map +1 -0
- package/{lib/p256.js → p256.js} +2 -1
- package/p256.js.map +1 -0
- package/{lib/p384.d.ts → p384.d.ts} +2 -1
- package/p384.d.ts.map +1 -0
- package/{lib/p384.js → p384.js} +2 -1
- package/p384.js.map +1 -0
- package/{lib/p521.d.ts → p521.d.ts} +2 -1
- package/p521.d.ts.map +1 -0
- package/{lib/p521.js → p521.js} +2 -1
- package/p521.js.map +1 -0
- package/package.json +84 -79
- package/{lib/pasta.d.ts → pasta.d.ts} +1 -0
- package/pasta.d.ts.map +1 -0
- package/{lib/pasta.js → pasta.js} +1 -0
- package/pasta.js.map +1 -0
- package/{lib/secp256k1.d.ts → secp256k1.d.ts} +15 -5
- package/secp256k1.d.ts.map +1 -0
- package/{lib/secp256k1.js → secp256k1.js} +38 -47
- package/secp256k1.js.map +1 -0
- package/src/_shortw_utils.ts +20 -0
- package/src/abstract/bls.ts +376 -0
- package/src/abstract/curve.ts +199 -0
- package/src/abstract/edwards.ts +479 -0
- package/src/abstract/hash-to-curve.ts +220 -0
- package/src/abstract/modular.ts +417 -0
- package/src/abstract/montgomery.ts +184 -0
- package/src/abstract/poseidon.ts +119 -0
- package/src/abstract/utils.ts +246 -0
- package/src/abstract/weierstrass.ts +1175 -0
- package/src/bls12-381.ts +1274 -0
- package/src/bn.ts +21 -0
- package/src/ed25519.ts +428 -0
- package/src/ed448.ts +241 -0
- package/{lib/esm/index.js → src/index.ts} +0 -1
- package/src/jubjub.ts +58 -0
- package/src/p192.ts +25 -0
- package/src/p224.ts +25 -0
- package/src/p256.ts +53 -0
- package/src/p384.ts +57 -0
- package/src/p521.ts +57 -0
- package/src/pasta.ts +31 -0
- package/src/secp256k1.ts +260 -0
- package/src/stark.ts +356 -0
- package/{lib/stark.d.ts → stark.d.ts} +1 -0
- package/stark.d.ts.map +1 -0
- package/{lib/stark.js → stark.js} +1 -0
- package/stark.js.map +1 -0
- package/lib/index.d.ts +0 -0
package/README.md
CHANGED
|
@@ -1,36 +1,35 @@
|
|
|
1
1
|
# noble-curves
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Audited & minimal JS implementation of elliptic curve cryptography.
|
|
4
4
|
|
|
5
|
+
- **noble** family, zero dependencies
|
|
5
6
|
- Short Weierstrass, Edwards, Montgomery curves
|
|
6
7
|
- ECDSA, EdDSA, Schnorr, BLS signature schemes, ECDH key agreement
|
|
7
|
-
- [hash to curve](https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/)
|
|
8
|
-
for encoding or hashing an arbitrary string to
|
|
9
|
-
- [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash
|
|
8
|
+
- #️⃣ [hash to curve](https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/)
|
|
9
|
+
for encoding or hashing an arbitrary string to an elliptic curve point
|
|
10
|
+
- 🧜♂️ [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash
|
|
10
11
|
- 🏎 [Ultra-fast](#speed), hand-optimized for caveats of JS engines
|
|
11
12
|
- 🔍 Unique tests ensure correctness. Wycheproof vectors included
|
|
12
13
|
- 🔻 Tree-shaking-friendly: there is no entry point, which ensures small size of your app
|
|
13
14
|
|
|
14
15
|
Package consists of two parts:
|
|
15
16
|
|
|
16
|
-
1.
|
|
17
|
-
2.
|
|
17
|
+
1. [Abstract](#abstract-api), zero-dependency EC algorithms
|
|
18
|
+
2. [Implementations](#implementations), utilizing one dependency `@noble/hashes`, providing ready-to-use:
|
|
18
19
|
- NIST curves secp192r1/P192, secp224r1/P224, secp256r1/P256, secp384r1/P384, secp521r1/P521
|
|
19
20
|
- SECG curve secp256k1
|
|
21
|
+
- ed25519/curve25519/x25519/ristretto255, edwards448/curve448/x448 RFC7748 / RFC8032 / ZIP215 stuff
|
|
20
22
|
- pairing-friendly curves bls12-381, bn254
|
|
21
|
-
- ed25519/curve25519/x25519/ristretto, edwards448/curve448/x448 RFC7748 / RFC8032 / ZIP215 stuff
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
([secp256k1](https://github.com/paulmillr/noble-secp256k1),
|
|
25
|
-
[
|
|
26
|
-
which had security audits and were developed from 2019 to 2022.
|
|
27
|
-
Check out [Upgrading](#upgrading) section if you've used them before.
|
|
24
|
+
Check out [Upgrading](#upgrading) if you've previously used single-feature noble packages
|
|
25
|
+
([secp256k1](https://github.com/paulmillr/noble-secp256k1), [ed25519](https://github.com/paulmillr/noble-ed25519)).
|
|
26
|
+
See [In the wild](#in-the-wild) for real-world software that uses curves.
|
|
28
27
|
|
|
29
28
|
### This library belongs to _noble_ crypto
|
|
30
29
|
|
|
31
30
|
> **noble-crypto** — high-security, easily auditable set of contained cryptographic libraries and tools.
|
|
32
31
|
|
|
33
|
-
-
|
|
32
|
+
- No dependencies, protection against supply chain attacks
|
|
34
33
|
- Easily auditable TypeScript/JS code
|
|
35
34
|
- Supported in all major browsers and stable node.js versions
|
|
36
35
|
- All releases are signed with PGP keys
|
|
@@ -42,15 +41,41 @@ Check out [Upgrading](#upgrading) section if you've used them before.
|
|
|
42
41
|
|
|
43
42
|
## Usage
|
|
44
43
|
|
|
45
|
-
Use NPM
|
|
46
|
-
[GitHub's releases page](https://github.com/paulmillr/noble-curves/releases):
|
|
44
|
+
Use NPM for browser / node.js:
|
|
47
45
|
|
|
48
46
|
> npm install @noble/curves
|
|
49
47
|
|
|
50
|
-
|
|
48
|
+
For [Deno](https://deno.land), use it with npm specifier. In browser, you could also include the single file from
|
|
49
|
+
[GitHub's releases page](https://github.com/paulmillr/noble-curves/releases).
|
|
50
|
+
|
|
51
|
+
The library is tree-shaking-friendly and does not expose root entry point as `import * from '@noble/curves'`.
|
|
52
|
+
Instead, you need to import specific primitives. This is done to ensure small size of your apps.
|
|
53
|
+
|
|
54
|
+
### Implementations
|
|
55
|
+
|
|
56
|
+
Each curve can be used in the following way:
|
|
51
57
|
|
|
52
58
|
```ts
|
|
53
|
-
import { secp256k1 } from '@noble/curves/secp256k1';
|
|
59
|
+
import { secp256k1 } from '@noble/curves/secp256k1'; // ECMAScript Modules (ESM) and Common.js
|
|
60
|
+
// import { secp256k1 } from 'npm:@noble/curves@1.2.0/secp256k1'; // Deno
|
|
61
|
+
const priv = secp256k1.utils.randomPrivateKey();
|
|
62
|
+
const pub = secp256k1.getPublicKey(priv);
|
|
63
|
+
const msg = new Uint8Array(32).fill(1);
|
|
64
|
+
const sig = secp256k1.sign(msg, priv);
|
|
65
|
+
secp256k1.verify(sig, msg, pub) === true;
|
|
66
|
+
|
|
67
|
+
const privHex = '46c930bc7bb4db7f55da20798697421b98c4175a52c630294d75a84b9c126236'
|
|
68
|
+
const pub2 = secp256k1.getPublicKey(privHex); // keys & other inputs can be Uint8Array-s or hex strings
|
|
69
|
+
|
|
70
|
+
// Follows hash-to-curve specification to encode arbitrary hashes to EC points
|
|
71
|
+
import { hashToCurve, encodeToCurve } from '@noble/curves/secp256k1';
|
|
72
|
+
hashToCurve('0102abcd');
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
All curves:
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import { secp256k1, schnorr } from '@noble/curves/secp256k1';
|
|
54
79
|
import { ed25519, ed25519ph, ed25519ctx, x25519, RistrettoPoint } from '@noble/curves/ed25519';
|
|
55
80
|
import { ed448, ed448ph, ed448ctx, x448 } from '@noble/curves/ed448';
|
|
56
81
|
import { p256 } from '@noble/curves/p256';
|
|
@@ -63,63 +88,208 @@ import { bn254 } from '@noble/curves/bn';
|
|
|
63
88
|
import { jubjub } from '@noble/curves/jubjub';
|
|
64
89
|
```
|
|
65
90
|
|
|
66
|
-
|
|
91
|
+
Weierstrass curves feature recovering public keys from signatures and ECDH key agreement:
|
|
67
92
|
|
|
68
93
|
```ts
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const pub = secp256k1.getPublicKey(key);
|
|
73
|
-
const msg = new Uint8Array(32).fill(1);
|
|
74
|
-
const sig = secp256k1.sign(msg, key);
|
|
75
|
-
// weierstrass curves should use extraEntropy: https://moderncrypto.org/mail-archive/curves/2017/000925.html
|
|
76
|
-
const sigImprovedSecurity = secp256k1.sign(msg, key, { extraEntropy: true });
|
|
77
|
-
secp256k1.verify(sig, msg, pub) === true;
|
|
78
|
-
// secp, p*, pasta curves allow pub recovery
|
|
79
|
-
sig.recoverPublicKey(msg) === pub;
|
|
94
|
+
// extraEntropy https://moderncrypto.org/mail-archive/curves/2017/000925.html
|
|
95
|
+
const sigImprovedSecurity = secp256k1.sign(msg, priv, { extraEntropy: true });
|
|
96
|
+
sig.recoverPublicKey(msg) === pub; // public key recovery
|
|
80
97
|
const someonesPub = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
|
|
81
|
-
const shared = secp256k1.getSharedSecret(
|
|
98
|
+
const shared = secp256k1.getSharedSecret(priv, someonesPub); // ECDH (elliptic curve diffie-hellman)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
secp256k1 has schnorr signature implementation which follows
|
|
102
|
+
[BIP340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki):
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import { schnorr } from '@noble/curves/secp256k1';
|
|
106
|
+
const priv = schnorr.utils.randomPrivateKey();
|
|
107
|
+
const pub = schnorr.getPublicKey(priv);
|
|
108
|
+
const msg = new TextEncoder().encode('hello');
|
|
109
|
+
const sig = schnorr.sign(msg, priv);
|
|
110
|
+
const isValid = schnorr.verify(sig, msg, pub);
|
|
111
|
+
console.log(isValid);
|
|
82
112
|
```
|
|
83
113
|
|
|
84
|
-
|
|
114
|
+
ed25519 module has ed25519ctx / ed25519ph variants,
|
|
115
|
+
x25519 ECDH and [ristretto255](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448).
|
|
116
|
+
It follows [ZIP215](https://zips.z.cash/zip-0215) and [can be used in consensus-critical applications](https://hdevalence.ca/blog/2020-10-04-its-25519am):
|
|
85
117
|
|
|
86
|
-
|
|
118
|
+
```ts
|
|
119
|
+
import { ed25519 } from '@noble/curves/ed25519';
|
|
120
|
+
|
|
121
|
+
// Variants from RFC8032: with context, prehashed
|
|
122
|
+
import { ed25519ctx, ed25519ph } from '@noble/curves/ed25519';
|
|
123
|
+
|
|
124
|
+
// ECDH using curve25519 aka x25519
|
|
125
|
+
import { x25519 } from '@noble/curves/ed25519';
|
|
126
|
+
const priv = 'a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4';
|
|
127
|
+
const pub = 'e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c';
|
|
128
|
+
x25519.getSharedSecret(priv, pub) === x25519.scalarMult(priv, pub);
|
|
129
|
+
x25519.getPublicKey(priv) === x25519.scalarMultBase(priv);
|
|
130
|
+
|
|
131
|
+
// hash-to-curve
|
|
132
|
+
import { hashToCurve, encodeToCurve } from '@noble/curves/ed25519';
|
|
133
|
+
|
|
134
|
+
import { RistrettoPoint } from '@noble/curves/ed25519';
|
|
135
|
+
const rp = RistrettoPoint.fromHex(
|
|
136
|
+
'6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919'
|
|
137
|
+
);
|
|
138
|
+
RistrettoPoint.hashToCurve('Ristretto is traditionally a short shot of espresso coffee');
|
|
139
|
+
// also has add(), equals(), multiply(), toRawBytes() methods
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
ed448 module is basically the same:
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import { ed448, ed448ph, ed448ctx, x448 } from '@noble/curves/ed448';
|
|
146
|
+
import { hashToCurve, encodeToCurve } from '@noble/curves/ed448';
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
BLS12-381 pairing-friendly Barreto-Lynn-Scott elliptic curve construction allows to
|
|
150
|
+
construct [zk-SNARKs](https://z.cash/technology/zksnarks/) at the 128-bit security
|
|
151
|
+
and use aggregated, batch-verifiable
|
|
152
|
+
[threshold signatures](https://medium.com/snigirev.stepan/bls-signatures-better-than-schnorr-5a7fe30ea716),
|
|
153
|
+
using Boneh-Lynn-Shacham signature scheme.
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
import { bls12_381 as bls } from '@noble/curves/bls12-381';
|
|
157
|
+
const privateKey = '67d53f170b908cabb9eb326c3c337762d59289a8fec79f7bc9254b584b73265c';
|
|
158
|
+
const message = '64726e3da8';
|
|
159
|
+
const publicKey = bls.getPublicKey(privateKey);
|
|
160
|
+
const signature = bls.sign(message, privateKey);
|
|
161
|
+
const isValid = bls.verify(signature, message, publicKey);
|
|
162
|
+
console.log({ publicKey, signature, isValid });
|
|
163
|
+
|
|
164
|
+
// Sign 1 msg with 3 keys
|
|
165
|
+
const privateKeys = [
|
|
166
|
+
'18f020b98eb798752a50ed0563b079c125b0db5dd0b1060d1c1b47d4a193e1e4',
|
|
167
|
+
'ed69a8c50cf8c9836be3b67c7eeff416612d45ba39a5c099d48fa668bf558c9c',
|
|
168
|
+
'16ae669f3be7a2121e17d0c68c05a8f3d6bef21ec0f2315f1d7aec12484e4cf5',
|
|
169
|
+
];
|
|
170
|
+
const messages = ['d2', '0d98', '05caf3'];
|
|
171
|
+
const publicKeys = privateKeys.map(bls.getPublicKey);
|
|
172
|
+
const signatures2 = privateKeys.map((p) => bls.sign(message, p));
|
|
173
|
+
const aggPubKey2 = bls.aggregatePublicKeys(publicKeys);
|
|
174
|
+
const aggSignature2 = bls.aggregateSignatures(signatures2);
|
|
175
|
+
const isValid2 = bls.verify(aggSignature2, message, aggPubKey2);
|
|
176
|
+
console.log({ signatures2, aggSignature2, isValid2 });
|
|
177
|
+
|
|
178
|
+
// Sign 3 msgs with 3 keys
|
|
179
|
+
const signatures3 = privateKeys.map((p, i) => bls.sign(messages[i], p));
|
|
180
|
+
const aggSignature3 = bls.aggregateSignatures(signatures3);
|
|
181
|
+
const isValid3 = bls.verifyBatch(aggSignature3, messages, publicKeys);
|
|
182
|
+
console.log({ publicKeys, signatures3, aggSignature3, isValid3 });
|
|
183
|
+
|
|
184
|
+
// Pairings
|
|
185
|
+
// bls.pairing(PointG1, PointG2)
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Abstract API
|
|
189
|
+
|
|
190
|
+
Abstract API allows to define custom curves. All arithmetics is done with JS bigints over finite fields,
|
|
191
|
+
which is defined from `modular` sub-module. For scalar multiplication, we use [precomputed tables with w-ary non-adjacent form (wNAF)](https://paulmillr.com/posts/noble-secp256k1-fast-ecc/).
|
|
192
|
+
Precomputes are enabled for weierstrass and edwards BASE points of a curve. You could precompute any
|
|
193
|
+
other point (e.g. for ECDH) using `utils.precompute()` method.
|
|
194
|
+
|
|
195
|
+
There are following zero-dependency algorithms:
|
|
87
196
|
|
|
88
|
-
- [
|
|
197
|
+
- [abstract/weierstrass: Short Weierstrass curve](#abstractweierstrass-short-weierstrass-curve)
|
|
89
198
|
- [abstract/edwards: Twisted Edwards curve](#abstractedwards-twisted-edwards-curve)
|
|
90
199
|
- [abstract/montgomery: Montgomery curve](#abstractmontgomery-montgomery-curve)
|
|
91
|
-
- [abstract/weierstrass: Short Weierstrass curve](#abstractweierstrass-short-weierstrass-curve)
|
|
92
200
|
- [abstract/hash-to-curve: Hashing strings to curve points](#abstracthash-to-curve-hashing-strings-to-curve-points)
|
|
93
201
|
- [abstract/poseidon: Poseidon hash](#abstractposeidon-poseidon-hash)
|
|
94
|
-
- [abstract/modular](#abstractmodular)
|
|
95
|
-
- [abstract/utils](#abstractutils)
|
|
202
|
+
- [abstract/modular: Modular arithmetics utilities](#abstractmodular-modular-arithmetics-utilities)
|
|
203
|
+
- [abstract/utils: General utilities](#abstractutils-general-utilities)
|
|
96
204
|
|
|
97
|
-
###
|
|
98
|
-
|
|
99
|
-
There are following zero-dependency abstract algorithms:
|
|
205
|
+
### abstract/weierstrass: Short Weierstrass curve
|
|
100
206
|
|
|
101
207
|
```ts
|
|
102
|
-
import { bls } from '@noble/curves/abstract/bls';
|
|
103
|
-
import { twistedEdwards } from '@noble/curves/abstract/edwards';
|
|
104
|
-
import { montgomery } from '@noble/curves/abstract/montgomery';
|
|
105
208
|
import { weierstrass } from '@noble/curves/abstract/weierstrass';
|
|
106
|
-
import * as mod from '@noble/curves/abstract/modular';
|
|
107
|
-
import * as utils from '@noble/curves/abstract/utils';
|
|
108
209
|
```
|
|
109
210
|
|
|
110
|
-
|
|
211
|
+
Short Weierstrass curve's formula is `y² = x³ + ax + b`. `weierstrass` expects arguments `a`, `b`, field `Fp`, curve order `n`, cofactor `h`
|
|
212
|
+
and coordinates `Gx`, `Gy` of generator point.
|
|
213
|
+
|
|
214
|
+
**`k` generation** is done deterministically, following [RFC6979](https://www.rfc-editor.org/rfc/rfc6979).
|
|
215
|
+
For this you will need `hmac` & `hash`, which in our implementations is provided by noble-hashes.
|
|
216
|
+
If you're using different hashing library, make sure to wrap it in the following interface:
|
|
111
217
|
|
|
112
218
|
```ts
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
219
|
+
export type CHash = {
|
|
220
|
+
(message: Uint8Array): Uint8Array;
|
|
221
|
+
blockLen: number;
|
|
222
|
+
outputLen: number;
|
|
223
|
+
create(): any;
|
|
224
|
+
};
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Weierstrass points:**
|
|
228
|
+
|
|
229
|
+
1. Exported as `ProjectivePoint`
|
|
230
|
+
2. Represented in projective (homogeneous) coordinates: (x, y, z) ∋ (x=x/z, y=y/z)
|
|
231
|
+
3. Use complete exception-free formulas for addition and doubling
|
|
232
|
+
4. Can be decoded/encoded from/to Uint8Array / hex strings using `ProjectivePoint.fromHex` and `ProjectivePoint#toRawBytes()`
|
|
233
|
+
5. Have `assertValidity()` which checks for being on-curve
|
|
234
|
+
6. Have `toAffine()` and `x` / `y` getters which convert to 2d xy affine coordinates
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
// T is usually bigint, but can be something else like complex numbers in BLS curves
|
|
238
|
+
export interface ProjPointType<T> extends Group<ProjPointType<T>> {
|
|
239
|
+
readonly px: T;
|
|
240
|
+
readonly py: T;
|
|
241
|
+
readonly pz: T;
|
|
242
|
+
multiply(scalar: bigint): ProjPointType<T>;
|
|
243
|
+
multiplyUnsafe(scalar: bigint): ProjPointType<T>;
|
|
244
|
+
multiplyAndAddUnsafe(Q: ProjPointType<T>, a: bigint, b: bigint): ProjPointType<T> | undefined;
|
|
245
|
+
toAffine(iz?: T): AffinePoint<T>;
|
|
246
|
+
isTorsionFree(): boolean;
|
|
247
|
+
clearCofactor(): ProjPointType<T>;
|
|
248
|
+
assertValidity(): void;
|
|
249
|
+
hasEvenY(): boolean;
|
|
250
|
+
toRawBytes(isCompressed?: boolean): Uint8Array;
|
|
251
|
+
toHex(isCompressed?: boolean): string;
|
|
252
|
+
}
|
|
253
|
+
// Static methods for 3d XYZ points
|
|
254
|
+
export interface ProjConstructor<T> extends GroupConstructor<ProjPointType<T>> {
|
|
255
|
+
new (x: T, y: T, z: T): ProjPointType<T>;
|
|
256
|
+
fromAffine(p: AffinePoint<T>): ProjPointType<T>;
|
|
257
|
+
fromHex(hex: Hex): ProjPointType<T>;
|
|
258
|
+
fromPrivateKey(privateKey: PrivKey): ProjPointType<T>;
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
**ECDSA signatures** are represented by `Signature` instances and can be described by the interface:
|
|
263
|
+
|
|
264
|
+
```ts
|
|
265
|
+
export interface SignatureType {
|
|
266
|
+
readonly r: bigint;
|
|
267
|
+
readonly s: bigint;
|
|
268
|
+
readonly recovery?: number;
|
|
269
|
+
assertValidity(): void;
|
|
270
|
+
addRecoveryBit(recovery: number): SignatureType;
|
|
271
|
+
hasHighS(): boolean;
|
|
272
|
+
normalizeS(): SignatureType;
|
|
273
|
+
recoverPublicKey(msgHash: Hex): ProjPointType<bigint>;
|
|
274
|
+
toCompactRawBytes(): Uint8Array;
|
|
275
|
+
toCompactHex(): string;
|
|
276
|
+
// DER-encoded
|
|
277
|
+
toDERRawBytes(isCompressed?: boolean): Uint8Array;
|
|
278
|
+
toDERHex(isCompressed?: boolean): string;
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Example implementing [secq256k1](https://personaelabs.org/posts/spartan-ecdsa) (NOT secp256k1)
|
|
283
|
+
[cycle](https://zcash.github.io/halo2/background/curves.html#cycles-of-curves) of secp256k1 with Fp/N flipped.
|
|
118
284
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
285
|
+
```typescript
|
|
286
|
+
import { weierstrass } from '@noble/curves/abstract/weierstrass';
|
|
287
|
+
import { Field } from '@noble/curves/abstract/modular'; // finite field, mod arithmetics done over it
|
|
288
|
+
import { sha256 } from '@noble/hashes/sha256'; // 3rd-party sha256() of type utils.CHash, with blockLen/outputLen
|
|
289
|
+
import { hmac } from '@noble/hashes/hmac'; // 3rd-party hmac() that will accept sha256()
|
|
290
|
+
import { concatBytes, randomBytes } from '@noble/hashes/utils'; // 3rd-party utilities
|
|
122
291
|
const secq256k1 = weierstrass({
|
|
292
|
+
// secq256k1: cycle of secp256k1 with Fp/N flipped.
|
|
123
293
|
a: 0n,
|
|
124
294
|
b: 7n,
|
|
125
295
|
Fp: Field(2n ** 256n - 432420386565659656852420866394968145599n),
|
|
@@ -130,42 +300,93 @@ const secq256k1 = weierstrass({
|
|
|
130
300
|
hmac: (key: Uint8Array, ...msgs: Uint8Array[]) => hmac(sha256, key, concatBytes(...msgs)),
|
|
131
301
|
randomBytes,
|
|
132
302
|
});
|
|
303
|
+
|
|
304
|
+
// All curves expose same generic interface.
|
|
305
|
+
const priv = secq256k1.utils.randomPrivateKey();
|
|
306
|
+
secq256k1.getPublicKey(priv); // Convert private key to public.
|
|
307
|
+
const sig = secq256k1.sign(msg, priv); // Sign msg with private key.
|
|
308
|
+
secq256k1.verify(sig, msg, priv); // Verify if sig is correct.
|
|
309
|
+
|
|
310
|
+
const point = secq256k1.Point.BASE; // Elliptic curve Point class and BASE point static var.
|
|
311
|
+
point.add(point).equals(point.double()); // add(), equals(), double() methods
|
|
312
|
+
point.subtract(point).equals(secq256k1.Point.ZERO); // subtract() method, ZERO static var
|
|
313
|
+
point.negate(); // Flips point over x/y coordinate.
|
|
314
|
+
point.multiply(31415n); // Multiplication of Point by scalar.
|
|
315
|
+
|
|
316
|
+
point.assertValidity(); // Checks for being on-curve
|
|
317
|
+
point.toAffine(); // Converts to 2d affine xy coordinates
|
|
318
|
+
|
|
319
|
+
secq256k1.CURVE.n;
|
|
320
|
+
secq256k1.CURVE.Fp.mod();
|
|
321
|
+
secq256k1.CURVE.hash();
|
|
133
322
|
```
|
|
134
323
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
324
|
+
`weierstrass()` returns `CurveFn`:
|
|
325
|
+
|
|
326
|
+
```ts
|
|
327
|
+
export type CurveFn = {
|
|
328
|
+
CURVE: ReturnType<typeof validateOpts>;
|
|
329
|
+
getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
|
|
330
|
+
getSharedSecret: (privateA: PrivKey, publicB: Hex, isCompressed?: boolean) => Uint8Array;
|
|
331
|
+
sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) => SignatureType;
|
|
332
|
+
verify: (
|
|
333
|
+
signature: Hex | SignatureType,
|
|
334
|
+
msgHash: Hex,
|
|
335
|
+
publicKey: Hex,
|
|
336
|
+
opts?: { lowS?: boolean; prehash?: boolean }
|
|
337
|
+
) => boolean;
|
|
338
|
+
ProjectivePoint: ProjectivePointConstructor;
|
|
339
|
+
Signature: SignatureConstructor;
|
|
340
|
+
utils: {
|
|
341
|
+
isValidPrivateKey(privateKey: PrivKey): boolean;
|
|
342
|
+
randomPrivateKey: () => Uint8Array;
|
|
150
343
|
};
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
It is possible to enable precomputes for edwards & weierstrass curves.
|
|
154
|
-
Precomputes are calculated once (takes ~20-40ms), after that most `G` base point multiplications:
|
|
155
|
-
for example, `getPublicKey()`, `sign()` and similar methods - would be much faster.
|
|
156
|
-
Use `curve.utils.precompute()` to adjust precomputation window size
|
|
157
|
-
- You could use optional special params to tune performance:
|
|
158
|
-
- `Fp({sqrt})` square root calculation, used for point decompression
|
|
159
|
-
- `endo` endomorphism options for Koblitz curves
|
|
344
|
+
};
|
|
345
|
+
```
|
|
160
346
|
|
|
161
347
|
### abstract/edwards: Twisted Edwards curve
|
|
162
348
|
|
|
163
|
-
Twisted Edwards curve's formula is
|
|
349
|
+
Twisted Edwards curve's formula is `ax² + y² = 1 + dx²y²`. You must specify `a`, `d`, field `Fp`, order `n`, cofactor `h`
|
|
350
|
+
and coordinates `Gx`, `Gy` of generator point.
|
|
164
351
|
|
|
165
|
-
|
|
166
|
-
- For EdDSA signatures, params `hash` is also required. `adjustScalarBytes` which instructs how to change private scalars could be specified
|
|
352
|
+
For EdDSA signatures, `hash` param required. `adjustScalarBytes` which instructs how to change private scalars could be specified.
|
|
167
353
|
|
|
168
|
-
|
|
354
|
+
**Edwards points:**
|
|
355
|
+
|
|
356
|
+
1. Exported as `ExtendedPoint`
|
|
357
|
+
2. Represented in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z)
|
|
358
|
+
3. Use complete exception-free formulas for addition and doubling
|
|
359
|
+
4. Can be decoded/encoded from/to Uint8Array / hex strings using `ExtendedPoint.fromHex` and `ExtendedPoint#toRawBytes()`
|
|
360
|
+
5. Have `assertValidity()` which checks for being on-curve
|
|
361
|
+
6. Have `toAffine()` and `x` / `y` getters which convert to 2d xy affine coordinates
|
|
362
|
+
7. Have `isTorsionFree()`, `clearCofactor()` and `isSmallOrder()` utilities to handle torsions
|
|
363
|
+
|
|
364
|
+
```ts
|
|
365
|
+
export interface ExtPointType extends Group<ExtPointType> {
|
|
366
|
+
readonly ex: bigint;
|
|
367
|
+
readonly ey: bigint;
|
|
368
|
+
readonly ez: bigint;
|
|
369
|
+
readonly et: bigint;
|
|
370
|
+
assertValidity(): void;
|
|
371
|
+
multiply(scalar: bigint): ExtPointType;
|
|
372
|
+
multiplyUnsafe(scalar: bigint): ExtPointType;
|
|
373
|
+
isSmallOrder(): boolean;
|
|
374
|
+
isTorsionFree(): boolean;
|
|
375
|
+
clearCofactor(): ExtPointType;
|
|
376
|
+
toAffine(iz?: bigint): AffinePoint<bigint>;
|
|
377
|
+
}
|
|
378
|
+
// Static methods of Extended Point with coordinates in X, Y, Z, T
|
|
379
|
+
export interface ExtPointConstructor extends GroupConstructor<ExtPointType> {
|
|
380
|
+
new (x: bigint, y: bigint, z: bigint, t: bigint): ExtPointType;
|
|
381
|
+
fromAffine(p: AffinePoint<bigint>): ExtPointType;
|
|
382
|
+
fromHex(hex: Hex): ExtPointType;
|
|
383
|
+
fromPrivateKey(privateKey: Hex): ExtPointType;
|
|
384
|
+
}
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Example implementing edwards25519:
|
|
388
|
+
|
|
389
|
+
```ts
|
|
169
390
|
import { twistedEdwards } from '@noble/curves/abstract/edwards';
|
|
170
391
|
import { div } from '@noble/curves/abstract/modular';
|
|
171
392
|
import { sha512 } from '@noble/hashes/sha512';
|
|
@@ -181,18 +402,13 @@ const ed25519 = twistedEdwards({
|
|
|
181
402
|
hash: sha512,
|
|
182
403
|
randomBytes,
|
|
183
404
|
adjustScalarBytes(bytes) {
|
|
184
|
-
// optional
|
|
405
|
+
// optional; but mandatory in ed25519
|
|
185
406
|
bytes[0] &= 248;
|
|
186
407
|
bytes[31] &= 127;
|
|
187
408
|
bytes[31] |= 64;
|
|
188
409
|
return bytes;
|
|
189
410
|
},
|
|
190
411
|
} as const);
|
|
191
|
-
const key = ed25519.utils.randomPrivateKey();
|
|
192
|
-
const pub = ed25519.getPublicKey(key);
|
|
193
|
-
const msg = new TextEncoder().encode('hello world'); // strings not accepted, must be Uint8Array
|
|
194
|
-
const sig = ed25519.sign(msg, key);
|
|
195
|
-
ed25519.verify(sig, msg, pub) === true;
|
|
196
412
|
```
|
|
197
413
|
|
|
198
414
|
`twistedEdwards()` returns `CurveFn` of following type:
|
|
@@ -202,8 +418,7 @@ export type CurveFn = {
|
|
|
202
418
|
CURVE: ReturnType<typeof validateOpts>;
|
|
203
419
|
getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
|
|
204
420
|
sign: (message: Hex, privateKey: Hex) => Uint8Array;
|
|
205
|
-
verify: (sig: SigType, message: Hex, publicKey: PubKey) => boolean;
|
|
206
|
-
Point: PointConstructor;
|
|
421
|
+
verify: (sig: SigType, message: Hex, publicKey: PubKey, context?: Hex) => boolean;
|
|
207
422
|
ExtendedPoint: ExtendedPointConstructor;
|
|
208
423
|
Signature: SignatureConstructor;
|
|
209
424
|
utils: {
|
|
@@ -221,9 +436,7 @@ export type CurveFn = {
|
|
|
221
436
|
|
|
222
437
|
### abstract/montgomery: Montgomery curve
|
|
223
438
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
Proper Elliptic Curve Points are not implemented yet.
|
|
439
|
+
The module contains methods for x-only ECDH on Curve25519 / Curve448 from RFC7748. Proper Elliptic Curve Points are not implemented yet.
|
|
227
440
|
|
|
228
441
|
You must specify curve field, `a24` special variable, `montgomeryBits`, `nByteLength`, and coordinate `u` of generator point.
|
|
229
442
|
|
|
@@ -250,145 +463,51 @@ const x25519 = montgomery({
|
|
|
250
463
|
});
|
|
251
464
|
```
|
|
252
465
|
|
|
253
|
-
### abstract/
|
|
254
|
-
|
|
255
|
-
Short Weierstrass curve's formula is: y² = x³ + ax + b. Uses deterministic ECDSA from RFC6979. You can also specify `extraEntropy` in `sign()`.
|
|
256
|
-
|
|
257
|
-
- You must specify curve params: `a`, `b`, field `Fp`, order `n`, cofactor `h` and coordinates `Gx`, `Gy` of generator point
|
|
258
|
-
- For ECDSA, you must specify `hash`, `hmac`. It is also possible to recover keys from signatures
|
|
259
|
-
- For ECDH, use `getSharedSecret(privKeyA, pubKeyB)`
|
|
260
|
-
- Optional params are `lowS` (default value) and `endo` (endomorphism)
|
|
261
|
-
|
|
262
|
-
```typescript
|
|
263
|
-
import { Fp } from '@noble/curves/abstract/modular';
|
|
264
|
-
import { weierstrass } from '@noble/curves/abstract/weierstrass'; // Short Weierstrass curve
|
|
265
|
-
import { sha256 } from '@noble/hashes/sha256';
|
|
266
|
-
import { hmac } from '@noble/hashes/hmac';
|
|
267
|
-
import { concatBytes, randomBytes } from '@noble/hashes/utils';
|
|
466
|
+
### abstract/hash-to-curve: Hashing strings to curve points
|
|
268
467
|
|
|
269
|
-
|
|
270
|
-
a: 0n,
|
|
271
|
-
b: 7n,
|
|
272
|
-
Fp: Fp(2n ** 256n - 2n ** 32n - 2n ** 9n - 2n ** 8n - 2n ** 7n - 2n ** 6n - 2n ** 4n - 1n),
|
|
273
|
-
n: 2n ** 256n - 432420386565659656852420866394968145599n,
|
|
274
|
-
Gx: 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
|
|
275
|
-
Gy: 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
|
|
276
|
-
hash: sha256,
|
|
277
|
-
hmac: (k: Uint8Array, ...msgs: Uint8Array[]) => hmac(sha256, key, concatBytes(...msgs)),
|
|
278
|
-
randomBytes,
|
|
468
|
+
The module allows to hash arbitrary strings to elliptic curve points. Implements [hash-to-curve v11](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11).
|
|
279
469
|
|
|
280
|
-
|
|
281
|
-
h: 1n, // Cofactor
|
|
282
|
-
lowS: true, // Allow only low-S signatures by default in sign() and verify()
|
|
283
|
-
endo: {
|
|
284
|
-
// Endomorphism options for Koblitz curve
|
|
285
|
-
// Beta param
|
|
286
|
-
beta: 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501een,
|
|
287
|
-
// Split scalar k into k1, k2
|
|
288
|
-
splitScalar: (k: bigint) => {
|
|
289
|
-
// return { k1neg: true, k1: 512n, k2neg: false, k2: 448n };
|
|
290
|
-
},
|
|
291
|
-
},
|
|
292
|
-
});
|
|
470
|
+
`expand_message_xmd` [(spec)](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.4.1) produces a uniformly random byte string using a cryptographic hash function H that outputs b bits.
|
|
293
471
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
const msg = randomBytes(32);
|
|
298
|
-
const sig = secp256k1.sign(msg, key);
|
|
299
|
-
secp256k1.verify(sig, msg, pub); // true
|
|
300
|
-
sig.recoverPublicKey(msg); // == pub
|
|
301
|
-
const someonesPubkey = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
|
|
302
|
-
const shared = secp256k1.getSharedSecret(key, someonesPubkey);
|
|
472
|
+
```ts
|
|
473
|
+
function expand_message_xmd(msg: Uint8Array, DST: Uint8Array, lenInBytes: number, H: CHash): Uint8Array;
|
|
474
|
+
function expand_message_xof(msg: Uint8Array, DST: Uint8Array, lenInBytes: number, k: number, H: CHash): Uint8Array;
|
|
303
475
|
```
|
|
304
476
|
|
|
305
|
-
`
|
|
477
|
+
`hash_to_field(msg, count, options)` [(spec)](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3)
|
|
478
|
+
hashes arbitrary-length byte strings to a list of one or more elements of a finite field F.
|
|
479
|
+
_ `msg` a byte string containing the message to hash
|
|
480
|
+
_ `count` the number of elements of F to output
|
|
481
|
+
_ `options` `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`
|
|
482
|
+
_ Returns `[u_0, ..., u_(count - 1)]`, a list of field elements.
|
|
306
483
|
|
|
307
484
|
```ts
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
hashToPrivateKey: (hash: Hex) => Uint8Array;
|
|
325
|
-
randomPrivateKey: () => Uint8Array;
|
|
326
|
-
};
|
|
485
|
+
function hash_to_field(msg: Uint8Array, count: number, options: htfOpts): bigint[][];
|
|
486
|
+
type htfOpts = {
|
|
487
|
+
DST: string; // a domain separation tag defined in section 2.2.5
|
|
488
|
+
// p: the characteristic of F
|
|
489
|
+
// where F is a finite field of characteristic p and order q = p^m
|
|
490
|
+
p: bigint;
|
|
491
|
+
// m: the extension degree of F, m >= 1
|
|
492
|
+
// where F is a finite field of characteristic p and order q = p^m
|
|
493
|
+
m: number;
|
|
494
|
+
k: number; // the target security level for the suite in bits defined in section 5.1
|
|
495
|
+
expand?: 'xmd' | 'xof'; // option to use a message that has already been processed by expand_message_xmd
|
|
496
|
+
// Hash functions for: expand_message_xmd is appropriate for use with a
|
|
497
|
+
// wide range of hash functions, including SHA-2, SHA-3, BLAKE2, and others.
|
|
498
|
+
// BBS+ uses blake2: https://github.com/hyperledger/aries-framework-go/issues/2247
|
|
499
|
+
// TODO: verify that hash is shake if expand==='xof' via types
|
|
500
|
+
hash: CHash;
|
|
327
501
|
};
|
|
328
502
|
```
|
|
329
503
|
|
|
330
|
-
### abstract/hash-to-curve: Hashing strings to curve points
|
|
331
|
-
|
|
332
|
-
The module allows to hash arbitrary strings to elliptic curve points.
|
|
333
|
-
|
|
334
|
-
- `expand_message_xmd` [(spec)](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.4.1) produces a uniformly random byte string using a cryptographic hash function H that outputs b bits..
|
|
335
|
-
|
|
336
|
-
```ts
|
|
337
|
-
function expand_message_xmd(
|
|
338
|
-
msg: Uint8Array,
|
|
339
|
-
DST: Uint8Array,
|
|
340
|
-
lenInBytes: number,
|
|
341
|
-
H: CHash
|
|
342
|
-
): Uint8Array;
|
|
343
|
-
function expand_message_xof(
|
|
344
|
-
msg: Uint8Array,
|
|
345
|
-
DST: Uint8Array,
|
|
346
|
-
lenInBytes: number,
|
|
347
|
-
k: number,
|
|
348
|
-
H: CHash
|
|
349
|
-
): Uint8Array;
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
- `hash_to_field(msg, count, options)` [(spec)](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3)
|
|
353
|
-
hashes arbitrary-length byte strings to a list of one or more elements of a finite field F.
|
|
354
|
-
_ `msg` a byte string containing the message to hash
|
|
355
|
-
_ `count` the number of elements of F to output
|
|
356
|
-
_ `options` `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`
|
|
357
|
-
_ Returns `[u_0, ..., u_(count - 1)]`, a list of field elements.
|
|
358
|
-
|
|
359
|
-
```ts
|
|
360
|
-
function hash_to_field(msg: Uint8Array, count: number, options: htfOpts): bigint[][];
|
|
361
|
-
type htfOpts = {
|
|
362
|
-
// DST: a domain separation tag
|
|
363
|
-
// defined in section 2.2.5
|
|
364
|
-
DST: string;
|
|
365
|
-
// p: the characteristic of F
|
|
366
|
-
// where F is a finite field of characteristic p and order q = p^m
|
|
367
|
-
p: bigint;
|
|
368
|
-
// m: the extension degree of F, m >= 1
|
|
369
|
-
// where F is a finite field of characteristic p and order q = p^m
|
|
370
|
-
m: number;
|
|
371
|
-
// k: the target security level for the suite in bits
|
|
372
|
-
// defined in section 5.1
|
|
373
|
-
k: number;
|
|
374
|
-
// option to use a message that has already been processed by
|
|
375
|
-
// expand_message_xmd
|
|
376
|
-
expand?: 'xmd' | 'xof';
|
|
377
|
-
// Hash functions for: expand_message_xmd is appropriate for use with a
|
|
378
|
-
// wide range of hash functions, including SHA-2, SHA-3, BLAKE2, and others.
|
|
379
|
-
// BBS+ uses blake2: https://github.com/hyperledger/aries-framework-go/issues/2247
|
|
380
|
-
// TODO: verify that hash is shake if expand==='xof' via types
|
|
381
|
-
hash: CHash;
|
|
382
|
-
};
|
|
383
|
-
```
|
|
384
|
-
|
|
385
504
|
### abstract/poseidon: Poseidon hash
|
|
386
505
|
|
|
387
506
|
Implements [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash.
|
|
388
507
|
|
|
389
|
-
There are many poseidon
|
|
390
|
-
|
|
391
|
-
stark
|
|
508
|
+
There are many poseidon variants with different constants.
|
|
509
|
+
We don't provide them: you should construct them manually.
|
|
510
|
+
The only variant provided resides in `stark` module: inspect it for proper usage.
|
|
392
511
|
|
|
393
512
|
```ts
|
|
394
513
|
import { poseidon } from '@noble/curves/abstract/poseidon';
|
|
@@ -406,27 +525,35 @@ type PoseidonOpts = {
|
|
|
406
525
|
const instance = poseidon(opts: PoseidonOpts);
|
|
407
526
|
```
|
|
408
527
|
|
|
409
|
-
### abstract/
|
|
528
|
+
### abstract/bls
|
|
410
529
|
|
|
411
|
-
|
|
530
|
+
The module abstracts BLS (Barreto-Lynn-Scott) primitives. In theory you should be able to write BLS12-377, BLS24,
|
|
531
|
+
and others with it.
|
|
412
532
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
533
|
+
### abstract/modular: Modular arithmetics utilities
|
|
534
|
+
|
|
535
|
+
The module also contains useful `hashToPrivateScalar` method which allows to create
|
|
536
|
+
scalars (e.g. private keys) with the modulo bias being neglible. It follows
|
|
537
|
+
FIPS 186 B.4.1. Requires at least 40 bytes of input for 32-byte private key.
|
|
538
|
+
|
|
539
|
+
```ts
|
|
540
|
+
import * as mod from '@noble/curves/abstract/modular';
|
|
541
|
+
const fp = mod.Field(2n ** 255n - 19n); // Finite field over 2^255-19
|
|
542
|
+
fp.mul(591n, 932n); // multiplication
|
|
543
|
+
fp.pow(481n, 11024858120n); // exponentiation
|
|
544
|
+
fp.div(5n, 17n); // division: 5/17 mod 2^255-19 == 5 * invert(17)
|
|
545
|
+
fp.sqrt(21n); // square root
|
|
418
546
|
|
|
419
547
|
// Generic non-FP utils are also available
|
|
420
|
-
mod(21n, 10n); // 21 mod 10 == 1n; fixed version of 21 % 10
|
|
421
|
-
invert(17n, 10n); // invert(17) mod 10; modular multiplicative inverse
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
sqrt(21n, 73n); // √21 mod 73; square root
|
|
548
|
+
mod.mod(21n, 10n); // 21 mod 10 == 1n; fixed version of 21 % 10
|
|
549
|
+
mod.invert(17n, 10n); // invert(17) mod 10; modular multiplicative inverse
|
|
550
|
+
mod.invertBatch([1n, 2n, 4n], 21n); // => [1n, 11n, 16n] in one inversion
|
|
551
|
+
mod.hashToPrivateScalar(sha512_of_something, secp256r1.n);
|
|
425
552
|
```
|
|
426
553
|
|
|
427
|
-
### abstract/utils
|
|
554
|
+
### abstract/utils: General utilities
|
|
428
555
|
|
|
429
|
-
```
|
|
556
|
+
```ts
|
|
430
557
|
import * as utils from '@noble/curves/abstract/utils';
|
|
431
558
|
|
|
432
559
|
utils.bytesToHex(Uint8Array.from([0xde, 0xad, 0xbe, 0xef]));
|
|
@@ -439,7 +566,6 @@ utils.numberToBytesLE(123n);
|
|
|
439
566
|
utils.numberToHexUnpadded(123n);
|
|
440
567
|
utils.concatBytes(Uint8Array.from([0xde, 0xad]), Uint8Array.from([0xbe, 0xef]));
|
|
441
568
|
utils.nLength(255n);
|
|
442
|
-
utils.hashToPrivateScalar(sha512_of_something, secp256r1.n);
|
|
443
569
|
utils.equalBytes(Uint8Array.from([0xde]), Uint8Array.from([0xde]));
|
|
444
570
|
```
|
|
445
571
|
|
|
@@ -447,80 +573,102 @@ utils.equalBytes(Uint8Array.from([0xde]), Uint8Array.from([0xde]));
|
|
|
447
573
|
|
|
448
574
|
The library had no prior security audit.
|
|
449
575
|
|
|
450
|
-
[Timing attack](https://en.wikipedia.org/wiki/Timing_attack) considerations: _JIT-compiler_ and _Garbage Collector_ make "constant time" extremely hard to achieve in a scripting language. Which means _any other JS library can't have constant-timeness_. Even statically typed Rust, a language without GC, [makes it harder to achieve constant-time](https://www.chosenplaintext.ca/open-source/rust-timing-shield/security) for some cases. If your goal is absolute security, don't use any JS lib — including bindings to native ones. Use low-level libraries & languages. Nonetheless we're targetting algorithmic constant time.
|
|
576
|
+
[Timing attack](https://en.wikipedia.org/wiki/Timing_attack) considerations: we are using non-CT bigints. However, _JIT-compiler_ and _Garbage Collector_ make "constant time" extremely hard to achieve in a scripting language. Which means _any other JS library can't have constant-timeness_. Even statically typed Rust, a language without GC, [makes it harder to achieve constant-time](https://www.chosenplaintext.ca/open-source/rust-timing-shield/security) for some cases. If your goal is absolute security, don't use any JS lib — including bindings to native ones. Use low-level libraries & languages. Nonetheless we're targetting algorithmic constant time.
|
|
451
577
|
|
|
452
|
-
We consider infrastructure attacks like rogue NPM modules very important; that's why it's crucial to minimize the amount of 3rd-party dependencies & native bindings. If your app uses 500 dependencies, any dep could get hacked and you'll be downloading malware with every `npm install`. Our goal is to minimize this attack vector.
|
|
578
|
+
We consider infrastructure attacks like rogue NPM modules very important; that's why it's crucial to minimize the amount of 3rd-party dependencies & native bindings. If your app uses 500 dependencies, any dep could get hacked and you'll be downloading malware with every `npm install`. Our goal is to minimize this attack vector. As for devDependencies used by the library:
|
|
579
|
+
|
|
580
|
+
- `@scure` base, bip32, bip39 (used in tests), micro-bmark (benchmark), micro-should (testing) are developed by us
|
|
581
|
+
and follow the same practices such as: minimal library size, auditability, signed releases
|
|
582
|
+
- prettier (linter), fast-check (property-based testing),
|
|
583
|
+
typescript versions are locked and rarely updated. Every update is checked with `npm-diff`.
|
|
584
|
+
The packages are big, which makes it hard to audit their source code thoroughly and fully.
|
|
585
|
+
- They are only used if you clone the git repo and want to add some feature to it. End-users won't use them.
|
|
453
586
|
|
|
454
587
|
## Speed
|
|
455
588
|
|
|
456
|
-
Benchmark results on Apple M2 with node
|
|
589
|
+
Benchmark results on Apple M2 with node v19:
|
|
457
590
|
|
|
458
591
|
```
|
|
459
592
|
secp256k1
|
|
460
|
-
init x
|
|
461
|
-
getPublicKey x
|
|
462
|
-
sign x 3,
|
|
463
|
-
verify x
|
|
464
|
-
getSharedSecret x
|
|
465
|
-
recoverPublicKey x
|
|
466
|
-
schnorr.sign x
|
|
467
|
-
schnorr.verify x
|
|
593
|
+
init x 58 ops/sec @ 17ms/op
|
|
594
|
+
getPublicKey x 5,640 ops/sec @ 177μs/op
|
|
595
|
+
sign x 3,909 ops/sec @ 255μs/op
|
|
596
|
+
verify x 780 ops/sec @ 1ms/op
|
|
597
|
+
getSharedSecret x 465 ops/sec @ 2ms/op
|
|
598
|
+
recoverPublicKey x 740 ops/sec @ 1ms/op
|
|
599
|
+
schnorr.sign x 597 ops/sec @ 1ms/op
|
|
600
|
+
schnorr.verify x 775 ops/sec @ 1ms/op
|
|
468
601
|
|
|
469
602
|
P256
|
|
470
|
-
init x
|
|
471
|
-
getPublicKey x 5,
|
|
472
|
-
sign x 3,
|
|
473
|
-
verify x
|
|
603
|
+
init x 31 ops/sec @ 31ms/op
|
|
604
|
+
getPublicKey x 5,607 ops/sec @ 178μs/op
|
|
605
|
+
sign x 3,930 ops/sec @ 254μs/op
|
|
606
|
+
verify x 540 ops/sec @ 1ms/op
|
|
474
607
|
|
|
475
608
|
P384
|
|
476
|
-
init x
|
|
477
|
-
getPublicKey x 2,
|
|
478
|
-
sign x 1,
|
|
479
|
-
verify x
|
|
609
|
+
init x 15 ops/sec @ 63ms/op
|
|
610
|
+
getPublicKey x 2,622 ops/sec @ 381μs/op
|
|
611
|
+
sign x 1,913 ops/sec @ 522μs/op
|
|
612
|
+
verify x 222 ops/sec @ 4ms/op
|
|
480
613
|
|
|
481
614
|
P521
|
|
482
|
-
init x
|
|
483
|
-
getPublicKey x 1,
|
|
484
|
-
sign x 1,
|
|
485
|
-
verify x
|
|
615
|
+
init x 8 ops/sec @ 119ms/op
|
|
616
|
+
getPublicKey x 1,371 ops/sec @ 729μs/op
|
|
617
|
+
sign x 1,090 ops/sec @ 917μs/op
|
|
618
|
+
verify x 118 ops/sec @ 8ms/op
|
|
486
619
|
|
|
487
620
|
ed25519
|
|
488
|
-
init x
|
|
489
|
-
getPublicKey x
|
|
490
|
-
sign x
|
|
491
|
-
verify x
|
|
621
|
+
init x 47 ops/sec @ 20ms/op
|
|
622
|
+
getPublicKey x 9,414 ops/sec @ 106μs/op
|
|
623
|
+
sign x 4,516 ops/sec @ 221μs/op
|
|
624
|
+
verify x 912 ops/sec @ 1ms/op
|
|
492
625
|
|
|
493
626
|
ed448
|
|
494
|
-
init x 17 ops/sec @
|
|
495
|
-
getPublicKey x 3,
|
|
496
|
-
sign x 1,
|
|
497
|
-
verify x
|
|
498
|
-
|
|
499
|
-
bls12-381
|
|
500
|
-
init x 30 ops/sec @ 33ms/op
|
|
501
|
-
getPublicKey x 788 ops/sec @ 1ms/op
|
|
502
|
-
sign x 45 ops/sec @ 21ms/op
|
|
503
|
-
verify x 32 ops/sec @ 30ms/op
|
|
504
|
-
pairing x 88 ops/sec @ 11ms/op
|
|
627
|
+
init x 17 ops/sec @ 56ms/op
|
|
628
|
+
getPublicKey x 3,363 ops/sec @ 297μs/op
|
|
629
|
+
sign x 1,615 ops/sec @ 619μs/op
|
|
630
|
+
verify x 319 ops/sec @ 3ms/op
|
|
505
631
|
|
|
506
632
|
stark
|
|
507
|
-
init x
|
|
508
|
-
pedersen
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
633
|
+
init x 35 ops/sec @ 28ms/op
|
|
634
|
+
pedersen x 884 ops/sec @ 1ms/op
|
|
635
|
+
poseidon x 8,598 ops/sec @ 116μs/op
|
|
636
|
+
verify x 528 ops/sec @ 1ms/op
|
|
637
|
+
|
|
638
|
+
bls12-381
|
|
639
|
+
init x 32 ops/sec @ 30ms/op
|
|
640
|
+
getPublicKey 1-bit x 858 ops/sec @ 1ms/op
|
|
641
|
+
getPublicKey x 858 ops/sec @ 1ms/op
|
|
642
|
+
sign x 49 ops/sec @ 20ms/op
|
|
643
|
+
verify x 34 ops/sec @ 28ms/op
|
|
644
|
+
pairing x 94 ops/sec @ 10ms/op
|
|
645
|
+
aggregatePublicKeys/8 x 116 ops/sec @ 8ms/op
|
|
646
|
+
aggregatePublicKeys/32 x 31 ops/sec @ 31ms/op
|
|
647
|
+
aggregatePublicKeys/128 x 7 ops/sec @ 125ms/op
|
|
648
|
+
aggregateSignatures/8 x 45 ops/sec @ 22ms/op
|
|
649
|
+
aggregateSignatures/32 x 11 ops/sec @ 84ms/op
|
|
650
|
+
aggregateSignatures/128 x 3 ops/sec @ 332ms/opp
|
|
515
651
|
```
|
|
516
652
|
|
|
653
|
+
## In the wild
|
|
654
|
+
|
|
655
|
+
Elliptic curve calculator: [paulmillr.com/ecc](https://paulmillr.com/ecc).
|
|
656
|
+
|
|
657
|
+
- secp256k1
|
|
658
|
+
- [btc-signer](https://github.com/paulmillr/micro-btc-signer), [eth-signer](https://github.com/paulmillr/micro-eth-signer)
|
|
659
|
+
- ed25519
|
|
660
|
+
- [sol-signer](https://github.com/paulmillr/micro-sol-signer)
|
|
661
|
+
- BLS12-381
|
|
662
|
+
- Threshold sigs demo [genthresh.com](https://genthresh.com)
|
|
663
|
+
- BBS signatures [github.com/Wind4Greg/BBS-Draft-Checks](https://github.com/Wind4Greg/BBS-Draft-Checks) following [draft-irtf-cfrg-bbs-signatures-latest](https://identity.foundation/bbs-signature/draft-irtf-cfrg-bbs-signatures.html)
|
|
664
|
+
|
|
517
665
|
## Upgrading
|
|
518
666
|
|
|
519
|
-
If you're coming from single-
|
|
667
|
+
If you're coming from single-feature noble packages, the following changes need to be kept in mind:
|
|
520
668
|
|
|
521
669
|
- 2d affine (x, y) points have been removed to reduce complexity and improve speed
|
|
522
|
-
- Removed `number` support as a type for private keys
|
|
523
|
-
- `mod`, `invert` are no longer present in `utils
|
|
670
|
+
- Removed `number` support as a type for private keys, `bigint` is still supported
|
|
671
|
+
- `mod`, `invert` are no longer present in `utils`: use `@noble/curves/abstract/modular`
|
|
524
672
|
|
|
525
673
|
Upgrading from @noble/secp256k1 1.7:
|
|
526
674
|
|