Skip to content

Commit

Permalink
README, security
Browse files Browse the repository at this point in the history
  • Loading branch information
paulmillr committed Dec 28, 2022
1 parent 1bfab42 commit d77a98a
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 69 deletions.
147 changes: 78 additions & 69 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ There are two parts of the package:

1. `abstract/` directory specifies zero-dependency EC algorithms
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
- SECG curve secp256k1
- pairing-friendly curves bls12-381, bn254
- ed25519/curve25519/x25519/ristretto, edwards448/curve448/x448 RFC7748 / RFC8032 / ZIP215 stuff
- NIST curves secp192r1/P192, secp224r1/P224, secp256r1/P256, secp384r1/P384, secp521r1/P521
- SECG curve secp256k1
- pairing-friendly curves bls12-381, bn254
- ed25519/curve25519/x25519/ristretto, edwards448/curve448/x448 RFC7748 / RFC8032 / ZIP215 stuff

Curves incorporate work from previous noble packages
([secp256k1](https://github.com/paulmillr/noble-secp256k1),
Expand Down Expand Up @@ -50,6 +50,7 @@ Use NPM in node.js / browser, or include single file from
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.

```ts
// Common.js and ECMAScript Modules (ESM)
import { secp256k1 } from '@noble/curves/secp256k1';

const key = secp256k1.utils.randomPrivateKey();
Expand All @@ -62,41 +63,7 @@ const someonesPub = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
const shared = secp256k1.getSharedSecret(key, someonesPub);
```

To define a custom curve with the same functionality:

```ts
import { Fp } from '@noble/curves/abstract/modular';
import { weierstrass } from '@noble/curves/abstract/weierstrass';
import { hmac } from '@noble/hashes/hmac';
import { sha256 } from '@noble/hashes/sha256';
import { concatBytes, randomBytes } from '@noble/hashes/utils';

const secp256k1 = weierstrass({
a: 0n,
b: 7n,
Fp: Fp(2n ** 256n - 2n ** 32n - 2n ** 9n - 2n ** 8n - 2n ** 7n - 2n ** 6n - 2n ** 4n - 1n),
n: 2n ** 256n - 432420386565659656852420866394968145599n,
Gx: 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
Gy: 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
hash: sha256,
hmac: (k: Uint8Array, ...msgs: Uint8Array[]) => hmac(sha256, key, concatBytes(...msgs)),
randomBytes
});
```

## API

- [Overview](#overview)
- [Abstract algorithms](#abstract-algorithms)
- [abstract/edwards: Twisted Edwards curve](#abstract/edwards-twisted-edwards-curve)
- [abstract/montgomery: Montgomery curve](#abstract/montgomery-montgomery-curve)
- [abstract/weierstrass: Short Weierstrass curve](#abstract/weierstrass-short-weierstrass-curve)
- [abstract/modular](#abstract/modular)
- [abstract/utils](#abstract/utils)

### Overview

There are following ready-to-use curves:
All curves:

```ts
import { secp256k1 } from '@noble/curves/secp256k1';
Expand All @@ -112,7 +79,20 @@ import { bn254 } from '@noble/curves/bn';
import { jubjub } from '@noble/curves/jubjub';
```

And following zero-dependency abstract algorithms:
To define a custom curve, check out API below.

## API

- [Overview](#overview)
- [abstract/edwards: Twisted Edwards curve](#abstract/edwards-twisted-edwards-curve)
- [abstract/montgomery: Montgomery curve](#abstract/montgomery-montgomery-curve)
- [abstract/weierstrass: Short Weierstrass curve](#abstract/weierstrass-short-weierstrass-curve)
- [abstract/modular](#abstract/modular)
- [abstract/utils](#abstract/utils)

### Overview

There are following zero-dependency abstract algorithms:

```ts
import { bls } from '@noble/curves/abstract/bls';
Expand All @@ -123,38 +103,60 @@ import * as mod from '@noble/curves/abstract/modular';
import * as utils from '@noble/curves/abstract/utils';
```

### Abstract algorithms
They allow to define a new curve in a few lines of code:

```ts
import { Fp } from '@noble/curves/abstract/modular';
import { weierstrass } from '@noble/curves/abstract/weierstrass';
import { hmac } from '@noble/hashes/hmac';
import { sha256 } from '@noble/hashes/sha256';
import { concatBytes, randomBytes } from '@noble/hashes/utils';

* To initialize new curve, you must specify its variables, order (number of points on curve), field prime (over which the modular division would be done)
* All curves expose same generic interface:
* `getPublicKey()`, `sign()`, `verify()` functions
* `Point` conforming to `Group` interface with add/multiply/double/negate/add/equals methods
* `CURVE` object with curve variables like `Gx`, `Gy`, `Fp` (field), `n` (order)
* `utils` object with `randomPrivateKey()`, `mod()`, `invert()` methods (`mod CURVE.P`)
* All arithmetics is done with JS bigints over finite fields, which is defined from `modular` sub-module
* Many features require hashing, which is not provided. `@noble/hashes` can be used for this purpose.
const secp256k1 = weierstrass({
a: 0n,
b: 7n,
Fp: Fp(2n ** 256n - 2n ** 32n - 2n ** 9n - 2n ** 8n - 2n ** 7n - 2n ** 6n - 2n ** 4n - 1n),
n: 2n ** 256n - 432420386565659656852420866394968145599n,
Gx: 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
Gy: 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
hash: sha256,
hmac: (key: Uint8Array, ...msgs: Uint8Array[]) => hmac(sha256, key, concatBytes(...msgs)),
randomBytes,
});
```

- To initialize new curve, you must specify its variables, order (number of points on curve), field prime (over which the modular division would be done)
- All curves expose same generic interface:
- `getPublicKey()`, `sign()`, `verify()` functions
- `Point` conforming to `Group` interface with add/multiply/double/negate/add/equals methods
- `CURVE` object with curve variables like `Gx`, `Gy`, `Fp` (field), `n` (order)
- `utils` object with `randomPrivateKey()`, `mod()`, `invert()` methods (`mod CURVE.P`)
- All arithmetics is done with JS bigints over finite fields, which is defined from `modular` sub-module
- Many features require hashing, which is not provided. `@noble/hashes` can be used for this purpose.
Any other library must conform to the CHash interface:
```ts
export type CHash = {
(message: Uint8Array): Uint8Array;
blockLen: number; outputLen: number; create(): any;
};
```
* w-ary non-adjacent form (wNAF) method with constant-time adjustments is used for point multiplication.
```ts
export type CHash = {
(message: Uint8Array): Uint8Array;
blockLen: number;
outputLen: number;
create(): any;
};
```
- w-ary non-adjacent form (wNAF) method with constant-time adjustments is used for point multiplication.
It is possible to enable precomputes for edwards & weierstrass curves.
Precomputes are calculated once (takes ~20-40ms), after that most `G` base point multiplications:
for example, `getPublicKey()`, `sign()` and similar methods - would be much faster.
Use `curve.utils.precompute()` to adjust precomputation window size
* You could use optional special params to tune performance:
* `Fp({sqrt})` square root calculation, used for point decompression
* `endo` endomorphism options for Koblitz curves
- You could use optional special params to tune performance:
- `Fp({sqrt})` square root calculation, used for point decompression
- `endo` endomorphism options for Koblitz curves

### abstract/edwards: Twisted Edwards curve

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
* For EdDSA signatures, params `hash` is also required. `adjustScalarBytes` which instructs how to change private scalars could be specified
- 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

```typescript
import { twistedEdwards } from '@noble/curves/abstract/edwards';
Expand All @@ -171,7 +173,8 @@ const ed25519 = twistedEdwards({
Gy: 46316835694926478169428394003475163141307993866256225615783033603165251855960n,
hash: sha512,
randomBytes,
adjustScalarBytes(bytes) { // optional in general, mandatory in ed25519
adjustScalarBytes(bytes) {
// optional in general, mandatory in ed25519
bytes[0] &= 248;
bytes[31] &= 127;
bytes[31] |= 64;
Expand Down Expand Up @@ -230,7 +233,9 @@ const x25519 = montgomery({
Gu: '0900000000000000000000000000000000000000000000000000000000000000',

// Optional params
powPminus2: (x: bigint): bigint => { return mod.pow(x, P-2, P); },
powPminus2: (x: bigint): bigint => {
return mod.pow(x, P - 2, P);
},
adjustScalarBytes(bytes) {
bytes[0] &= 248;
bytes[31] &= 127;
Expand All @@ -244,10 +249,10 @@ const x25519 = montgomery({

Short Weierstrass curve's formula is: y² = x³ + ax + b. Uses deterministic ECDSA from RFC6979. You can also specify `extraEntropy` in `sign()`.

* You must specify curve params: `a`, `b`, field `Fp`, order `n`, cofactor `h` and coordinates `Gx`, `Gy` of generator point
* For ECDSA, you must specify `hash`, `hmac`. It is also possible to recover keys from signatures
* For ECDH, use `getSharedSecret(privKeyA, pubKeyB)`
* Optional params are `lowS` (default value) and `endo` (endomorphism)
- You must specify curve params: `a`, `b`, field `Fp`, order `n`, cofactor `h` and coordinates `Gx`, `Gy` of generator point
- For ECDSA, you must specify `hash`, `hmac`. It is also possible to recover keys from signatures
- For ECDH, use `getSharedSecret(privKeyA, pubKeyB)`
- Optional params are `lowS` (default value) and `endo` (endomorphism)

```typescript
import { Fp } from '@noble/curves/abstract/modular';
Expand All @@ -270,7 +275,8 @@ const secp256k1 = weierstrass({
// Optional params
h: 1n, // Cofactor
lowS: true, // Allow only low-S signatures by default in sign() and verify()
endo: { // Endomorphism options for Koblitz curve
endo: {
// Endomorphism options for Koblitz curve
// Beta param
beta: 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501een,
// Split scalar k into k1, k2
Expand Down Expand Up @@ -300,7 +306,10 @@ export type CurveFn = {
getSharedSecret: (privateA: PrivKey, publicB: PubKey, isCompressed?: boolean) => Uint8Array;
sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) => SignatureType;
verify: (
signature: Hex | SignatureType, msgHash: Hex, publicKey: PubKey, opts?: {lowS?: boolean;}
signature: Hex | SignatureType,
msgHash: Hex,
publicKey: PubKey,
opts?: { lowS?: boolean }
) => boolean;
Point: PointConstructor;
ProjectivePoint: ProjectivePointConstructor;
Expand Down
18 changes: 18 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Security Policy

## Supported Versions

| Version | Supported |
| ------- | ------------------ |
| >=0.5.0 | :white_check_mark: |
| <0.5.0 | :x: |

## Reporting a Vulnerability

Use maintainer's email specified at https://github.com/paulmillr.

It's preferred that you use
PGP key from [pgp proof](https://paulmillr.com/pgp_proof.txt) (current is [697079DA6878B89B](https://paulmillr.com/pgp_proof.txt)).
Ensure the pgp proof page has maintainer's site/github specified.

You will get an update as soon as the email is read; a "Security vulnerability" phrase in email's title would help.

0 comments on commit d77a98a

Please sign in to comment.