# streaming-aead-xchacha20 _(no submodules)_ ## Purpose `streaming-aead-xchacha20.ts` is the XChaCha20-Poly1305 adapter that satisfies the `StreamingAeadEngine` contract used by `encryptStreamAead` / `decryptStreamAead`. XChaCha20-Poly1305 is preferred over AES-GCM when the deployment runs without hardware AES acceleration or when the 24-byte extended nonce makes random-nonce schemes safer (the `2^96` random-nonce birthday-bound is comfortable, where AES-GCM's `2^48` is not). The engine declares a 20-byte caller-supplied base nonce; the per-chunk 24-byte nonce is `baseNonce ‖ counter_be32`. The high bit of the 32-bit counter carries the final-flag so terminator and data chunks at the same counter index produce different nonces. This is the default streaming engine — callers who do not pass `engine:` to `encryptStreamAead` / `decryptStreamAead` get this one. ## Features - Implements the `StreamingAeadEngine` contract — drop-in for the streaming generators. - 20-byte base nonce / 24-byte per-chunk nonce / 16-byte AEAD tag. - Counter-discipline guard: rejects negative or `> 2^32 - 1` counters with `STREAM_OUT_OF_ORDER`. - Base-nonce length guard: rejects any base nonce whose length is not exactly 20 bytes with `STREAM_INVALID_NONCE_BASE`. - Tag-mismatch promotion: open-side tag failures route to `STREAM_TAG_MISMATCH` (with the original `DECRYPT_FAILED` as cause) so streaming callers see the streaming-shaped error. ## Usage: Basic Example ```ts import { xchacha20StreamingEngine } from "@suaveplan/crypto-cipher/streaming/streaming-aead-xchacha20"; import { encryptStreamAead } from "@suaveplan/crypto-cipher/streaming/streaming-aead"; const key = crypto.getRandomValues(new Uint8Array(32)); // xchacha20StreamingEngine is the default — passing it explicitly is optional. for await (const chunk of encryptStreamAead(key, source(), { engine: xchacha20StreamingEngine, })) { sink.write(chunk); } ``` ## Usage: Advanced Example ```ts import { xchacha20StreamingEngine } from "@suaveplan/crypto-cipher/streaming/streaming-aead-xchacha20"; // Use the engine directly without the framing layer to embed XChaCha20-Poly1305 // into a custom transport. The 20-byte base nonce gives plenty of headroom for // random nonces if the caller derives one per-stream rather than per-chunk. const baseNonce = crypto.getRandomValues(new Uint8Array(20)); const ct = await xchacha20StreamingEngine.seal({ key, baseNonce, counter: 0, finalFlag: 0, data: plaintext, aad: contextBytes, }); ``` ## API Reference - `xchacha20StreamingEngine: StreamingAeadEngine` — frozen engine instance. - `BASE_NONCE_LENGTH: 20` - `NONCE_LENGTH: 24` - `TAG_LENGTH: 16` Errors: `STREAM_INVALID_NONCE_BASE`, `STREAM_OUT_OF_ORDER`, `STREAM_TAG_MISMATCH`. ## Implementation Notes XChaCha20-Poly1305 (libsodium specification, RFC draft) extends the ChaCha20 nonce from 12 to 24 bytes via HChaCha20 sub-key derivation. The 24-byte nonce makes random nonces safe (`2^96` random nonces have a `~10^-19` collision probability), which is the basis for the streaming layer using a random base nonce plus a counter. Counter-overflow at `2^32` chunks short-circuits before reuse can occur. This adapter does not generate the base nonce — the streaming generator supplies it (random by default; deterministic via the `baseNonce` option for tests).