# `public/public` — `TPMT_PUBLIC` parser _(no submodules)_ - serialize — `serializeTpmtPublic` re-emits a parsed… - [serialize](./serialize.md) — `serializeTpmtPublic` re-emits a parsed `TpmtPublic` value as the TCG-canonical byte string per Library Part 2 §12.2. I… - serialize — `serializeTpmtPublic` re-emits a parsed… - [serialize](./serialize.md) — `serializeTpmtPublic` re-emits a parsed `TpmtPublic` value as the TCG-canonical byte string per Library Part 2 §12.2. I… - serialize — `serializeTpmtPublic` re-emits a parsed… - [serialize](./serialize.md) — `serializeTpmtPublic` re-emits a parsed `TpmtPublic` value as the TCG-canonical byte string per Library Part 2 §12.2. I… - serialize — `serializeTpmtPublic` re-emits a parsed… - [serialize](./serialize.md) — `serializeTpmtPublic` re-emits a parsed `TpmtPublic` value as the TCG-canonical byte string per Library Part 2 §12.2. I… - [serialize](./serialize.md) — `serializeTpmtPublic` re-emits a parsed `TpmtPublic` value as the TCG-canonical byte string per Library Part 2 §12.2. I… ## Purpose `parseTpmtPublic` decodes a TCG TPM 2.0 `TPMT_PUBLIC` byte string per Library Part 2 §12.2 into a discriminated-union value keyed on the `TPMI_ALG_PUBLIC` `type` field. The four supported branches — `TPM_ALG_RSA`, `TPM_ALG_ECC`, `TPM_ALG_KEYEDHASH`, `TPM_ALG_SYMCIPHER` — each decode their own `TPMS_*_PARMS` parameter substructure and matching `TPMU_PUBLIC_ID` unique slot. The parser is the central seam between the on-the-wire byte format and every downstream consumer of TPM public areas: `computeTpmtPublicName` re-emits the bytes through `serializeTpmtPublic` and hashes them for the canonical Part 1 §16 name digest, while the WebAuthn `tpm`-format verifier validates the `pubArea` against the credential public key in `authData.attestedCredentialData`. ## Features - Full §12.2 field order enforcement (`type` → `nameAlg` → `objectAttributes` → `authPolicy` → `parameters` → `unique`). - RSA-2048/3072/4096 with default-exponent (`0` → `65537`) normalisation per §12.2.3.5 plus a `rawExponent` slot preserved for round-trip fidelity. - ECC P-256/P-384/P-521/BN-256/BN-638/SM2-256 with `curveID` lookup via the §11.2.5 registry; unknown curves raise `CURVE_UNSUPPORTED`. - KEYEDHASH NULL / HMAC / XOR schemes per §12.2.3.3. - SYMCIPHER with full `TPMT_SYM_DEF_OBJECT` decoding per §12.2.3.4. - `objectAttributes` decoded into raw `uint32` + typed flag struct; reserved bits non-zero raise `OBJECT_ATTRIBUTES_RESERVED_NONZERO`. - Boundary Zod schema (`TpmtPublicSchema`) validates the constructed result before returning — malformed parser output raises `MALFORMED`. - OTel histograms (`tpm_struct.parse_tpmt_public_duration_ms{type,outcome}`) - counters (`tpm_struct.parse_total{kind="public",outcome}` and `tpm_struct.parse_errors_total{code}`). ## Usage: Basic Example ```ts import { parseTpmtPublic } from "@suaveplan/tpm-struct/public"; const pub = parseTpmtPublic(pubAreaBytes); if (pub.type === "TPM_ALG_RSA") { console.log(pub.parameters.keyBits, pub.parameters.exponent); console.log(pub.unique.modulus.byteLength); } ``` ## Usage: Advanced Example ```ts import { createHash } from "node:crypto"; import { computeTpmtPublicName, parseTpmtPublic, } from "@suaveplan/tpm-struct"; const pub = parseTpmtPublic(pubAreaBytes); if (pub.nameAlg === "TPM_ALG_SHA256" && pub.type === "TPM_ALG_ECC") { const name = computeTpmtPublicName(pub, { digest: (b) => new Uint8Array(createHash("sha256").update(b).digest()), }); // `name` is `0x000b || sha256(serializeTpmtPublic(pub))` — feed this // into the WebAuthn `tpm`-attestation name-match step (W3C WebAuthn // L3 §8.3 step 5). } ``` ## API Reference - **`parseTpmtPublic(bytes: Uint8Array): TpmtPublic`** — returns a discriminated-union value. Throws `TpmStructError` with one of `ALG_UNSUPPORTED`, `CURVE_UNSUPPORTED`, `OBJECT_ATTRIBUTES_RESERVED_NONZERO`, `PARAMETERS_INVALID`, `TRUNCATED`, or `MALFORMED`. - **`TpmtPublic`** — discriminator union over `type`. Each branch carries `nameAlg`, `objectAttributes`, `authPolicy`, `parameters`, `unique`. ## Implementation Notes The parser is deliberately straight-line: every field decode advances the underlying `TpmBufferReader`'s cursor by exactly the bytes named in the spec. `assertEnd()` is called at the end of every successful parse so a trailing byte is reported as `TRUNCATED` rather than silently dropped. The exponent-zero normalisation rule is preserved alongside `rawExponent` because re-serialisation must emit the original bytes so the §16 name digest stays stable.