@noble/ed25519 Documentation

repository·main·Indexed 19 days ago

https://github.com/paulmillr/noble-ed25519

A high-performance, lightweight (5KB) JavaScript implementation of the Ed25519 EdDSA signature algorithm. Compliant with RFC8032, FIPS 186-5, and ZIP215. The library provides both asynchronous and synchronous methods for key generation, signing, and verification, including a Point class for elliptic curve arithmetic and utility namespaces for byte manipulation.

Tokens
6.8K
Snippets
30
Records
32
Agent score
66%

What's inside @noble/ed25519

  1. Upgrade from @noble/ed25519 v1 to v2

    main

    Upgrading to v2 involves significant changes as the library was refactored for security and performance:

    • Synchronous by Default: Methods are now synchronous by default. For asynchronous versions, use getPublicKeyAsync, signAsync, and verifyAsync.
    • No BigInts: bigint is no longer allowed in getPublicKey, sign, or verify to prevent bugs related to Little Endian (LE) encoding.
    • Point Class Change: The Point class (2d xy) has been replaced by ExtendedPoint (xyzt).
    • Signature Type: The Signature type was removed; use raw bytes or hex instead.
    • Utility Splitting: utils were split into utils (standard API) and etc (containing sha512Sync and others).

    Note on Feature Migration: Many features were moved to noble-curves. If you require any of the following, switch to noble-curves instead:

    • x25519 / curve25519 / getSharedSecret
    • ristretto255 / RistrettoPoint
    • Using utils.precompute() for non-base point
    • Support for environments without bigint literals
    • Common.js support
    • Support for Node.js 18 and older (without shims)
  2. Enable Synchronous Methods

    main

    To use synchronous methods (e.g., ed.keygen(), ed.sign()), you must manually provide a hash function from @noble/hashes. This allows the library to avoid a hard dependency on a specific hash implementation.

    1. Install @noble/hashes.
    2. Assign sha512 to ed.hashes.sha512.
    import * as ed from '@noble/ed25519';
    import { sha512 } from '@noble/hashes/sha2.js';
    
    ed.hashes.sha512 = sha512;
    
    // Sync methods are now available:
    const { secretKey, publicKey } = ed.keygen();
    const msg = new TextEncoder().encode('hello noble');
    const sig = ed.sign(msg, secretKey);
    const isValid = ed.verify(sig, msg, publicKey);
  3. Configure for React Native

    main

    React Native lacks a secure getRandomValues implementation and requires a manual assignment of the SHA512 hash function. You must install a React Native-specific polyfill for randomness.

    import 'react-native-get-random-values';
    import * as ed from '@noble/ed25519';
    import { sha512 } from '@noble/hashes/sha2.js';
    
    ed.hashes.sha512 = sha512;
    ed.hashes.sha512Async = (m: Uint8Array) => Promise.resolve(sha512(m));
    import 'react-native-get-random-values';
    import * as ed from '@noble/ed25519';
    import { sha512 } from '@noble/hashes/sha2.js';
    ed.hashes.sha512 = sha512;
    ed.hashes.sha512Async = (m: Uint8Array) => Promise.resolve(sha512(m));
  4. Upgrade from @noble/ed25519 v2 to v3

    main

    Upgrading to v3 introduces several breaking changes to align with noble-curves v2:

    • Input Types: Most methods now strictly expect Uint8Array. Passing string hex inputs is now prohibited.
    • New Methods: keygen and keygenAsync have been added.
    • Runtime Requirement: Node.js v20.19 is now the minimum required version.
    • Hash Configuration: Hashes are no longer set on ed.etc. They are now configured via the ed.hashes object.

    Example of updating hash configuration:

    import * as ed from '@noble/ed25519';
    import { sha512 } from '@noble/hashes/sha2.js';
    
    // Before v3:
    // ed.etc.sha512Sync = (...m: Uint8Array[]) => sha512(ed.etc.concatBytes(...m));
    // ed.etc.sha512Async = (...m: Uint8Array[]) => Promise.resolve(sha512(ed.etc.concatBytes(...m)));
    
    // In v3:
    ed.hashes.sha512 = sha512;
    ed.hashes.sha512Async = (m: Uint8Array) => Promise.resolve(sha512(m));
    import * as ed from '@noble/ed25519';
    import { sha512 } from '@noble/hashes/sha2.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));
  5. Quickstart: Basic Ed25519 usage

    main

    Use the asynchronous API to generate a secret key, derive a public key, sign a message, and verify the signature. This is the recommended way to use the library in modern environments.

    import * as ed from '@noble/ed25519';
    (async () => {
      const secretKey = ed.utils.randomSecretKey();
      const message = Uint8Array.from([0xab, 0xbc, 0xcd, 0xde]);
      const pubKey = await ed.getPublicKeyAsync(secretKey); // Sync methods are also present
      const signature = await ed.signAsync(message, secretKey);
      const isValid = await ed.verifyAsync(signature, message, pubKey);
    })();
  6. Configure SHA-512 for synchronous API usage

    main

    The synchronous methods (keygen, sign, verify) require a SHA-512 implementation to be manually provided via the hashes.sha512 property. If you are in an environment where you want to use the synchronous API, you must assign a function that takes a Bytes array and returns a Bytes array to ed.hashes.sha512 before calling those methods.

    Example using @noble/hashes:

    import * as ed from '@noble/ed25519';
    import { sha512 } from '@noble/hashes/sha2.js';
    
    // Must be done before calling synchronous keygen, sign, or verify
    ed.hashes.sha512 = sha512;
    
    const { secretKey, publicKey } = ed.keygen();
  7. Basic Usage with Async Methods

    main

    By default, the library only provides asynchronous methods to remain dependency-free. This is the standard way to use the library for key generation, signing, and verification.

    import * as ed from '@noble/ed25519';
    
    (async () => {
      const { secretKey, publicKey } = await ed.keygenAsync();
      const message = new TextEncoder().encode('hello noble');
      const signature = await ed.signAsync(message, secretKey);
      const isValid = await ed.verifyAsync(signature, message, publicKey);
    })();
    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);
    })();
  8. Derive Public Key with getPublicKey() and getPublicKeyAsync()

    main

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

    Additional Utilities:

    • ed.Point.fromBytes(publicKey): Converts bytes into a Point object.
    • ed.Point.fromHex(hex): Converts hex string into a Point object (uses RFC 8032 decompression 5.1.3).
    • ed.utils.getExtendedPublicKey(secretKey): Returns the full SHA512 hash of the seed.
    import * as ed from '@noble/ed25519';
    import { sha512 } from '@noble/hashes/sha2.js';
    ed.hashes.sha512 = sha512;
    
    (async () => {
      const { secretKey: secretKeyA } = ed.keygen();
      const pubKey = ed.getPublicKey(secretKeyA);
      const pubKeyA = await ed.getPublicKeyAsync(secretKeyA);
      const pubKeyPoint = ed.Point.fromBytes(pubKey);
      const pubKeyExtended = ed.utils.getExtendedPublicKey(secretKeyA);
    })();
  9. Sign Messages with sign() and signAsync()

    main

    Generates a deterministic EdDSA signature. The message is hashed by ed25519 internally.

    Note: For prehashed ed25519ph, use noble-curves instead.

    import * as ed from '@noble/ed25519';
    import { sha512 } from '@noble/hashes/sha2.js';
    ed.hashes.sha512 = sha512;
    
    (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);
    })();
  10. Verify Signatures with verify() and verifyAsync()

    main

    Verifies an EdDSA signature.

    Security Options:

    • Default (ZIP215): Compliant with ZIP215, suitable for consensus-critical applications.
    • Strict (RFC8032 / FIPS 186-5): Pass { zip215: false } to switch to strict verification, providing non-repudiation with SBS (Strongly Binding Signatures).

    Warning: Any message with a public key from ED25519_TORSION_SUBGROUP would be valid in signatures under ZIP215.

    import * as ed from '@noble/ed25519';
    import { sha512 } from '@noble/hashes/sha2.js';
    ed.hashes.sha512 = sha512;
    
    (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, publicKey);
    
      const isValidFips = ed.verify(signature, message, publicKey, { zip215: false });
      const isValidA = await ed.verifyAsync(signature, message, publicKey);
    })();
  11. Generate Keys with keygen() and keygenAsync()

    main

    Generates a new Ed25519 key pair. Returns an object containing secretKey and publicKey as Uint8Arrays.

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