# `signature` _(no submodules)_ ## Purpose `signature.ts` is the Ed25519 signature-verification gate run by the loader before any packed bytes are handed to `Unpacker.unpack`. It exists because the upstream audit (`enterprise/packer-browser.md` §3.5) explicitly required archive-signature verification — without it, an attacker who can substitute the bytes at the packed URL can ship arbitrary content to the page. By verifying the manifest signature under a caller-supplied public key first, the loader gives consumers a hard cryptographic anchor before any decompression / decryption runs. ## Features - Thin wrapper over `@suaveplan/crypto`'s `ed25519.verify` — single authoritative implementation, no parallel curve code. - Boundary defence: a signature whose length is not 64 bytes throws `PackerBrowserError(ARCHIVE_SIGNATURE_INVALID)` rather than silently returning `false`. This catches wire corruption / header mis-parse before it pollutes downstream logs. - Returns a boolean for cryptographic verify-or-not — never throws on a non-verifying-but-well-formed signature (that's a domain decision the caller makes; the loader throws on the bool side). - Optional `messageResolver` for i18n on the boundary throw. ## Usage: Basic ```ts import { verifyArchiveSignature } from "@suaveplan/packer-browser"; const ok = verifyArchiveSignature(manifestBytes, signature, publicKey); if (!ok) throw new Error("signature did not verify"); ``` ## Usage: Advanced ```ts import { ed25519 } from "@suaveplan/crypto"; import { verifyArchiveSignature } from "@suaveplan/packer-browser"; const { publicKey, secretKey } = ed25519.generateKeypair(); const message = new TextEncoder().encode("manifest:v1"); const sig = ed25519.sign(secretKey, message); const valid = verifyArchiveSignature(message, sig, publicKey); // valid === true const tampered = new Uint8Array(sig); tampered[0] ^= 1; const invalid = verifyArchiveSignature(message, tampered, publicKey); // invalid === false ``` ## API Reference - `verifyArchiveSignature(manifestBytes, signature, publicKey, opts?)` — returns `boolean`. - Throws `PackerBrowserError(ARCHIVE_SIGNATURE_INVALID)` when `signature.length !== 64`. - Forwards `publicKey` to `ed25519.verify`, which throws if the key length is not 32 bytes. - `VerifyArchiveSignatureOptions`: - `messageResolver?: MessageResolver` — resolver for the boundary error message. ## Implementation Notes Signature material is conventionally hex-encoded in the `X-Archive-Signature` response header; the loader decodes it before calling this function. The public key is **not** sourced from the wire — the loader requires the caller to pass `verifyKey` on `PackedResourceLoadOptions`, ensuring an out-of-band trust anchor. Cluster B's encrypted-archive keyring adds the per-key public-key selection step on top of this primitive; Cluster A simply takes one public key per `load(...)` call.