Kyber (ML-KEM) + Dilithium (ML-DSA): A Practical Post-Quantum Handshake
Quantum computers threaten today’s most widely used public-key cryptography (RSA and classical elliptic curves) by enabling efficient attacks on their underlying math. Post-quantum cryptography (PQC) replaces those assumptions with problems believed to remain hard even for quantum adversaries.
Two flagship PQC families are:
-
Kyber (standardized as ML-KEM): a Key Encapsulation Mechanism (KEM) used to establish a shared secret.
-
Dilithium (standardized as ML-DSA): a Digital Signature Algorithm used to authenticate parties and protect against man-in-the-middle attacks.
This article explains the core math intuition and then shows a clean “handshake” that combines Kyber for confidentiality (key establishment) and Dilithium for authenticity (signing the transcript).
-
The Algebraic Playground: Polynomials Modulo a Ring
Kyber and Dilithium live in a structured polynomial ring. Intuitively, you replace big integers with polynomials, and you do arithmetic modulo both a polynomial and an integer modulus.
Rq=Zq[x] / (xn+1)R_q = \mathbb{Z}_q[x]\ /\ (x^n + 1)
Elements are polynomials of degree < n with coefficients reduced mod q. Operations are addition and multiplication in the ring. Implementations use fast polynomial multiplication (NTT) for speed.
-
Kyber (ML-KEM): A KEM from Learning With Errors
Kyber is based on the hardness of the Module-LWE problem: given “noisy” linear equations, it’s hard to recover the secret.
2.1) The Module-LWE shape
Think of a public matrix (over the ring) times a secret vector, plus a small noise term:
t=As+e\mathbf{t} = \mathbf{A}\mathbf{s} + \mathbf{e}
Where:
-
A is public (often derived from a seed),
-
s is secret (small coefficients),
-
e is small “error” noise,
-
t is public (part of the public key).
The “noise” makes solving for s computationally hard, even if you know A and t.
2.2) Kyber in three roles: KeyGen, Encaps, Decaps
Kyber is not a direct “encrypt a message” primitive in modern protocols; it’s a KEM that produces a shared secret used with symmetric crypto (e.g., AES-GCM / ChaCha20-Poly1305).
(A) Key Generation
-
Generate seed(s) to derive A.
-
Sample small secret s and error e.
-
Compute public t = A s + e.
-
Public key: (seed for A, t)
-
Secret key: s (plus auxiliary values for CCA security in real KEM constructions).
(B) Encapsulation (Client → Server)
Given the server’s public key, the client produces:
-
a ciphertext c (encapsulation), and
-
a shared secret K (derived via a KDF).
At a high level, the client samples fresh small randomness and creates a ciphertext that “hides” key material.
(C) Decapsulation (Server)
The server uses its secret key to recover the same shared secret K from c. Real Kyber KEM includes checks and fallback behavior to resist chosen-ciphertext attacks (CCA security).
-
Dilithium (ML-DSA): Signatures from Module Lattices
Dilithium is designed for strong security, clean implementation, and resistance to timing pitfalls. It is based on module lattice assumptions (often described via Module-LWE/Module-SIS style hardness).
3.1) Public key structure
A simplified mental model: the public key contains a “noisy” linear image of a secret, similarly shaped to Kyber’s structure.
t=As1+s2\mathbf{t} = \mathbf{A}\mathbf{s}_1 + \mathbf{s}_2
Where s1, s2 are small secret vectors and A is public.
3.2) Signing intuition
Dilithium uses a commit–challenge–response style:
-
Pick a fresh random y (small).
-
Compute a commitment w = A y.
-
Hash the message and (part of) w to produce a sparse challenge c.
-
Respond with z = y + c s1, while ensuring values stay within bounds (“rejection sampling”).
c=H(μ∥highbits(w))c = H(\mu \parallel \mathrm{highbits}(\mathbf{w})) z=y+cs1\mathbf{z} = \mathbf{y} + c\mathbf{s}_1
Verification checks that the response is consistent with the public key and the challenge, and that z is within safe bounds.
-
Why Kyber + Dilithium Together?
A KEM like Kyber gives you confidentiality for a session key. But without authentication, an attacker can do a classic man-in-the-middle (MITM): they establish one key with the client and a different key with the server.
A signature scheme like Dilithium provides authentication and integrity: the server can sign the handshake transcript so the client knows it is talking to the real server.
-
A Clean Post-Quantum Handshake (Simplified)
Below is a protocol-style view of a typical “PQ-TLS-like” flow using:
-
Kyber KEM for ephemeral key establishment
-
Dilithium signatures for authentication
-
A KDF to derive traffic keys
5.1) Roles and keys
-
Server has long-term Dilithium keypair: (pk_S^sig, sk_S^sig).
-
Server also has a Kyber KEM public key pk_S^kem (either long-term or rotated periodically).
5.2) Transcript hash
Define a transcript hash TH that accumulates handshake messages:
TH=H(all handshake messages so far)TH = H(\text{all handshake messages so far})
5.3) Handshake steps
Step 1 — ClientHello
C → S: ClientHello, nonce_C, supported = { Kyber/ML-KEM, Dilithium/ML-DSA, AEAD… }
Step 2 — ServerHello + KEM Public Key + Signature Key
S → C: ServerHello, nonce_S, pk_S^kem, pk_S^sig (or cert chain)
Step 3 — Kyber Encapsulation (Key Establishment)
Client encapsulates to the server’s KEM public key:
(c,K)←Encaps(pkSkem)(c, K) \leftarrow \mathrm{Encaps}(pk_S^{kem})
C → S: KEMCiphertext c
Now both sides can compute the same shared secret:
-
Client already has K.
-
Server recovers it via decapsulation.
K←Decaps(skSkem,c)K \leftarrow \mathrm{Decaps}(sk_S^{kem}, c)
Step 4 — Derive session keys with a KDF
Use nonces + transcript hash to bind the session key to the handshake:
master=KDF(K, nonceC∥nonceS∥TH)\text{master} = \mathrm{KDF}(K,\ \text{nonce}_C \parallel \text{nonce}_S \parallel TH) ktx,krx=Expand(master)k_{tx}, k_{rx} = \mathrm{Expand}(\text{master})
Step 5 — Server Authentication (Dilithium Signature)
Server signs the transcript hash so the client can verify authenticity:
σ←Sign(skSsig, TH)\sigma \leftarrow \mathrm{Sign}(sk_S^{sig},\ TH)
S → C: Signature σ over TH
Client verifies:
Verify(pkSsig,TH,σ)=?true\mathrm{Verify}(pk_S^{sig}, TH, \sigma) \stackrel{?}{=} \text{true}
If verification passes, the client trusts it shares keys with the genuine server, not a MITM.
Step 6 — Encrypted application data
Both sides now switch to symmetric AEAD with k_tx, k_rx for fast encrypted traffic.
-
Security Notes (Important in the real world)
-
CCA security matters: practical Kyber KEM constructions include checks and constant-time behavior to avoid side channels and chosen-ciphertext pitfalls.
-
Transcript binding matters: always mix handshake context into key derivation; otherwise, “key substitution” games appear.
-
Hybrid deployments are common: many systems combine classical + PQ (e.g., X25519 + Kyber) during transition for defense-in-depth.
-
Implementations are everything: PQC is robust math, but real security depends on constant-time code, correct randomness, and safe parameter handling.
-
Practical Takeaway
Kyber (ML-KEM) gives a fast, quantum-resistant way to establish a shared secret. Dilithium (ML-DSA) gives quantum-resistant authentication via signatures. Together, they form the backbone of modern post-quantum secure handshakes:
-
Kyber: “We now share a secret key.”
-
Dilithium: “And I can prove who I am.”
That combination is exactly what you want for secure sessions that must survive the “harvest now, decrypt later” era.