6.3 KiB
Ed25519
(no submodules)
- ed25519.select — (no submodules)- ed25519.native — (no submodules) - ed25519.native — (no submodules)- ed25519.noble — (no submodules) - ed25519.noble — (no submodules)- ed25519 — (no submodules)- ed25519.select — _(no submo…
- ed25519.select — (no submodules)- ed25519.native — (no submodules)- ed25519.native — (no submodules)- ed25519.noble — (no submodules)- ed25519.noble — (no submodules)- ed25519 — (no submodules)- ed25519.select — (no submodules)- ed25519.native — (no submodules)- ed25519.native — (no submodules)- ed25519.noble — (no submodules)- ed25519.noble — (no submodules)- ed25519 — (no submodules)- ed25519.select — <!-- begin:…
- ed25519.select — (no submodules)- ed25519.native — (no submodules)- ed25519.native — (no submodules)- ed25519.noble — (no submodules)- ed25519.noble — (no submodules)- ed25519 — (no submodules)- ed25519.select — _(no subm…
- ed25519.select — (no submodules)- ed25519.native — (no submodules) - ed25519.native — (no submodules)- ed25519.noble — (no submodules) - ed25519.noble — (no submodules)- ed25519 — (no submodules)
Purpose
Ed25519 is the Edwards-curve Digital Signature Algorithm defined in RFC 8032, the recommended signature scheme for new protocols. Compared with ECDSA it has deterministic signatures (no per-signature randomness needed), constant-time verification of well-formed inputs, small 32-byte public keys and 64-byte signatures, and formal soundness properties that make it the baseline choice for TLS, SSH, JWT signing, and peer-to-peer identity. This module exposes the primitive directly — key generation, signing, verification, and public-key derivation — as thin wrappers over @noble/curves/ed25519, with a paired native stub that throws PrimitiveNotImplemented. Selection between the two is controlled by crypto.config.ts at build time.
Features
getPublicKey(privateKey)→ 32-byte compressed Edwards public key.sign(message, privateKey)→ 64-byte deterministic signature.verify(signature, message, publicKey)→booleanthat never throws for malformed inputs.randomPrivateKey()→ 32 random bytes (every 32-byte value is a valid Ed25519 secret; no retry loop needed).- RFC 8032 §7.1 vector 1 is covered in tests.
- Native stub throws
PrimitiveNotImplemented('ed25519')— flip to'native'only after per-primitive audit (Phase 3).
Usage: Basic Example
import * as ed25519 from "@suaveplan/crypto-curve/ed25519";
const sk = ed25519.randomPrivateKey();
const pk = ed25519.getPublicKey(sk);
const msg = new TextEncoder().encode("hello");
const sig = ed25519.sign(msg, sk);
console.log(ed25519.verify(sig, msg, pk)); // true
Usage: Advanced Example
import * as ed25519 from "@suaveplan/crypto-curve/ed25519";
import { zeroize } from "@suaveplan/crypto-utils/zeroize";
function signAndDiscardKey(msg: Uint8Array): { pk: Uint8Array; sig: Uint8Array } {
const sk = ed25519.randomPrivateKey();
try {
const pk = ed25519.getPublicKey(sk);
const sig = ed25519.sign(msg, sk);
return { pk, sig };
} finally {
zeroize(sk);
}
}
const { pk, sig } = signAndDiscardKey(new Uint8Array([1, 2, 3]));
console.log(pk.length, sig.length);
API Reference
getPublicKey(privateKey: Uint8Array): Uint8Array— 32-byte public key. Throws ifprivateKey.length !== 32.sign(message: Uint8Array, privateKey: Uint8Array): Uint8Array— 64-byte signature.verify(signature: Uint8Array, message: Uint8Array, publicKey: Uint8Array): boolean— returnsfalseinstead of throwing on malformed inputs.randomPrivateKey(): Uint8Array— 32 random bytes via@suaveplan/crypto-utils/random.
Implementation Notes
Noble's verify throws on some malformed inputs (bad-length public key, non-canonical signature encodings) rather than returning false. The noble impl wraps the call in a try/catch so every flavour exposes a boolean-only contract — CI's differential fuzz harness depends on that uniformity. Signing is deterministic, so the same (msg, sk) pair always produces the same signature: this is a deliberate property that makes replay/caching sound and prevents fault-attack reuse. For signing data larger than a few megabytes, streaming APIs are not offered here on purpose — callers should compose over the hash-then-sign idiom instead.