ADR 0007: Versioned wire format with algorithm-id byte
Status: Accepted
Context
Cryptographic libraries that ship "v1" without a versioned wire format discover, three years later, that their on-the-wire blobs are stuck forever. Adding a second algorithm requires either a flag day, a new package, or heuristic detection — all bad.
We want PostQuantum.Hybrid to be able to add X25519MlKem1024,
Ed448MlDsa87, X-Wing, SLH-DSA, or whatever else the next decade
standardizes without breaking any deployed v1 deployment.
Decision
Every serialized artifact begins with a single algorithm-identifier byte. The byte's value selects which combination is used:
| Family | Byte | Combination |
|---|---|---|
| Hybrid KEM | 0x01 |
X25519 + ML-KEM-768 |
| Hybrid signatures | 0x01 |
Ed25519 + ML-DSA-65 |
Each family numbers its own identifier space. 0x00 is reserved (never
emitted; used as a parse error sentinel if a blob is zero-padded). Values
0x80–0xFF are reserved for future extension.
Rationale
- One byte costs nothing. ~0.08% overhead on the smallest blob (a hybrid sig public key).
- Parseability over time is the highest-value property of a wire format. Lose that and the library's ecosystem fragments.
- No need for length prefixes. Within a given algorithm identifier, every component is fixed-size (32, 1184, 2400, etc.). The total length is implied by the identifier.
- No need for ASN.1 / TLV. We are not negotiating across heterogeneous parser stacks; we are exchanging artifacts inside a controlled .NET ecosystem. A 1-byte version tag plus fixed-size concatenation is the simplest thing that could possibly work.
Consequences
- On deserialization, the library reads byte 0, dispatches on it, and
parses the rest with the known component sizes for that combination.
Any unknown identifier →
CryptographicException. - On serialization, the library writes byte 0 from the typed
HybridKemAlgorithm/HybridSignatureAlgorithmenum value. - Future additions: pick a new byte, add the enum value, add a new branch in the dispatch. v1 blobs continue to parse unchanged.
- PEM labels (
PQH HYBRID KEM PUBLIC KEY, etc.) are deliberately algorithm-family-scoped, not algorithm-combination-scoped, so a future combination uses the same label. The blob inside identifies the specific combination via its first byte.