Ed25519 public-key signature algorithm implementation with key generation, signing, verification, and X25519 conversion
npx @tessl/cli install tessl/npm-stablelib--ed25519@2.0.0Ed25519 is a TypeScript implementation of the Ed25519 public-key signature algorithm (EdDSA with Curve25519). It provides secure key generation, message signing, signature verification, and conversion to X25519 keys. The implementation uses constant-time operations to prevent timing attacks and is compatible with standard Ed25519 implementations.
npm install @stablelib/ed25519import {
generateKeyPair,
generateKeyPairFromSeed,
extractPublicKeyFromSecretKey,
sign,
verify,
convertPublicKeyToX25519,
convertSecretKeyToX25519,
SIGNATURE_LENGTH,
PUBLIC_KEY_LENGTH,
SECRET_KEY_LENGTH,
SEED_LENGTH,
type KeyPair
} from "@stablelib/ed25519";
import type { RandomSource } from "@stablelib/random";For CommonJS:
const {
generateKeyPair,
sign,
verify
} = require("@stablelib/ed25519");import { generateKeyPair, sign, verify } from "@stablelib/ed25519";
// Generate a key pair
const keyPair = generateKeyPair();
const { publicKey, secretKey } = keyPair;
// Sign a message
const message = new TextEncoder().encode("Hello, world!");
const signature = sign(secretKey, message);
// Verify the signature
const isValid = verify(publicKey, message, signature);
console.log(isValid); // true
// Sign with a different secret key
const anotherKeyPair = generateKeyPair();
const invalidSignature = sign(anotherKeyPair.secretKey, message);
const isInvalid = verify(publicKey, message, invalidSignature);
console.log(isInvalid); // falseEd25519 is built around the elliptic curve cryptography principles:
Generate Ed25519 key pairs for digital signatures.
/**
* Generate a key pair from a 32-byte seed
* @param seed - 32-byte Uint8Array seed for deterministic key generation
* @returns KeyPair containing 32-byte public key and 64-byte secret key
* @throws Error if seed is not exactly 32 bytes
*/
function generateKeyPairFromSeed(seed: Uint8Array): KeyPair;
/**
* Generate a random key pair using secure random number generation
* @param prng - Optional random source, uses system random if not provided
* @returns KeyPair containing 32-byte public key and 64-byte secret key
*/
function generateKeyPair(prng?: RandomSource): KeyPair;
/**
* Extract the public key from a secret key
* @param secretKey - 64-byte secret key
* @returns 32-byte public key
* @throws Error if secret key is not exactly 64 bytes
*/
function extractPublicKeyFromSecretKey(secretKey: Uint8Array): Uint8Array;Sign messages and verify signatures using Ed25519 algorithm.
/**
* Sign a message with a secret key
* @param secretKey - 64-byte secret key for signing
* @param message - Message to sign (any length)
* @returns 64-byte signature
* @throws Error if secret key is not exactly 64 bytes
*/
function sign(secretKey: Uint8Array, message: Uint8Array): Uint8Array;
/**
* Verify a signature against a message and public key
* @param publicKey - 32-byte public key for verification
* @param message - Original message that was signed
* @param signature - 64-byte signature to verify
* @returns true if signature is valid, false otherwise
* @throws Error if signature is not exactly 64 bytes
*/
function verify(
publicKey: Uint8Array,
message: Uint8Array,
signature: Uint8Array
): boolean;Convert Ed25519 keys to X25519 format for key exchange protocols.
/**
* Convert Ed25519 public key to X25519 public key
* @param publicKey - 32-byte Ed25519 public key
* @returns 32-byte X25519 public key
* @throws Error if public key is invalid
*/
function convertPublicKeyToX25519(publicKey: Uint8Array): Uint8Array;
/**
* Convert Ed25519 secret key to X25519 secret key
* @param secretKey - 64-byte Ed25519 secret key (or 32-byte seed portion)
* @returns 32-byte X25519 secret key
*/
function convertSecretKeyToX25519(secretKey: Uint8Array): Uint8Array;/**
* Key pair containing both public and secret keys
*/
interface KeyPair {
/** 32-byte public key for verification and sharing */
publicKey: Uint8Array;
/** 64-byte secret key for signing (contains seed + public key) */
secretKey: Uint8Array;
}
/**
* Random source interface for custom randomness
*/
interface RandomSource {
(length: number): Uint8Array;
}/** Length of Ed25519 signatures in bytes */
const SIGNATURE_LENGTH: 64;
/** Length of Ed25519 public keys in bytes */
const PUBLIC_KEY_LENGTH: 32;
/** Length of Ed25519 secret keys in bytes */
const SECRET_KEY_LENGTH: 64;
/** Length of key generation seeds in bytes */
const SEED_LENGTH: 32;import { generateKeyPairFromSeed } from "@stablelib/ed25519";
// Generate keys from a known seed (for testing or deterministic purposes)
const seed = new Uint8Array(32);
seed.fill(1); // Don't use predictable seeds in production!
const keyPair = generateKeyPairFromSeed(seed);
// This will always produce the same key pair for the same seedimport {
generateKeyPair,
sign,
verify,
SIGNATURE_LENGTH
} from "@stablelib/ed25519";
try {
const keyPair = generateKeyPair();
const message = new TextEncoder().encode("Important message");
const signature = sign(keyPair.secretKey, message);
console.log(`Signature length: ${signature.length} bytes`); // 64 bytes
if (signature.length !== SIGNATURE_LENGTH) {
throw new Error("Invalid signature length");
}
const isValid = verify(keyPair.publicKey, message, signature);
console.log(`Signature valid: ${isValid}`);
} catch (error) {
console.error("Signing failed:", error.message);
}import {
generateKeyPair,
convertPublicKeyToX25519,
convertSecretKeyToX25519
} from "@stablelib/ed25519";
// Generate Ed25519 keys
const ed25519Keys = generateKeyPair();
// Convert to X25519 for key exchange
const x25519PublicKey = convertPublicKeyToX25519(ed25519Keys.publicKey);
const x25519SecretKey = convertSecretKeyToX25519(ed25519Keys.secretKey);
console.log(`X25519 public key length: ${x25519PublicKey.length} bytes`); // 32 bytes
console.log(`X25519 secret key length: ${x25519SecretKey.length} bytes`); // 32 bytesimport {
generateKeyPair,
extractPublicKeyFromSecretKey
} from "@stablelib/ed25519";
const keyPair = generateKeyPair();
// Extract public key from secret key (useful when you only store secret key)
const extractedPublicKey = extractPublicKeyFromSecretKey(keyPair.secretKey);
// Verify they match
const keysMatch = keyPair.publicKey.every(
(byte, index) => byte === extractedPublicKey[index]
);
console.log(`Keys match: ${keysMatch}`); // true