Lesson map
Lesson 26 published. Map, example, EX051.
flowchart TD
N0["Learning outcomes"]
N1["26.1 Combining secrets"]
N2["26.2 Practical activity — Lab C"]
N3["26.3 Post-quantum signatures"]
N4["26.4 Comparing options"]
N5["Synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5
N5 --> EX["Worked example"]
EX --> Q["Exercise EX051"]
Logical drawing
flowchart LR
N0["Learning outcomes"]
N1["26.1 Combining secrets"]
N2["26.2 Practical activity — Lab C"]
N3["26.3 Post-quantum signatures"]
N4["26.4 Comparing options"]
N5["Synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> Q["EX051"]
[Learning outcomes]
|
v
[26.1 Combining secrets]
|
v
[26.2 Practical activity — Lab C]
|
v
[26.3 Post-quantum signatures]
|
v
[26.4 Comparing options]
|
v
[Synthesis]
|
v
[Worked example] --> [Exercise EX051]
Learning outcomes
You will (1) explain how hybrid secrets are combined with a key-derivation function; (2) run a toy combiner and interpret its outputs; (3) describe ML-DSA and SLH-DSA at a conceptual level; and (4) compare signature options by size, speed and assumptions.
26.1 Combining secrets
A hybrid KEM produces two shared secrets. A combiner feeds both, plus context such as the handshake transcript, into a key-derivation function (KDF) so that the output is unpredictable if either secret is. Concatenation followed by HKDF-Extract, as in the TLS hybrid design, is one standard approach; SP 800-56C Rev. 2 and SP 800-227 describe approved key-derivation and combination methods.
The combiner is small, but it is where the security of the hybrid is actually decided.
26.2 Practical activity — Lab C
# Lab C (ch 26): a hybrid key combiner. The session key depends on BOTH shared secrets.
import hashlib, hmac
def hkdf_extract(salt, ikm): return hmac.new(salt, ikm, hashlib.sha256).digest()
def combine(ss_pq, ss_trad, context):
# Concatenate secrets (PQ first, as in X25519MLKEM768), bind the transcript/context, then extract.
return hkdf_extract(b"\x00" * 32, ss_pq + ss_trad + context).hex()[:16]
pq, trad, ctx = b"P" * 32, b"T" * 32, b"handshake-transcript-hash"
print("baseline ", combine(pq, trad, ctx))
print("PQ secret changed ", combine(b"Q" * 32, trad, ctx))
print("traditional changed ", combine(pq, b"U" * 32, ctx))
print("context changed ", combine(pq, trad, b"other-transcript"))
Expected output:
baseline d48e982e8c06ca60
PQ secret changed d4c36ea2d90b2e9c
traditional changed 8dcefa12ded3d99c
context changed af06eca8abcd45a9
Changing either secret, or the context, changes the derived key completely. Binding the context prevents an attacker from reusing secrets across different handshakes.
The four keys share no visible pattern, which is the property a KDF should give. The order of inputs matters too: the lab puts the post-quantum secret first, matching X25519MLKEM768, and both ends must use the same order or they derive different keys. In a real protocol the context is the handshake transcript hash, and the output is expanded into separate keys for each direction rather than truncated as here for display.
26.3 Post-quantum signatures
ML-DSA (FIPS 204) is a lattice-based signature using the "Fiat–Shamir with aborts" technique: the signer repeatedly samples until the candidate signature reveals nothing about the key. Parameter sets ML-DSA-44, -65 and -87 have signatures of 2,420, 3,309 and 4,627 bytes. SLH-DSA (FIPS 205) relies only on hash functions; it has tiny public keys (32–64 bytes) but large signatures (7,856 to 49,856 bytes) and slower signing. LMS and XMSS are smaller and faster but stateful. FN-DSA, based on Falcon, promises compact signatures and is still in development.
26.4 Comparing options
Compare signatures on: assumption (lattice versus hash), sizes, signing and verification speed, statefulness, and ecosystem support. For TLS certificates, ML-DSA's speed and moderate size fit best. For firmware signed rarely and verified on boot, SLH-DSA's conservatism or LMS's small signatures may be preferred. For documents needing decades of trust, conservatism weighs heavily.
HCU's own choices follow this pattern: ML-DSA for its gateway certificates, with firmware signing for card terminals still under review. Each choice is written down with the reason, so it can be revisited when ecosystem support or cryptanalysis changes.
26.5 Worked example
HCU compares options for signing member statements, produced 500,000 times per month: ML-DSA-65 (3,309-byte signatures, fast signing) versus SLH-DSA-SHA2-128s (7,856-byte signatures, slow signing). The volume and PDF size favour ML-DSA-65; HCU records the residual assumption risk and plans to keep algorithm identifiers in each document so that a future change is possible.
The comparison is recorded in the decision log together with the measured signing rate on HCU's statement servers, so it can be revisited if volumes change. The measurements showed that SLH-DSA would have needed extra hardware to keep up.
26.6 Common errors and limits
- Combining secrets by XOR without context binding.
- Choosing SLH-DSA for high-volume TLS without measuring cost.
- Using stateful signatures where state cannot be protected.
- Truncating the combined output below the strength needed for the session key.
- Comparing signature schemes on signature size alone, ignoring the public key carried in each certificate.
- Leaving the algorithm identifier out of signed documents, which makes a later migration hard.
- Assuming a hybrid design is secure because each component is, without checking that the combiner binds both secrets and the context.
Exercises
- EX051 — Combiner property. Using Lab C, explain why the session key stays unpredictable if X25519 is broken but ML-KEM is not. Rubric: 3 = attacker lacks one KDF input.
- EX052 — Signature choice. Choose a signature for ATM firmware signed four times a year and justify it. Rubric: 3 = LMS/XMSS or SLH-DSA with reasoning about volume, state and conservatism.
Synthesis
Hybrid secrets are combined through a KDF bound to context. ML-DSA suits high-volume signing; SLH-DSA and stateful hash-based signatures trade size or state for conservative assumptions.
Continue studying — chapter 26 of 40
← Chapter 25 (draft) · Course chapter index · Chapter 27 (draft) →