npm package: @noble/ed25519
Description: Fastest 5KB JS implementation of ed25519 EDDSA signatures compliant with RFC8032, FIPS 186-5 & ZIP215
Author: Paul Miller
Latest version: 3.0.1

# noble-ed25519

Fastest 5KB JS implementation of ed25519 signatures.

- ✍️ [EDDSA](https://en.wikipedia.org/wiki/EdDSA) signatures compliant with
  [RFC8032](https://tools.ietf.org/html/rfc8032), FIPS 186-5
- 🪢 Consensus-friendly, compliant with [ZIP215](https://zips.z.cash/zip-0215)
- 🔖 SUF-CMA (strong unforgeability under chosen message attacks) and
  SBS (non-repudiation / exclusive ownership)
- 🪶 3.7KB (gzipped)

The module is a sister project of [noble-curves](https://github.com/paulmillr/noble-curves).
Use noble-ed25519 if you need smaller attack surface & better auditability.
Switch to noble-curves (drop-in) if you need features like ristretto255, x25519 / curve25519, ed25519ph, hash-to-curve, oprf.

### This library belongs to _noble_ cryptography

> **noble-cryptography** — high-security, easily auditable set of contained cryptographic libraries and tools.

- Zero or minimal dependencies
- Highly readable TypeScript / JS code
- PGP-signed releases and transparent NPM builds
- All libraries:
  [ciphers](https://github.com/paulmillr/noble-ciphers),
  [curves](https://github.com/paulmillr/noble-curves),
  [hashes](https://github.com/paulmillr/noble-hashes),
  [post-quantum](https://github.com/paulmillr/noble-post-quantum),
  5kb [secp256k1](https://github.com/paulmillr/noble-secp256k1) /
  [ed25519](https://github.com/paulmillr/noble-ed25519)
- [Check out the homepage](https://paulmillr.com/noble/)
  for reading resources, documentation, and apps built with noble

## Usage

> `npm install @noble/ed25519`

> `deno add jsr:@noble/ed25519`

We support all major platforms and runtimes. For React Native, additional polyfills are needed: see below.

```js
import * as ed from '@noble/ed25519';
(async () => {
  const { secretKey, publicKey } = await ed.keygenAsync();
  // const publicKey = await ed.getPublicKeyAsync(secretKey);
  const message = new TextEncoder().encode('hello noble');
  const signature = await ed.signAsync(message, secretKey);
  const isValid = await ed.verifyAsync(signature, message, publicKey);
})();
```

### Enabling synchronous methods

Only async methods are available by default, to keep the library dependency-free.
To enable sync methods:

```ts
import { sha512 } from '@noble/hashes/sha2.js';
ed.hashes.sha512 = sha512;
// Sync methods can be used now:
const { secretKey, publicKey } = ed.keygen();
// const publicKey = ed.getPublicKey(secretKey);
const sig = ed.sign(msg, secretKey);
const isValid = ed.verify(sig, msg, publicKey);
```

### React Native: polyfill getRandomValues and sha512

React Native does not provide secure getRandomValues by default.
This can't be securely polyfilled from our end, so one will need a RN-specific compile-time dep.

```ts
import 'react-native-get-random-values';
import { sha512 } from '@noble/hashes/sha2.js';
ed.hashes.sha512 = sha512;
ed.hashes.sha512Async = (m: Uint8Array) => Promise.resolve(sha512(m));
```

## API

There are 4 main methods, which accept Uint8Array-s:

- `keygen()` and `keygenAsync()`
- `getPublicKey(secretKey)` and `getPublicKeyAsync(secretKey)`
- `sign(message, secretKey)` and `signAsync(message, secretKey)`
- `verify(signature, message, publicKey)` and `verifyAsync(signature, message, publicKey)`

### keygen

```typescript
import * as ed from '@noble/ed25519';
(async () => {
  const keys = ed.keygen(); // needs ed.hashes.sha512
  const { secretKey, publicKey } = keys
  const keysA = await ed.keygenAsync();
})();
```

### getPublicKey

```typescript
import * as ed from '@noble/ed25519';
(async () => {
  const pubKey = ed.getPublicKey(secretKeyA); // needs ed.hashes.sha512
  const pubKeyA = await ed.getPublicKeyAsync(secretKeyA);
  const pubKeyPoint = ed.Point.fromBytes(pubKeyB);
  const pubKeyExtended = ed.utils.getExtendedPublicKey(secretKeyA);
})();
```

Generates 32-byte public key from 32-byte private key.

- Some libraries have 64-byte private keys - those are just priv+pub concatenated
- Use `ExtendedPoint.fromHex(publicKey)` if you want to convert hex / bytes into Point.
  It will use decompression algorithm 5.1.3 of RFC 8032.
- Use `utils.getExtendedPublicKey` if you need full SHA512 hash of seed

### sign

```ts
import * as ed from '@noble/ed25519';
(async () => {
  const { secretKey, publicKey } = ed.keygen();
  const message = new TextEncoder().encode('hello noble');
  const signature = ed.sign(message, secretKey);
  const signatureA = await ed.signAsync(message, secretKey);
})();
```

Generates deterministic EdDSA signature. `message` would be hashed by ed25519 internally.
For prehashed ed25519ph, switch to noble-curves.

### verify

```ts
import * as ed from '@noble/ed25519';
(async () => {
  const { secretKey, publicKey } = ed.keygen();
  const message = new TextEncoder().encode('hello noble');
  const signature = ed.sign(message, secretKey);
  const isValid = ed.verify(signature, message, pubKey);

  const isValidFips = ed.verify(signature, message, pubKey, { zip215: false });
  const isValidA = await ed.verifyAsync(signature, message, pubKey);
})();
```

Verifies EdDSA signature. Has SUF-CMA (strong unforgeability under chosen message attacks).
By default, follows ZIP215 [^1] and can be used in consensus-critical apps [^2].
`zip215: false` option switches verification criteria to strict
RFC8032 / FIPS 186-5 and provides non-repudiation with SBS (Strongly Binding Signatures) [^3].

> [!NOTE]
> Most other libraries don't have SUF-CMA & SBS - less optimal choice for their security.

> [!NOTE]
> Any message with pubkey from `ED25519_TORSION_SUBGROUP` would be valid in sigs under ZIP215.

### utils

A bunch of useful **utilities** are also exposed:

```typescript
import * as ed from '@noble/ed25519';
const { bytesToHex, hexToBytes, concatBytes, mod, invert, randomBytes } = ed.etc;
const { getExtendedPublicKey, getExtendedPublicKeyAsync, randomSecretKey } = ed.utils;
const { Point } = ed;
console.log(Point.CURVE(), Point.BASE);
/*
class Point {
  static BASE: Point;
  static ZERO: Point;
  readonly X: bigint;
  readonly Y: bigint;
  readonly Z: bigint;
  readonly T: bigint;
  constructor(X: bigint, Y: bigint, Z: bigint, T: bigint);
  static CURVE(): EdwardsOpts;
  static fromAffine(p: AffinePoint): Point;
  static fromBytes(hex: Bytes, zip215?: boolean): Point;
  static fromHex(hex: string, zip215?: boolean): Point;
  get x(): bigint;
  get y(): bigint;
  assertValidity(): this;
  equals(other: Point): boolean;
  is0(): boolean;
  negate(): Point;
  double(): Point;
  add(other: Point): Point;
  subtract(other: Point): Point;
  multiply(n: bigint, safe?: boolean): Point;
  multiplyUnsafe(scalar: bigint): Point;
  toAffine(): AffinePoint;
  toBytes(): Bytes;
  toHex(): string;
  clearCofactor(): Point;
  isSmallOrder(): boolean;
  isTorsionFree(): boolean;
}
*/
```

## Security

The module is production-ready.

We cross-test against sister project [noble-curves](https://github.com/paulmillr/noble-curves), which was audited and provides improved security.

- The current version has not been independently audited. It is a rewrite of v1, which has been audited by cure53 in Feb 2022:
  [PDF](https://cure53.de/pentest-report_ed25519.pdf).
- It's being fuzzed [in a separate repository](https://github.com/paulmillr/fuzzing)

If you see anything unusual: investigate and report.

### Constant-timeness

We're targetting algorithmic constant time. _JIT-compiler_ and _Garbage Collector_ make "constant time"
extremely hard to achieve [timing attack](https://en.wikipedia.org/wiki/Timing_attack) resistance
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.

### Supply chain security

- **Commits** are signed with PGP keys to prevent forgery. Be sure to verify the commit signatures
- **Releases** are made transparently through token-less GitHub CI and Trusted Publishing. Be sure to verify the [provenance logs](https://docs.npmjs.com/generating-provenance-statements) for authenticity.
- **Rare releasing** is practiced to minimize the need for re-audits by end-users.
- **Dependencies** are minimized and strictly pinned to reduce supply-chain risk.
  - We use as few dependencies as possible.
  - Version ranges are locked, and changes are checked with npm-diff.
- **Dev dependencies** are excluded from end-user installs; they’re only used for development and build steps.

For this package, there are 0 dependencies; and a few dev dependencies:

- [noble-hashes](https://github.com/paulmillr/noble-hashes) provides cryptographic hashing functionality
- jsbt is used for benchmarking / testing / build tooling and developed by the same author
- prettier, fast-check and typescript are used for code quality / test generation / ts compilation

### Randomness

We rely on the built-in
[`crypto.getRandomValues`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues),
which is considered a cryptographically secure PRNG.

Browsers have had weaknesses in the past - and could again - but implementing a userspace CSPRNG is even worse, as there’s no reliable userspace source of high-quality entropy.

### Quantum computers

Cryptographically relevant quantum computer, if built, will allow to
break elliptic curve cryptography (both ECDSA / EdDSA & ECDH) using Shor's algorithm.

Consider switching to newer / hybrid algorithms, such as SPHINCS+. They are available in
[noble-post-quantum](https://github.com/paulmillr/noble-post-quantum).

NIST prohibits classical cryptography (RSA, DSA, ECDSA, ECDH) [after 2035](https://nvlpubs.nist.gov/nistpubs/ir/2024/NIST.IR.8547.ipd.pdf). Australian ASD prohibits it [after 2030](https://www.cyber.gov.au/resources-business-and-government/essential-cyber-security/ism/cyber-security-guidelines/guidelines-cryptography).

## Speed

    npm run bench

Benchmarks measured with Apple M4.

    init 11ms
    keygen x 11,253 ops/sec @ 88μs/op
    sign x 5,891 ops/sec @ 169μs/op
    verify x 1,281 ops/sec @ 780μs/op

    keygenAsync x 10,205 ops/sec @ 97μs/op
    signAsync x 4,985 ops/sec @ 200μs/op
    verifyAsync x 1,286 ops/sec @ 777μs/op

    Point.fromBytes x 22,811 ops/sec @ 43μs/op

Compare to alternative implementations:

    tweetnacl@1.0.3 getPublicKey x 1,808 ops/sec @ 552μs/op ± 1.64%
    tweetnacl@1.0.3 sign x 651 ops/sec @ 1ms/op
    ristretto255@0.1.2 getPublicKey x 640 ops/sec @ 1ms/op ± 1.59%
    sodium-native#sign x 83,654 ops/sec @ 11μs/op

## Upgrading

### v2 to v3

v3 brings the package closer to noble-curves v2.

- Most methods now expect Uint8Array, string hex inputs are prohibited
- Add `keygen`, `keygenAsync` method
- Node v20.19 is now the minimum required version
- Various small changes for types and Point class
- etc: hashes are now set in `hashes` object:

```js
// before
ed.etc.sha512Sync = (...m: Uint8Array[]) => sha512(ed.etc.concatBytes(...m));
ed.etc.sha512Async = (...m: Uint8Array[]) => Promise.resolve(sha512(ed.etc.concatBytes(...m)));
// after
ed.hashes.sha512 = sha512;
ed.hashes.sha512Async = (m: Uint8Array) => Promise.resolve(sha512(m));
```

### v1 to v2

v2 features improved security and smaller attack surface.
The goal of v2 is to provide minimum possible JS library which is safe and fast.

That means the library was reduced 4x, to just over 300 lines. In order to
achieve the goal, **some features were moved** to
[noble-curves](https://github.com/paulmillr/noble-curves), which is
even safer and faster drop-in replacement library with same API.
Switch to curves if you intend to keep using these features:

- x25519 / curve25519 / getSharedSecret
- ristretto255 / RistrettoPoint
- Using `utils.precompute()` for non-base point
- Support for environments which don't support bigint literals
- Common.js support
- Support for node.js 18 and older without [shim](#usage)

Other changes for upgrading from @noble/ed25519 1.7 to 2.0:

- Methods are now sync by default; use `getPublicKeyAsync`, `signAsync`, `verifyAsync` for async versions
- `bigint` is no longer allowed in `getPublicKey`, `sign`, `verify`. Reason: ed25519 is LE, can lead to bugs
- `Point` (2d xy) has been changed to `ExtendedPoint` (xyzt)
- `Signature` was removed: just use raw bytes or hex now
- `utils` were split into `utils` (same api as in noble-curves) and
  `etc` (`sha512Sync` and others)

## Contributing & testing

- `npm install && npm run build && npm test` will build the code and run tests.
- `npm run bench` will run benchmarks
- `npm run build:release` will build single file

See [paulmillr.com/noble](https://paulmillr.com/noble/)
for useful resources, articles, documentation and demos
related to the library.

## License

The MIT License (MIT)

Copyright (c) 2019 Paul Miller [(https://paulmillr.com)](https://paulmillr.com)

See LICENSE file.

[^1]: https://zips.z.cash/zip-0215

[^2]: https://hdevalence.ca/blog/2020-10-04-its-25519am

[^3]: https://eprint.iacr.org/2020/1244