Fastest 5KB JS implementation of ed25519 EDDSA signatures compliant with RFC8032, FIPS 186-5 & ZIP215
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Essential utility functions for byte manipulation, hashing, key derivation operations, and mathematical utilities. These functions support the core cryptographic operations and provide common helpers for working with ed25519.
The etc object provides essential utilities for byte manipulation and mathematical operations.
const etc: {
/** Convert bytes to hex string */
bytesToHex(b: Bytes): string;
/** Convert hex string to bytes */
hexToBytes(hex: string): Bytes;
/** Concatenate multiple byte arrays */
concatBytes(...arrs: Bytes[]): Bytes;
/** Modular arithmetic operation */
mod(a: bigint, b?: bigint): bigint;
/** Modular inversion */
invert(num: bigint, md: bigint): bigint;
/** Generate cryptographically secure random bytes */
randomBytes(len?: number): Bytes;
};Usage Examples:
import { etc } from '@noble/ed25519';
// Hex conversion
const bytes = new Uint8Array([255, 0, 128, 64]);
const hex = etc.bytesToHex(bytes); // "ff008040"
const restored = etc.hexToBytes(hex);
console.log(bytes.every((b, i) => b === restored[i])); // true
// Byte concatenation
const part1 = new Uint8Array([1, 2, 3]);
const part2 = new Uint8Array([4, 5, 6]);
const combined = etc.concatBytes(part1, part2); // [1, 2, 3, 4, 5, 6]
// Random bytes generation
const randomKey = etc.randomBytes(32); // 32 random bytes
const randomNonce = etc.randomBytes(); // Default length
// Mathematical operations
const result = etc.mod(17n, 5n); // 2n
const inverse = etc.invert(3n, 7n); // Modular inverse of 3 mod 7The hashes object provides access to SHA-512 hash functions required for ed25519 operations.
const hashes: {
/** Asynchronous SHA-512 hash function using WebCrypto */
sha512Async(message: Bytes): Promise<Bytes>;
/** Synchronous SHA-512 hash function (must be set by user) */
sha512: undefined | ((message: Bytes) => Bytes);
};
/** Convenience alias for hashes.sha512Async - asynchronous hash function */
function hash(msg: Bytes): Promise<Bytes>;Usage Examples:
import { hashes, hash } from '@noble/ed25519';
// Async hashing (works out of the box)
const message = new TextEncoder().encode('Hello, World!');
const hashAsync = await hashes.sha512Async(message);
// Using the convenience function (async)
const hashResult = await hash(message);
// Setting up sync hashing
import { sha512 } from '@noble/hashes/sha512';
hashes.sha512 = sha512;
// Now sync operations work
const syncHash = hashes.sha512(message);
console.log(Buffer.from(hashAsync).equals(Buffer.from(syncHash))); // trueThe utils object provides advanced key derivation and management functions.
const utils: {
/** Get extended public key information asynchronously */
getExtendedPublicKeyAsync(secretKey: Bytes): Promise<ExtK>;
/** Get extended public key information synchronously (requires hashes.sha512) */
getExtendedPublicKey(secretKey: Bytes): ExtK;
/** Generate random secret key with optional seed */
randomSecretKey(seed?: Bytes): Bytes;
};
/** Extended key information structure */
type ExtK = {
/** First 32 bytes of SHA-512(secretKey) */
head: Bytes;
/** Second 32 bytes of SHA-512(secretKey) used as prefix */
prefix: Bytes;
/** Scalar derived from head for key operations */
scalar: bigint;
/** Public key point */
point: Point;
/** Public key in byte representation */
pointBytes: Bytes;
};Usage Examples:
import { utils } from '@noble/ed25519';
// Generate random secret key
const secretKey = utils.randomSecretKey();
console.log(secretKey.length); // 32
// Deterministic key from seed
const seed = new Uint8Array(32).fill(42);
const deterministicKey = utils.randomSecretKey(seed);
// Get extended key information (async)
const extendedInfo = await utils.getExtendedPublicKeyAsync(secretKey);
console.log('Head length:', extendedInfo.head.length); // 32
console.log('Prefix length:', extendedInfo.prefix.length); // 32
console.log('Scalar:', extendedInfo.scalar);
console.log('Point bytes length:', extendedInfo.pointBytes.length); // 32
// Sync version (requires hash function)
import { sha512 } from '@noble/hashes/sha512';
import { hashes } from '@noble/ed25519';
hashes.sha512 = sha512;
const syncExtended = utils.getExtendedPublicKey(secretKey);
console.log('Extended keys match:',
Buffer.from(extendedInfo.pointBytes).equals(Buffer.from(syncExtended.pointBytes))
);Additional mathematical operations exposed through the etc object for advanced use cases.
/**
* Modular arithmetic with optional modulus
* @param a - Number to reduce
* @param b - Modulus (defaults to curve order if not provided)
* @returns a mod b
*/
etc.mod(a: bigint, b?: bigint): bigint;
/**
* Modular multiplicative inverse
* @param num - Number to invert
* @param md - Modulus
* @returns Multiplicative inverse of num modulo md
*/
etc.invert(num: bigint, md: bigint): bigint;Usage Examples:
import { etc } from '@noble/ed25519';
// Basic modular arithmetic
const a = 123456789n;
const b = 1000n;
const remainder = etc.mod(a, b); // 789n
// Modular inverse for cryptographic operations
const num = 7n;
const modulus = 13n;
const inverse = etc.invert(num, modulus); // 2n (because 7 * 2 ≡ 1 (mod 13))
// Verify the inverse
const product = etc.mod(num * inverse, modulus);
console.log(product); // 1n
// Using with curve parameters for advanced operations
const curveOrder = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn;
const scalar = 12345n;
const reduced = etc.mod(scalar, curveOrder);Cryptographically secure random number generation for keys and nonces.
/**
* Generate cryptographically secure random bytes using WebCrypto
* @param len - Number of bytes to generate (default: 32)
* @returns Random byte array
*/
etc.randomBytes(len?: number): Bytes;
/**
* Generate random secret key with optional deterministic seed
* @param seed - Optional seed for deterministic generation
* @returns 32-byte secret key
*/
utils.randomSecretKey(seed?: Bytes): Bytes;Usage Examples:
import { etc, utils } from '@noble/ed25519';
// Generate random bytes for various purposes
const nonce = etc.randomBytes(16); // 16-byte nonce
const salt = etc.randomBytes(32); // 32-byte salt
const defaultRandom = etc.randomBytes(); // 32 bytes (default)
// Generate secret keys
const randomSecretKey = utils.randomSecretKey();
const deterministicSecretKey = utils.randomSecretKey(salt);
console.log('All keys are 32 bytes:',
randomSecretKey.length === 32 && deterministicSecretKey.length === 32
);Utility functions throw errors for invalid inputs:
hexToBytesbytesToHeximport { etc, utils } from '@noble/ed25519';
try {
// Invalid hex string
etc.hexToBytes('invalid-hex-string');
} catch (error) {
console.log('Invalid hex format');
}
try {
// Invalid secret key length
const invalidKey = new Uint8Array(31); // Should be 32
await utils.getExtendedPublicKeyAsync(invalidKey);
} catch (error) {
console.log('Invalid secret key length');
}type Bytes = Uint8Array;
type ExtK = {
head: Bytes;
prefix: Bytes;
scalar: bigint;
point: Point;
pointBytes: Bytes;
};