# Ed25519 _(no submodules)_ - [ed25519.select](./ed25519.select/ed25519.select.md) — _(no submodules)_- [ed25519.native](./impl/ed25519.native/ed25519.native.md) — _(no submodules)_ - [ed25519.native](./impl/ed25519.native/ed25519.native.md) — _(no submodules)_- [ed25519.noble](./impl/ed25519.noble/ed25519.noble.md) — _(no submodules)_ - [ed25519.noble](./impl/ed25519.noble/ed25519.noble.md) — _(no submodules)_- [ed25519](./ed25519.md) — _(no submodules)_- ed25519.select — _(no submo… - [ed25519.select](./ed25519.select/ed25519.select.md) — _(no submodules)_- [ed25519.native](./impl/ed25519.native/ed25519.native.md) — _(no submodules)_- [ed25519.native](./impl/ed25519.native/ed25519.native.md) — _(no submodules)_- [ed25519.noble](./impl/ed25519.noble/ed25519.noble.md) — _(no submodules)_- [ed25519.noble](./impl/ed25519.noble/ed25519.noble.md) — _(no submodules)_- [ed25519](./ed25519.md) — _(no submodules)_- [ed25519.select](./ed25519.select/ed25519.select.md) — _(no submodules)_- [ed25519.native](./impl/ed25519.native/ed25519.native.md) — _(no submodules)_- [ed25519.native](./impl/ed25519.native/ed25519.native.md) — _(no submodules)_- [ed25519.noble](./impl/ed25519.noble/ed25519.noble.md) — _(no submodules)_- [ed25519.noble](./impl/ed25519.noble/ed25519.noble.md) — _(no submodules)_- [ed25519](./ed25519.md) — _(no submodules)_- ed25519.select — _(no submodules)_- [ed25519.native](./impl/ed25519.native/ed25519.native.md) — _(no submodules)_- [ed25519.native](./impl/ed25519.native/ed25519.native.md) — _(no submodules)_- [ed25519.noble](./impl/ed25519.noble/ed25519.noble.md) — _(no submodules)_- [ed25519.noble](./impl/ed25519.noble/ed25519.noble.md) — _(no submodules)_- [ed25519](./ed25519.md) — _(no submodules)_- ed25519.select — _(no subm… - [ed25519.select](./ed25519.select/ed25519.select.md) — _(no submodules)_- [ed25519.native](./impl/ed25519.native/ed25519.native.md) — _(no submodules)_ - [ed25519.native](./impl/ed25519.native/ed25519.native.md) — _(no submodules)_- [ed25519.noble](./impl/ed25519.noble/ed25519.noble.md) — _(no submodules)_ - [ed25519.noble](./impl/ed25519.noble/ed25519.noble.md) — _(no submodules)_- [ed25519](./ed25519.md) — _(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)` → `boolean` that 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 ```ts 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 ```ts 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 if `privateKey.length !== 32`. - `sign(message: Uint8Array, privateKey: Uint8Array): Uint8Array` — 64-byte signature. - `verify(signature: Uint8Array, message: Uint8Array, publicKey: Uint8Array): boolean` — returns `false` instead 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.