Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
# `public/serialize` — `TPMT_PUBLIC` canonical serialiser
## Purpose
`serializeTpmtPublic` re-emits a parsed `TpmtPublic` value as the
TCG-canonical byte string per Library Part 2 §12.2. It is the
round-trip partner of `parseTpmtPublic`: for any input the parser
accepts, `serialize(parse(bytes))` returns the same bytes. This
property is load-bearing — `computeTpmtPublicName` per Part 1 §16
hashes the canonical bytes to produce the TPM name digest, and any
mismatch between the parser and the serialiser would silently produce a
wrong name, which in turn would silently fail every downstream
attestation check.
## Features
- Byte-identical round-trip across RSA, ECC, KEYEDHASH, and SYMCIPHER
branches.
- Preserves `rawExponent` (default-exponent normalisation is a parse-time
convenience; the wire bytes are emitted unchanged).
- Re-writes every `TPM2B_*` size prefix from the decoded payload length —
the serialiser never trusts a stored size value.
- Schema-validated input via the public API: only outputs of
`parseTpmtPublic` (which are validated) can reach the serialiser.
## Usage: Basic Example
```ts
import {
parseTpmtPublic,
serializeTpmtPublic,
} from "@suaveplan/tpm-struct/public";
const pub = parseTpmtPublic(bytes);
const reSerialised = serializeTpmtPublic(pub);
// reSerialised equals bytes byte-for-byte.
```
## Usage: Advanced Example
```ts
import {
parseTpmtPublic,
serializeTpmtPublic,
} from "@suaveplan/tpm-struct/public";
// Re-emit pub-area bytes through the canonical serialiser before signing
// or hashing. This is the canonical witness for TCG TPM 2.0 Library
// Part 1 §16 name computation.
function canonicalPubArea(rawPubArea: Uint8Array): Uint8Array {
return serializeTpmtPublic(parseTpmtPublic(rawPubArea));
}
// Property test pattern used by `property.test.ts`:
import fc from "fast-check";
fc.assert(
fc.property(fc.uint8Array({ maxLength: 600 }), (bytes) => {
// Parsing might throw; that is expected for invalid inputs.
// The serialiser is exercised only on parse-success paths.
let parsed;
try {
parsed = parseTpmtPublic(bytes);
} catch {
return true;
}
return serializeTpmtPublic(parsed).join() === bytes.join();
}),
{ numRuns: 100 }
);
```
## API Reference
- **`serializeTpmtPublic(pub: TpmtPublic): Uint8Array`** — returns a
fresh byte string. Throws `TpmStructError(PARAMETERS_INVALID)` if a
parameter substructure is internally inconsistent (e.g. non-NULL RSA
scheme without `hashAlg`).
## Implementation Notes
The serialiser dispatches on `pub.type` and walks the §12.2 field order.
The symmetric / scheme / KDF sub-writers each consult their algorithm
discriminator to decide whether trailing fields are emitted (e.g. an RSA
scheme of `TPM_ALG_NULL` emits only the 2-byte scheme id and no hashAlg).
This mirrors how the parser reads those substructures and is what makes
the round-trip property hold across the full input space.