readme updates

This commit is contained in:
Paul Miller 2023-02-12 10:30:55 +00:00
parent fe3491c5aa
commit a462fc5779
No known key found for this signature in database
GPG Key ID: 697079DA6878B89B

179
README.md

@ -1,12 +1,13 @@
# noble-curves # noble-curves
Minimal, auditable JS implementation of elliptic curve cryptography. Audited & minimal JS implementation of elliptic curve cryptography.
- **noble** family, zero dependencies
- Short Weierstrass, Edwards, Montgomery curves - Short Weierstrass, Edwards, Montgomery curves
- ECDSA, EdDSA, Schnorr, BLS signature schemes, ECDH key agreement - ECDSA, EdDSA, Schnorr, BLS signature schemes, ECDH key agreement
- [hash to curve](https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/) - #[hash to curve](https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/)
for encoding or hashing an arbitrary string to a point on an elliptic curve for encoding or hashing an arbitrary string to an elliptic curve point
- [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash - 🧜‍♂️ [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash
- 🏎 [Ultra-fast](#speed), hand-optimized for caveats of JS engines - 🏎 [Ultra-fast](#speed), hand-optimized for caveats of JS engines
- 🔍 Unique tests ensure correctness. Wycheproof vectors included - 🔍 Unique tests ensure correctness. Wycheproof vectors included
- 🔻 Tree-shaking-friendly: there is no entry point, which ensures small size of your app - 🔻 Tree-shaking-friendly: there is no entry point, which ensures small size of your app
@ -17,20 +18,20 @@ Package consists of two parts:
2. root directory utilizes one dependency `@noble/hashes` and provides ready-to-use: 2. root directory utilizes one dependency `@noble/hashes` and provides ready-to-use:
- NIST curves secp192r1/P192, secp224r1/P224, secp256r1/P256, secp384r1/P384, secp521r1/P521 - NIST curves secp192r1/P192, secp224r1/P224, secp256r1/P256, secp384r1/P384, secp521r1/P521
- SECG curve secp256k1 - SECG curve secp256k1
- pairing-friendly curves bls12-381, bn254
- ed25519/curve25519/x25519/ristretto, edwards448/curve448/x448 RFC7748 / RFC8032 / ZIP215 stuff - ed25519/curve25519/x25519/ristretto, edwards448/curve448/x448 RFC7748 / RFC8032 / ZIP215 stuff
- pairing-friendly curves bls12-381, bn254
Curves incorporate work from previous noble packages Curves incorporate work from previous noble packages
([secp256k1](https://github.com/paulmillr/noble-secp256k1), ([secp256k1](https://github.com/paulmillr/noble-secp256k1),
[ed25519](https://github.com/paulmillr/noble-ed25519)), [ed25519](https://github.com/paulmillr/noble-ed25519)),
which had security audits and were developed from 2019 to 2022. which were developed from 2019 to 2022.
Check out [Upgrading](#upgrading) section if you've used them before. Check out [Upgrading](#upgrading) section if you've used them before.
### This library belongs to _noble_ crypto ### This library belongs to _noble_ crypto
> **noble-crypto** — high-security, easily auditable set of contained cryptographic libraries and tools. > **noble-crypto** — high-security, easily auditable set of contained cryptographic libraries and tools.
- Protection against supply chain attacks - No dependencies, protection against supply chain attacks
- Easily auditable TypeScript/JS code - Easily auditable TypeScript/JS code
- Supported in all major browsers and stable node.js versions - Supported in all major browsers and stable node.js versions
- All releases are signed with PGP keys - All releases are signed with PGP keys
@ -42,14 +43,17 @@ Check out [Upgrading](#upgrading) section if you've used them before.
## Usage ## Usage
Use NPM in node.js / browser, or include single file from Use NPM for browser / node.js:
[GitHub's releases page](https://github.com/paulmillr/noble-curves/releases):
> npm install @noble/curves > npm install @noble/curves
For [Deno](https://deno.land), use it with npm specifier: `import { secp256k1 } from 'npm:@noble/curves@1.2.0/secp256k1';`.
In browser, you could also include the single file from
[GitHub's releases page](https://github.com/paulmillr/noble-curves/releases).
The library does not have an entry point. It allows you to select specific primitives and drop everything else. If you only want to use secp256k1, just use the library with rollup or other bundlers. This is done to make your bundles tiny. All curves: The library does not have an entry point. It allows you to select specific primitives and drop everything else. If you only want to use secp256k1, just use the library with rollup or other bundlers. This is done to make your bundles tiny. All curves:
```ts ```typescript
import { secp256k1 } from '@noble/curves/secp256k1'; import { secp256k1 } from '@noble/curves/secp256k1';
import { ed25519, ed25519ph, ed25519ctx, x25519, RistrettoPoint } from '@noble/curves/ed25519'; import { ed25519, ed25519ph, ed25519ctx, x25519, RistrettoPoint } from '@noble/curves/ed25519';
import { ed448, ed448ph, ed448ctx, x448 } from '@noble/curves/ed448'; import { ed448, ed448ph, ed448ctx, x448 } from '@noble/curves/ed448';
@ -81,7 +85,7 @@ const someonesPub = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
const shared = secp256k1.getSharedSecret(key, someonesPub); const shared = secp256k1.getSharedSecret(key, someonesPub);
``` ```
To define a custom curve, check out docs below. See [additional examples](#additional-examples) for guides.
## API ## API
@ -103,6 +107,7 @@ import { bls } from '@noble/curves/abstract/bls';
import { twistedEdwards } from '@noble/curves/abstract/edwards'; import { twistedEdwards } from '@noble/curves/abstract/edwards';
import { montgomery } from '@noble/curves/abstract/montgomery'; import { montgomery } from '@noble/curves/abstract/montgomery';
import { weierstrass } from '@noble/curves/abstract/weierstrass'; import { weierstrass } from '@noble/curves/abstract/weierstrass';
import * as curve from '@noble/curves/abstract/curve';
import * as mod from '@noble/curves/abstract/modular'; import * as mod from '@noble/curves/abstract/modular';
import * as utils from '@noble/curves/abstract/utils'; import * as utils from '@noble/curves/abstract/utils';
``` ```
@ -110,11 +115,11 @@ import * as utils from '@noble/curves/abstract/utils';
They allow to define a new curve in a few lines of code: They allow to define a new curve in a few lines of code:
```ts ```ts
import { Field } from '@noble/curves/abstract/modular'; import { Field } from '@noble/curves/abstract/modular'; // finite field, modulo arithmetics done over it
import { weierstrass } from '@noble/curves/abstract/weierstrass'; import { weierstrass } from '@noble/curves/abstract/weierstrass'; // short weierstrass curve
import { hmac } from '@noble/hashes/hmac'; import { sha256 } from '@noble/hashes/sha256'; // 3rd-party sha256() of type utils.CHash, with blockLen/outputLen
import { sha256 } from '@noble/hashes/sha256'; import { hmac } from '@noble/hashes/hmac'; // 3rd-party hmac() that will accept sha256()
import { concatBytes, randomBytes } from '@noble/hashes/utils'; import { concatBytes, randomBytes } from '@noble/hashes/utils'; // 3rd-party utilities
// secq (NOT secp) 256k1: cycle of secp256k1 with Fp/N flipped. // secq (NOT secp) 256k1: cycle of secp256k1 with Fp/N flipped.
// https://zcash.github.io/halo2/background/curves.html#cycles-of-curves // https://zcash.github.io/halo2/background/curves.html#cycles-of-curves
@ -155,7 +160,7 @@ const secq256k1 = weierstrass({
for example, `getPublicKey()`, `sign()` and similar methods - would be much faster. for example, `getPublicKey()`, `sign()` and similar methods - would be much faster.
Use `curve.utils.precompute()` to adjust precomputation window size Use `curve.utils.precompute()` to adjust precomputation window size
- You could use optional special params to tune performance: - You could use optional special params to tune performance:
- `Fp({sqrt})` square root calculation, used for point decompression - `Field({sqrt})` square root calculation, used for point decompression
- `endo` endomorphism options for Koblitz curves - `endo` endomorphism options for Koblitz curves
### abstract/edwards: Twisted Edwards curve ### abstract/edwards: Twisted Edwards curve
@ -165,7 +170,7 @@ Twisted Edwards curve's formula is: ax² + y² = 1 + dx²y².
- You must specify curve params `a`, `d`, field `Fp`, order `n`, cofactor `h` and coordinates `Gx`, `Gy` of generator point - You must specify curve params `a`, `d`, field `Fp`, order `n`, cofactor `h` and coordinates `Gx`, `Gy` of generator point
- For EdDSA signatures, params `hash` is also required. `adjustScalarBytes` which instructs how to change private scalars could be specified - For EdDSA signatures, params `hash` is also required. `adjustScalarBytes` which instructs how to change private scalars could be specified
```typescript ```ts
import { twistedEdwards } from '@noble/curves/abstract/edwards'; import { twistedEdwards } from '@noble/curves/abstract/edwards';
import { div } from '@noble/curves/abstract/modular'; import { div } from '@noble/curves/abstract/modular';
import { sha512 } from '@noble/hashes/sha512'; import { sha512 } from '@noble/hashes/sha512';
@ -260,7 +265,7 @@ Short Weierstrass curve's formula is: y² = x³ + ax + b. Uses deterministic ECD
- Optional params are `lowS` (default value) and `endo` (endomorphism) - Optional params are `lowS` (default value) and `endo` (endomorphism)
```typescript ```typescript
import { Fp } from '@noble/curves/abstract/modular'; import { Field } from '@noble/curves/abstract/modular';
import { weierstrass } from '@noble/curves/abstract/weierstrass'; // Short Weierstrass curve import { weierstrass } from '@noble/curves/abstract/weierstrass'; // Short Weierstrass curve
import { sha256 } from '@noble/hashes/sha256'; import { sha256 } from '@noble/hashes/sha256';
import { hmac } from '@noble/hashes/hmac'; import { hmac } from '@noble/hashes/hmac';
@ -269,27 +274,26 @@ import { concatBytes, randomBytes } from '@noble/hashes/utils';
const secp256k1 = weierstrass({ const secp256k1 = weierstrass({
a: 0n, a: 0n,
b: 7n, b: 7n,
Fp: Fp(2n ** 256n - 2n ** 32n - 2n ** 9n - 2n ** 8n - 2n ** 7n - 2n ** 6n - 2n ** 4n - 1n), Fp: Field(2n ** 256n - 2n ** 32n - 2n ** 9n - 2n ** 8n - 2n ** 7n - 2n ** 6n - 2n ** 4n - 1n),
n: 2n ** 256n - 432420386565659656852420866394968145599n, n: 2n ** 256n - 432420386565659656852420866394968145599n,
Gx: 55066263022277343669578718895168534326250603453777594175500187360389116729240n, Gx: 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
Gy: 32670510020758816978083085130507043184471273380659243275938904335757337482424n, Gy: 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
hash: sha256, hash: sha256,
hmac: (k: Uint8Array, ...msgs: Uint8Array[]) => hmac(sha256, key, concatBytes(...msgs)), hmac: (k: Uint8Array, ...msgs: Uint8Array[]) => hmac(sha256, key, concatBytes(...msgs)),
randomBytes, randomBytes,
h: 1n, // cofactor
// Optional params
h: 1n, // Cofactor
lowS: true, // Allow only low-S signatures by default in sign() and verify()
endo: {
// Endomorphism options for Koblitz curve
// Beta param
beta: 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501een,
// Split scalar k into k1, k2
splitScalar: (k: bigint) => {
// return { k1neg: true, k1: 512n, k2neg: false, k2: 448n };
},
},
}); });
// Optional weierstrass params:
// lowS: true, // Allow only low-S signatures by default in sign() and verify()
// endo: {
// // Endomorphism options for Koblitz curve
// // Beta param
// beta: 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501een,
// // Split scalar k into k1, k2
// splitScalar: (k: bigint) => {
// // return { k1neg: true, k1: 512n, k2neg: false, k2: 448n };
// },
// },
// Usage // Usage
const key = secp256k1.utils.randomPrivateKey(); const key = secp256k1.utils.randomPrivateKey();
@ -406,13 +410,61 @@ type PoseidonOpts = {
const instance = poseidon(opts: PoseidonOpts); const instance = poseidon(opts: PoseidonOpts);
``` ```
### abstract/bls
The pairing-friendly Barreto-Lynn-Scott elliptic curve construction allows to:
- Construct [zk-SNARKs](https://z.cash/technology/zksnarks/) at the 128-bit security
- Use [threshold signatures](https://medium.com/snigirev.stepan/bls-signatures-better-than-schnorr-5a7fe30ea716),
which allows a user to sign lots of messages with one signature and verify them swiftly in a batch,
using Boneh-Lynn-Shacham signature scheme.
Compatible with Algorand, Chia, Dfinity, Ethereum, FIL, Zcash. Matches specs [pairing-curves-10](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-10), [bls-sigs-04](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04), [hash-to-curve-12](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-12). To learn more about internals, navigate to
[utilities](#utilities) section.
Resources that help to understand bls12-381:
- [BLS12-381 for the rest of us](https://hackmd.io/@benjaminion/bls12-381)
- [Key concepts of pairings](https://medium.com/@alonmuroch_65570/bls-signatures-part-2-key-concepts-of-pairings-27a8a9533d0c)
- Pairing over bls12-381: [part 1](https://research.nccgroup.com/2020/07/06/pairing-over-bls12-381-part-1-fields/),
[part 2](https://research.nccgroup.com/2020/07/13/pairing-over-bls12-381-part-2-curves/),
[part 3](https://research.nccgroup.com/2020/08/13/pairing-over-bls12-381-part-3-pairing/)
- [Estimating the bit security of pairing-friendly curves](https://research.nccgroup.com/2022/02/03/estimating-the-bit-security-of-pairing-friendly-curves/)
- Check out [the online demo](https://paulmillr.com/ecc) and [threshold sigs demo](https://genthresh.com)
- See [BBS signatures implementation](https://github.com/Wind4Greg/BBS-Draft-Checks) based on the library, following [draft-irtf-cfrg-bbs-signatures-latest](https://identity.foundation/bbs-signature/draft-irtf-cfrg-bbs-signatures.html)
The library uses G1 for public keys and G2 for signatures. Adding support for G1 signatures is planned.
- BLS Relies on Bilinear Pairing (expensive)
- Private Keys: 32 bytes
- Public Keys: 48 bytes: 381 bit affine x coordinate, encoded into 48 big-endian bytes.
- Signatures: 96 bytes: two 381 bit integers (affine x coordinate), encoded into two 48 big-endian byte arrays.
- The signature is a point on the G2 subgroup, which is defined over a finite field
with elements twice as big as the G1 curve (G2 is over Fp2 rather than Fp. Fp2 is analogous to the complex numbers).
- The 12 stands for the Embedding degree.
Formulas:
- `P = pk x G` - public keys
- `S = pk x H(m)` - signing
- `e(P, H(m)) == e(G, S)` - verification using pairings
- `e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))` - signature aggregation
The BLS parameters for the library are:
- `PK_IN` `G1`
- `HASH_OR_ENCODE` `true`
- `DST` `BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_` - use `bls.utils.getDSTLabel()` & `bls.utils.setDSTLabel("...")` to read/change the Domain Separation Tag label
- `RAND_BITS` `64`
Filecoin uses little endian byte arrays for private keys - so ensure to reverse byte order if you'll use it with FIL.
### abstract/modular ### abstract/modular
Modular arithmetics utilities. Modular arithmetics utilities.
```typescript ```typescript
import { Fp, mod, invert, div, invertBatch, sqrt } from '@noble/curves/abstract/modular'; import { Field, mod, invert, div, invertBatch, sqrt } from '@noble/curves/abstract/modular';
const fp = Fp(2n ** 255n - 19n); // Finite field over 2^255-19 const fp = Field(2n ** 255n - 19n); // Finite field over 2^255-19
fp.mul(591n, 932n); fp.mul(591n, 932n);
fp.pow(481n, 11024858120n); fp.pow(481n, 11024858120n);
@ -443,6 +495,63 @@ utils.hashToPrivateScalar(sha512_of_something, secp256r1.n);
utils.equalBytes(Uint8Array.from([0xde]), Uint8Array.from([0xde])); utils.equalBytes(Uint8Array.from([0xde]), Uint8Array.from([0xde]));
``` ```
### Additional examples
secp256k1 schnorr:
```ts
import { schnorr } from '@noble/curves/secp256k1';
const priv = schnorr.utils.randomPrivateKey();
const pub = schnorr.getPublicKey(priv);
const msg = new TextEncoder().encode('hello');
const sig = schnorr.sign(msg, priv);
const isValid = schnorr.verify(sig, msg, pub);
console.log(isValid);
```
ed25519, x25519, ristretto255:
```ts
import { ed25519, ed25519ctx, ed25519ph, x25519, RistrettoPoint } from '@noble/curves/ed25519';
```
bls12_381
```ts
import { bls12_381 as bls } from '@noble/curves/bls12-381';
// keys, messages & other inputs can be Uint8Arrays or hex strings
const privateKey = '67d53f170b908cabb9eb326c3c337762d59289a8fec79f7bc9254b584b73265c';
const message = '64726e3da8';
const publicKey = bls.getPublicKey(privateKey);
const signature = bls.sign(message, privateKey);
const isValid = bls.verify(signature, message, publicKey);
console.log({ publicKey, signature, isValid });
// Sign 1 msg with 3 keys
const privateKeys = [
'18f020b98eb798752a50ed0563b079c125b0db5dd0b1060d1c1b47d4a193e1e4',
'ed69a8c50cf8c9836be3b67c7eeff416612d45ba39a5c099d48fa668bf558c9c',
'16ae669f3be7a2121e17d0c68c05a8f3d6bef21ec0f2315f1d7aec12484e4cf5'
];
const messages = ['d2', '0d98', '05caf3'];
const publicKeys = privateKeys.map(bls.getPublicKey);
const signatures2 = privateKeys.map(p => bls.sign(message, p))
const aggPubKey2 = bls.aggregatePublicKeys(publicKeys);
const aggSignature2 = bls.aggregateSignatures(signatures2);
const isValid2 = bls.verify(aggSignature2, message, aggPubKey2);
console.log({ signatures2, aggSignature2, isValid2 });
// Sign 3 msgs with 3 keys
const signatures3 = privateKeys.map((p, i) => bls.sign(messages[i], p));
const aggSignature3 = bls.aggregateSignatures(signatures3);
const isValid3 = bls.verifyBatch(aggSignature3, messages, publicKeys);
console.log({ publicKeys, signatures3, aggSignature3, isValid3 });
// Pairing API
// bls.pairing(PointG1, PointG2)
```
## Security ## Security
The library had no prior security audit. The library had no prior security audit.