Applied PQC GitHub Home Playground Blog @AppliedPQC

Introduction to Kyber (ML-KEM)

Every code listing from this chapter of Applied Post-Quantum Cryptography: 15 in total, 15 runnable here. Edit any cell and press Run.

The book's snippets build on each other down the chapter, but a Sage Cell kernel runs one cell and keeps no state afterwards, so each cell replays the earlier listings with apqc_book. That call is the only thing added to the book's own code.

← the playground

Listing 1: Simplifications used in the toy version

The real ML-KEM standard uses many sophisticated mechanisms. In the toy version, we keep only the core idea:

Although these simplifications are significant, the mathematical skeleton remains the same. For the module dimension we also shrink k from 2,3,4 down to k=2, so that the objects are easy to inspect by hand.

Listing 2: Set up the ring

We define a polynomial ring modulo x⁸+1. Every object we build from here on lives in this quotient ring R_q.

Listing 3: Set up the ring

Listing 4: Build the module: vectors and matrices of polynomials

For Kyber512, the module dimension is k=2. That means the secret is not one polynomial but a vector of k polynomials, and the public matrix A is a k × k matrix of polynomials.

Listing 5: Create small noise

In real Kyber, the noise is sampled from a centered binomial distribution (CBD), which is the subject of a later chapter. For the toy version, we simply use small coefficients in the range {-1,0,1}.

Listing 6: Key generation

The module-LWE form is very close to the standard LWE form:

We implement it as follows.

Listing 7: Verify the key generation process

We can print the matrix and the resulting public value to check that the shapes and types match expectations.

Listing 8: Encoding a message bit

For the toy version, the message is reduced to a single bit. In the real scheme, message encoding is far more subtle; here we simply map a bit to either zero or a value near the middle of the modulus range.

Listing 9: Encryption

To encrypt a message bit, we sample a random vector r and two noise terms e₁,e₂. The core equations are

Listing 10: Decryption

The decryption step uses the secret key s. The main idea is that the terms involving A and s cancel out during the algebraic expansion, leaving only a small amount of noise and the encoded message.

Listing 11: Decryption

We recover the bit by comparing circular distances to the two encoding centres, 0 and ⌊ q/2⌋. In particular, the field element 16 represents -1 and must be recognised as close to encoded zero, not as a message-one value.

Listing 12: Putting everything together

A complete toy run looks like this.

Listing 13: Why the scheme can fail sometimes

This toy construction can still fail frequently because q=17 is tiny and the accumulated error is not bounded as in ML-KEM. It illustrates cancellation and circular decoding, not a reliable encryption scheme. In real ML-KEM, the parameters are tuned so that the decryption failure probability is extremely small.

A simple experiment is to change the noise generator from

Listing 14: Why the scheme can fail sometimes

to something larger, such as

Listing 15: Why the scheme can fail sometimes

or even