# `name/name` — TPM 2.0 canonical name digest _(no submodules)_ ## Purpose `computeTpmtPublicName` produces the canonical TPM 2.0 name for a `TpmtPublic` value per TCG TPM 2.0 Library Part 1 — Architecture §16 _Names_. The canonical name is the two-byte big-endian `nameAlg` identifier followed by the digest of the canonical `TPMT_PUBLIC` byte serialisation under that algorithm. The W3C WebAuthn Level 3 `tpm`- attestation verifier compares this exact value against the certified name carried in the `TPMS_CERTIFY_INFO.name` slot to prove that the public area the relying party recovered is the one the TPM signed (WebAuthn L3 §8.3 step 5). ## Features - Hash backend injected via a `HashLike` interface so this package stays universal; consumers wire `@suaveplan/crypto-hash` (or any compatible primitive) at the call site. - Caller-controlled algorithm selection — the injected hash MUST match `pub.nameAlg`. - Rejects `pub.nameAlg === TPM_ALG_NULL` with `TPM_STRUCT.NAME_ALG_NULL` because a canonical name cannot be computed without a digest. - OTel: `tpm_struct.compute_name_duration_ms{name_alg}` histogram + `tpm_struct.parse_total{kind="name",outcome}` counter. ## Usage: Basic Example ```ts import { createHash } from "node:crypto"; import { computeTpmtPublicName, parseTpmtPublic, } from "@suaveplan/tpm-struct"; const pub = parseTpmtPublic(pubAreaBytes); const name = computeTpmtPublicName(pub, { digest: (b) => new Uint8Array(createHash("sha256").update(b).digest()), }); // name === 0x000b || sha256(canonical TPMT_PUBLIC bytes) ``` ## Usage: Advanced Example ```ts import { sha256, sha384, sha512 } from "@noble/hashes/sha2"; import { sha1 } from "@noble/hashes/legacy"; import { computeTpmtPublicName, parseTpmtPublic, } from "@suaveplan/tpm-struct"; // Route to the correct backend at call time based on the public area's // nameAlg. The package itself imports no hash code; the caller picks // the engine. function hashForNameAlg(nameAlg: string) { if (nameAlg === "TPM_ALG_SHA1") return { digest: sha1 }; if (nameAlg === "TPM_ALG_SHA256") return { digest: sha256 }; if (nameAlg === "TPM_ALG_SHA384") return { digest: sha384 }; if (nameAlg === "TPM_ALG_SHA512") return { digest: sha512 }; throw new Error(`unsupported nameAlg ${nameAlg}`); } const pub = parseTpmtPublic(pubAreaBytes); const name = computeTpmtPublicName(pub, hashForNameAlg(pub.nameAlg)); ``` ## API Reference - **`computeTpmtPublicName(pub: TpmtPublic, hash: HashLike): Uint8Array`** — return a fresh byte string `nameAlg (2 BE) || hash.digest(serializeTpmtPublic(pub))`. Throws `TpmStructError(NAME_ALG_NULL)` on `pub.nameAlg === "TPM_ALG_NULL"`. Re-throws any error raised by `hash.digest`. - **`HashLike`** — `{ digest(bytes: Uint8Array): Uint8Array }`. The digest size MUST match the algorithm (SHA-1 → 20, SHA-256 → 32, etc.). ## Implementation Notes The function delegates to `serializeTpmtPublic` for the canonical byte encoding so the parser and the name digest cannot drift independently. The 2-byte `nameAlg` prefix is the big-endian wire id (looked up via `nameToAlgId`) rather than the symbolic name — this matches the binary form the TPM emits and that downstream verifiers reproduce.