6.7 Ring-LWE and Module-LWE
How polynomial rings shrink the Learning With Errors problem, and why every NIST lattice standard uses the module version.
Ring-LWE is Learning With Errors where the secret, the noise and the public values are polynomials in a ring such as . One random polynomial takes the place of a whole matrix, so keys shrink from about numbers to . Module-LWE sits in between: it uses a small matrix of such polynomials. ML-KEM (Kyber) and ML-DSA (Dilithium) are both built on Module-LWE.
Plain LWE and its size problem
In Learning With Errors you are given a random matrix and a vector , where is secret and is a vector of small errors. Recovering , or even telling apart from uniform, is believed hard. The cost is size: with , the matrix alone holds numbers. At the dimension used by ML-KEM-768, , that is 589,824 entries, and every multiplication by takes about as many operations.
What is Ring-LWE?
Ring-LWE replaces vectors of integers with polynomials and the matrix with a single polynomial. Work in the ring
whose elements are polynomials of degree below with coefficients mod . Multiplication is ordinary polynomial multiplication followed by the rule . The ring notation is summarised in 8.4 Rings and polynomials.
Definition — Ring-LWE sample
Fix a secret with small coefficients. A Ring-LWE sample is a pair where is uniformly random and has small coefficients. Search Ring-LWE asks for ; decision Ring-LWE asks whether pairs come from this distribution or are uniform.
One polynomial is a structured matrix
Multiplying by a fixed is a linear map on the coefficient vector of , so it has a matrix. Column of that matrix holds the coefficients of : the coefficients of shifted down by places, with every coefficient that wraps around negated. Take , and :
Four numbers determine all sixteen entries. With the small secret , coefficient vector , both and give mod 17. Adding the error gives the public value . Seen as a lattice problem, a Ring-LWE sample is an LWE sample whose matrix happens to be negacyclic.
The saving goes beyond storage. Because is chosen so that splits mod , products in can be computed with the number theoretic transform in operations instead of .
How hard is Ring-LWE?
Lyubashevsky, Peikert and Regev (2010) showed that, for rings such as with a power of two, solving Ring-LWE on average is at least as hard as solving approximate shortest-vector problems on ideal lattices in the worst case, using a quantum reduction. Ideal lattices are a special class, so this is a weaker foundation than the reduction for plain LWE, which starts from arbitrary lattices. In practice, the best known attacks on Ring-LWE at cryptographic parameters are the same lattice-reduction attacks used against plain LWE of the same dimension.
What is Module-LWE?
Module-LWE keeps the polynomial ring but brings back a small matrix. The secret is a vector of polynomials and the public matrix is polynomials.
Definition — Module-LWE sample
Fix a secret with small coefficients. A Module-LWE sample is with uniformly random and small. Here is the module rank, and the underlying lattice has dimension .
The two earlier problems are special cases. With the matrix is a single polynomial: that is Ring-LWE. With the ring is just and is an ordinary integer matrix: that is plain LWE. Langlois and Stehlé (2015) gave worst-case to average-case reductions for Module-LWE from problems on module lattices, which contain the ideal lattices of Ring-LWE as the rank-one case.
A toy Module-LWE sample in Python
The code below builds one sample with , and , using plain Python. It draws small values uniformly from for simplicity; ML-KEM uses a centred binomial distribution instead.
import random
n, q, k, eta = 8, 3329, 2, 2 # toy sizes; ML-KEM uses n = 256
rng = random.Random(1)
def polymul(a, b):
"""Multiply in Z_q[X]/(X^n + 1): wrap-around terms change sign."""
c = [0] * n
for i, ai in enumerate(a):
for j, bj in enumerate(b):
if i + j < n:
c[i + j] = (c[i + j] + ai * bj) % q
else:
c[i + j - n] = (c[i + j - n] - ai * bj) % q
return c
def add(a, b):
return [(x + y) % q for x, y in zip(a, b)]
def uniform():
return [rng.randrange(q) for _ in range(n)]
def small():
return [rng.randint(-eta, eta) % q for _ in range(n)]
A = [[uniform() for _ in range(k)] for _ in range(k)] # k x k matrix of polynomials
s = [small() for _ in range(k)] # secret: k small polynomials
e = [small() for _ in range(k)] # error: k small polynomials
b = []
for i in range(k):
row = e[i]
for j in range(k):
row = add(row, polymul(A[i][j], s[j]))
b.append(row)
centered = lambda p: [x - q if x > q // 2 else x for x in p]
print("s[0] =", centered(s[0]))
print("b[0] =", b[0])
print("numbers in A:", k * k * n, " plain LWE would need:", (k * n) ** 2)s[0] = [0, -2, -2, -2, 2, -2, 1, -1]
b[0] = [1055, 8, 2628, 307, 706, 570, 860, 3310]
numbers in A: 32 plain LWE would need: 256The secret stays small while looks like random numbers mod 3329. At ML-KEM-768 sizes, and , the matrix has 2,304 coefficients instead of 589,824, and ML-KEM does not even store those: it regenerates from a 32-byte seed.
Ring-LWE vs Module-LWE vs plain LWE
| Plain LWE | Ring-LWE | Module-LWE | |
|---|---|---|---|
| Public matrix | integers | one polynomial of degree | polynomials of degree |
| Lattice dimension | |||
| Numbers in the matrix | |||
| Multiplication cost | with the NTT | ||
| Structure an attacker could use | none | most (ideal lattice) | less (module lattice) |
| Changing the security level | change | change the ring | change , keep the ring |
Why ML-KEM and ML-DSA use Module-LWE
Module-LWE gives most of the size and speed of Ring-LWE while keeping one ring for every security level. ML-KEM (FIPS 203) fixes and and sets for ML-KEM-512, -768 and -1024. The same NTT code, the same polynomial arithmetic and the same hardware serve all three. ML-DSA (FIPS 204) does the same with and , using a matrix of size , and for its three parameter sets. There the security relies on Module-LWE for the keys and on Module-SIS for the signatures.
| Parameter set | Module shape | Lattice dimension | ||
|---|---|---|---|---|
| ML-KEM-512 | 256 | 3329 | 512 | |
| ML-KEM-768 | 256 | 3329 | 768 | |
| ML-KEM-1024 | 256 | 3329 | 1024 | |
| ML-DSA-44 | 256 | 8,380,417 | 1024 (secret) | |
| ML-DSA-65 | 256 | 8,380,417 | 1280 (secret) | |
| ML-DSA-87 | 256 | 8,380,417 | 1792 (secret) |
Does the ring structure make it weaker?
Structure is a risk in principle, and it is the main reason the reductions are stated for ideal or module lattices rather than all lattices. Some algebraic attacks do exist: for example, there are quantum algorithms that find unusually short vectors in principal ideal lattices better than general lattice reduction can. None of these translate into a practical attack on Ring-LWE or Module-LWE at the parameters of ML-KEM or ML-DSA, whose security estimates come from the same primal and dual lattice attacks used against plain LWE. The power-of-two cyclotomic ring is chosen because it is fast, well studied and has no known weakness for these problems. Module-LWE adds a margin over Ring-LWE because the lattice has less algebraic symmetry.
Common mistakes
- Reducing mod instead of . The wrapped coefficient must change sign. With you get a cyclic ring whose structure is weaker and whose NTT differs.
- Counting Module-LWE dimension as . The lattice an attacker reduces has dimension , which is 768 for ML-KEM-768.
- Treating Ring-LWE as proved as hard as plain LWE. Its reduction starts from ideal lattices, a narrower class. The practical evidence is that no better attack is known.
- Sampling the secret uniformly mod . Secret and error must be small; a uniform secret breaks decryption correctness and changes the problem.
Further reading
V. Lyubashevsky, C. Peikert and O. Regev, On Ideal Lattices and Learning with Errors over Rings, Eurocrypt 2010. A. Langlois and D. Stehlé, Worst-case to Average-case Reductions for Module Lattices, Designs, Codes and Cryptography, 2015. NIST FIPS 203 (ML-KEM) and FIPS 204 (ML-DSA), 2024, for the exact parameter sets. The first two references are cited from memory. See also the q-ary lattices guide for the lattice behind LWE samples.
Check Your Understanding
Q1. In , what happens to the coefficient that wraps past when you multiply by ?
Q2. Module-LWE with module rank is the same as which problem?
Q3. ML-KEM-512, ML-KEM-768 and ML-KEM-1024 differ mainly in which parameter?