# `attest/serialize` — `TPMS_ATTEST` canonical serialiser ## Purpose `serializeTpmsAttest` re-emits a parsed `TpmsAttest` value as the TCG-canonical byte string per Library Part 2 §10.12. The serialiser is the inverse of `parseTpmsAttest`: for any input the parser accepts, `serialize(parse(bytes))` returns the same bytes. This invariant is load-bearing for two downstream uses: signature verification (the TPM endorsement key signed these exact bytes — a re-serialisation that differed by a single bit would silently fail every signature check) and proxy / replay use cases that want to forward a verified attest blob without trusting the originating wire to preserve the formatting. ## Features - Byte-identical round-trip across all eight `TPMU_ATTEST` variants. - Re-emits the 32-bit `magic` prefix regardless of source — the serialiser is the authoritative encoder, not a passthrough. - Re-emits `TPM2B_*` size prefixes from the decoded payload length so a mutated stored size is silently ignored. - Renders the 17-byte `clockInfo` substructure exactly per §10.10. - Per-variant attested encoder for `CERTIFY`, `QUOTE`, `SESSION_AUDIT`, `COMMAND_AUDIT`, `TIME`, `CREATION`, `NV`, `NV_DIGEST`. ## Usage: Basic Example ```ts import { parseTpmsAttest, serializeTpmsAttest, } from "@suaveplan/tpm-struct/attest"; const att = parseTpmsAttest(bytes); const re = serializeTpmsAttest(att); // `re` equals `bytes` byte-for-byte. ``` ## Usage: Advanced Example ```ts import { parseTpmsAttest, serializeTpmsAttest, } from "@suaveplan/tpm-struct/attest"; // Proxy / verifier-of-verifiers pattern: validate, normalise, forward. function relayAttestation(raw: Uint8Array, verifySig: (b: Uint8Array) => boolean) { const att = parseTpmsAttest(raw); const canonical = serializeTpmsAttest(att); if (!verifySig(canonical)) { throw new Error("attestation signature did not verify"); } return { att, canonical }; } ``` ## API Reference - **`serializeTpmsAttest(att: TpmsAttest): Uint8Array`** — returns a fresh byte string. Does not throw on any well-typed input — the caller must construct `att` through `parseTpmsAttest` (or a Zod- validated synthetic constructor) so the input is structurally valid. ## Implementation Notes The serialiser dispatches on `att.type` via a `switch` that the TypeScript compiler verifies as exhaustive. Each per-variant encoder walks the §10.11 / §10.12 field order using `TpmBufferWriter` so size prefixes and big-endian conventions stay locked to the reader semantics. The serialiser writes into a single growing buffer to avoid the cost of multiple `Uint8Array` allocations on the encoder hot path.