ADR 0003: HKDF-SHA256 KEM combiner with transcript binding
Status: Accepted
Context
A hybrid KEM produces two component shared secrets, ss_classical and
ss_pq. We need a deterministic, secure way to combine them into a single
32-byte hybrid shared secret that:
- Is IND-CCA secure if either component KEM is IND-CCA secure.
- Binds the full transcript so swapping either ciphertext changes the derived secret.
- Uses primitives that are universally available across our target frameworks without extra dependencies.
Options considered
A. Naïve concatenation: KDF(ss_classical || ss_pq)
Simple but not transcript-binding. An adversary who can substitute ciphertexts can sometimes create cross-session attacks. Insufficient.
B. X-Wing (Barbosa et al., 2024)
SS = SHA3-256(label || ss_M || X25519(eph_priv, recipient_pub) || eph_pub || recipient_pub)
(Note, 2026-06-10: the formula above reflects the early draft; the current IETF draft hashes the label last. See the amendment in ADR 0013.)
A published, peer-reviewed construction with a tight IND-CCA proof. It is
specifically designed for X25519 + ML-KEM-768. The drawback for us:
SHA3-256 is not in the BCL on every TFM, requiring BouncyCastle or
Org.BouncyCastle.Crypto.Digests.Sha3Digest.
C. HKDF-SHA256 with transcript binding (our choice)
SS = HKDF-SHA256(
ikm = ss_classical || ss_pq,
info = LABEL || ct_classical || ct_pq,
L = 32 )
HKDF-SHA256 is in System.Security.Cryptography.HKDF from .NET 6+; it's
universally available on every TFM we target and on every PQ-capable .NET
TFM going forward. Binding both ciphertexts into info provides the
transcript binding we need.
Decision
We use option C: HKDF-SHA256 with transcript binding.
sharedSecret = HKDF-SHA256(
ikm = ss_X || ss_M,
salt = empty,
info = "PostQuantum.Hybrid v1 KEM X25519-MLKEM768" || ct_X || ct_M,
L = 32 )
Rationale
- Zero new dependencies. HKDF is in the BCL; we don't add SHA3.
- Ecosystem familiarity. Developers can read this combiner without needing to study X-Wing's specific construction.
- Transcript-binding is preserved. Both ciphertexts feed into HKDF's
info, so any tampering changes the derived secret. This is the same binding property X-Wing achieves with itsrecipient_pubandeph_pubfields, just expressed differently. - Forward compatibility. A future algorithm-id
0x02can opt into X-Wing precisely if the ecosystem standardizes there.
Consequences
- We are not bit-compatible with X-Wing. A blob produced by
PostQuantum.Hybrid
0x01cannot be decrypted by an X-Wing implementation and vice versa. This is by design — we own the algorithm-id namespace. - The combiner's security is the security of HKDF as a KDF (which is proven secure when SHA-256 behaves as a PRF), composed with the security of each component KEM. Standard hybrid-KEM proof techniques apply.