# aead _(no submodules)_ ## Purpose Wraps `@suaveplan/crypto.aeadEncrypt` / `aeadDecrypt` (XChaCha20-Poly1305) into helpers that match the v1 chunk wire format, where the ciphertext and Poly1305 tag are stored in separate fields rather than as the noble-style concatenated `ciphertext || tag` buffer. Also provides the deterministic per-chunk nonce derivation used by the chunked packer. ## Features - `aeadSeal(key, nonce, plaintext)` — encrypts and returns `{ ciphertext, aeadTag }` as detached `Uint8Array` instances. - `aeadOpen(key, nonce, ciphertext, aeadTag)` — re-joins the two and decrypts; throws on tag mismatch. - `deriveChunkNonce(baseNonce, chunkId)` — `baseNonce[0..4] XOR chunkId-as-u32-BE`, deterministic and unique per chunk. - All inputs validated; failures wrapped as `PackerError(PACKER.ENCRYPTION_FAILED)`. ## Usage: Basic Example ```ts import { aeadSeal, aeadOpen, deriveChunkNonce } from "@suaveplan/packer/chunked"; const fileKey = new Uint8Array(32); // caller-supplied const baseNonce = crypto.getRandomValues(new Uint8Array(24)); const nonce = deriveChunkNonce(baseNonce, 0); const { ciphertext, aeadTag } = aeadSeal(fileKey, nonce, plaintext); const back = aeadOpen(fileKey, nonce, ciphertext, aeadTag); ``` ## Usage: Advanced Example ```ts import { aeadSeal, deriveChunkNonce } from "@suaveplan/packer/chunked"; // Seal each chunk with a derived nonce so the manifest only stores baseNonce. function sealAll(plaintexts: Uint8Array[], fileKey: Uint8Array, baseNonce: Uint8Array) { return plaintexts.map((p, i) => { const nonce = deriveChunkNonce(baseNonce, i); const { ciphertext, aeadTag } = aeadSeal(fileKey, nonce, p); return { ciphertext, aeadTag, nonce }; }); } ``` ## API Reference - **`AeadSealResult`** — `{ ciphertext: Uint8Array; aeadTag: Uint8Array }`. - **`aeadSeal(key, nonce, plaintext): AeadSealResult`** — `key` 32 B, `nonce` 24 B. Returns ciphertext (same length as plaintext) and 16-byte tag. - **`aeadOpen(key, nonce, ciphertext, aeadTag): Uint8Array`** — returns plaintext. Throws `PackerError(PACKER.ENCRYPTION_FAILED)` on tag mismatch or invalid lengths. - **`deriveChunkNonce(baseNonce, chunkId): Uint8Array`** — 24-byte nonce, deterministic per `(baseNonce, chunkId)` pair. - **Constants:** `AEAD_KEY_LEN = 32`, `AEAD_NONCE_LEN = 24`, `AEAD_TAG_LEN = 16`, `FILE_ID_LEN = 32`. ## Implementation Notes The seal helper detaches the returned `ciphertext` and `aeadTag` from the underlying combined buffer with `new Uint8Array(view)` so callers can mutate one without aliasing the other. Nonce derivation XORs only the first 32 bits to keep the rest of `baseNonce` intact — the manifest's `baseNonce` plus a `chunkId` is sufficient to reconstruct any chunk's nonce. The tag length is fixed at 16 (Poly1305); `AEAD_TAG_LEN` is exported for callers writing their own decoders.