first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
# Ed25519
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
- [ed25519.select](./ed25519.select/ed25519.select.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519.native](./impl/ed25519.native/ed25519.native.md) — <!-- begin:auto-docs --> _(no submodules)_ - [ed25519.native](./impl/ed25519.native/ed25519.native.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519.noble](./impl/ed25519.noble/ed25519.noble.md) — <!-- begin:auto-docs --> _(no submodules)_ - [ed25519.noble](./impl/ed25519.noble/ed25519.noble.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519](./ed25519.md) — <!-- begin:auto-docs --> _(no submodules)_- ed25519.select — <!-- begin:auto-docs --> _(no submo…
- [ed25519.select](./ed25519.select/ed25519.select.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519.native](./impl/ed25519.native/ed25519.native.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519.native](./impl/ed25519.native/ed25519.native.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519.noble](./impl/ed25519.noble/ed25519.noble.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519.noble](./impl/ed25519.noble/ed25519.noble.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519](./ed25519.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519.select](./ed25519.select/ed25519.select.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519.native](./impl/ed25519.native/ed25519.native.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519.native](./impl/ed25519.native/ed25519.native.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519.noble](./impl/ed25519.noble/ed25519.noble.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519.noble](./impl/ed25519.noble/ed25519.noble.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519](./ed25519.md) — <!-- begin:auto-docs --> _(no submodules)_- ed25519.select — <!-- begin:…
- [ed25519.select](./ed25519.select/ed25519.select.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519.native](./impl/ed25519.native/ed25519.native.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519.native](./impl/ed25519.native/ed25519.native.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519.noble](./impl/ed25519.noble/ed25519.noble.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519.noble](./impl/ed25519.noble/ed25519.noble.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519](./ed25519.md) — <!-- begin:auto-docs --> _(no submodules)_- ed25519.select — <!-- begin:auto-docs --> _(no subm…
- [ed25519.select](./ed25519.select/ed25519.select.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519.native](./impl/ed25519.native/ed25519.native.md) — <!-- begin:auto-docs --> _(no submodules)_ - [ed25519.native](./impl/ed25519.native/ed25519.native.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519.noble](./impl/ed25519.noble/ed25519.noble.md) — <!-- begin:auto-docs --> _(no submodules)_ - [ed25519.noble](./impl/ed25519.noble/ed25519.noble.md) — <!-- begin:auto-docs --> _(no submodules)_- [ed25519](./ed25519.md) — <!-- begin:auto-docs --> _(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.