Post-Quantum Cryptography in Python: Learning With Errors (LWE), Regev Encryption, and Why It Resists Quantum Computers

While Shor's algorithm solves the factoring and discrete-log problems behind RSA, Diffie-Hellman, and ECC in polynomial time, the Learning With Errors (LWE) problem and Regev encryption are believed to resist quantum attack. We rigorously derive Regev's correctness condition from noise accumulation, then show with a fixed random seed that pushing sigma past the safe threshold (sigma=150) actually breaks decryption down to 30.80% correct over 1000 trials, while sigma=2 stays at 2000/2000. We sweep decryption success rate vs. sigma against the theoretical prediction, visualize how ciphertext/public-key size scale with n, and show with sympy's modular linear algebra that the secret key is recovered instantly once the error term is removed — demonstrating experimentally that the error is exactly what makes LWE hard.

Introduction

https://yuhi-sa.github.io/en/posts/20260614_cryptography_roadmap/1/ listed “Post-Quantum Cryptography (CRYSTALS-Kyber / Dilithium)” as the final placeholder for a future article. This article implements it. The factoring problem behind https://yuhi-sa.github.io/en/posts/20260225_rsa/1/ and the discrete-log problems behind https://yuhi-sa.github.io/en/posts/20260614_diffie_hellman/1/ and https://yuhi-sa.github.io/en/posts/20260702_elliptic_curve_cryptography/1/ are all known to be solvable in polynomial time on a quantum computer via Shor’s algorithm. This article examines why the Learning With Errors (LWE) problem is believed to resist quantum computers too, by implementing Regev encryption (an LWE-based public-key cryptosystem) from scratch and running numerical experiments.

Why Quantum Computers Are a Threat: Shor’s Algorithm

RSA, Diffie-Hellman, and ECC all derive their security from the assumption that certain number-theoretic problems (factoring, discrete logarithm) cannot be solved efficiently on a classical computer. What Peter Shor showed in 1994 was that efficient (polynomial-time) algorithms for these problems exist on a quantum computer. This means that once a sufficiently large quantum computer exists, RSA-, DH-, and ECC-based cryptography currently in use would in principle all become breakable. This is why the transition to Post-Quantum Cryptography (PQC), designed to resist quantum computers, is underway. NIST finalized lattice-based CRYSTALS-Kyber (key encapsulation, standardized as FIPS 203) and CRYSTALS-Dilithium (signatures, FIPS 204) as standards in 2024.

The Learning With Errors (LWE) Problem

The foundation of many post-quantum schemes, including Kyber, is the LWE problem, proposed by Oded Regev in 2005. Intuitively, it exploits the property that “mixing a small amount of noise into a system of linear equations makes solving it dramatically harder.”

LWE problem definition: given a secret vector \(\mathbf{s} \in \mathbb{Z}_q^n\) , a random matrix \(A \in \mathbb{Z}_q^{m \times n}\) , and a small error vector \(\mathbf{e} \in \mathbb{Z}_q^m\) (each component drawn from, e.g., a normal distribution), compute

\[ \mathbf{b} = A\mathbf{s} + \mathbf{e} \pmod{q} \tag{1} \]

Given \((A, \mathbf{b})\) , find \(\mathbf{s}\) . Without the error term \(\mathbf{e}\) , for \(m \geq n\) this is trivial: just solve the linear system (modular linear algebra) to find \(\mathbf{s}\) uniquely. With the error added, this simple approach breaks down, and the problem is instead shown to reduce to a hard lattice problem (such as the shortest vector problem). No known quantum algorithm — including Shor’s — is believed to solve this lattice problem efficiently.

Regev Encryption: LWE-Based Public-Key Encryption (Single-Bit Version)

The LWE problem’s hardness can be used to construct a public-key cryptosystem, as follows (a simplified version of Regev, 2005).

Key generation: choose a secret key \(\mathbf{s} \in \mathbb{Z}_q^n\) at random. The public key is the LWE instance \((A, \mathbf{b} = A\mathbf{s} + \mathbf{e})\) .

Encryption (encrypting a single bit \(b \in \{0,1\}\) ): choose a random subset \(\mathbf{r} \in \{0,1\}^m\) , and compute

\[ \mathbf{u} = \mathbf{r}^\top A \pmod q, \qquad v = \mathbf{r}^\top \mathbf{b} + b \cdot \lfloor q/2 \rfloor \pmod q \tag{2} \]

as the ciphertext.

Decryption: compute

\[ v - \mathbf{u}^\top \mathbf{s} = \mathbf{r}^\top\mathbf{e} + b\cdot\lfloor q/2\rfloor \pmod q \tag{3} \]

Since \(\mathbf{r}^\top\mathbf{e}\) is small (a sum of error terms), the result is close to \(0\) if \(b=0\) and close to \(q/2\) if \(b=1\) .

Python Implementation

import numpy as np

n, q, m, sigma = 32, 3329, 128, 2.0  # toy parameters (q matches Kyber's modulus)
rng = np.random.default_rng(20260715)  # seed fixed for every experiment in this article

def sample_error(size, sigma, q):
    e = np.round(rng.normal(0, sigma, size)).astype(np.int64) % q
    return e

def keygen():
    s = rng.integers(0, q, size=n)
    A = rng.integers(0, q, size=(m, n))
    e = sample_error(m, sigma, q)
    b = (A @ s + e) % q
    return (A, b), s

def encrypt(pub, bit, q):
    A, b = pub
    r = rng.integers(0, 2, size=A.shape[0])
    u = (r @ A) % q
    v = (int(r @ b) + bit * (q // 2)) % q
    return u, v

def decrypt(sk, ct, q):
    u, v = ct
    raw = (v - int(u @ sk)) % q
    return 1 if abs(raw - q // 2) < q // 4 else 0

Deriving Correctness: Noise Accumulation and the Decryption Condition

The decrypt function recovers the bit with the threshold test abs(raw - q // 2) < q // 4. From equation (3), \(\mathtt{raw} = \mathbf{r}^\top\mathbf{e} + b\cdot\lfloor q/2\rfloor \pmod q\) , so the necessary and sufficient condition for this test to return the correct bit is, as a signed integer before reduction mod \(q\) ,

\[ |\mathbf{r}^\top\mathbf{e}| < q/4 \tag{4} \]

(for \(b=0\) , \(\mathtt{raw}\approx 0\) must stay under \(q/4\) ; for \(b=1\) , \(\mathtt{raw}\approx\lfloor q/2\rfloor\) must stay within \(q/4\) of \(q/2\) — a symmetric condition). So the probability of correct decryption is exactly the probability that the accumulated error \(\mathbf{r}^\top\mathbf{e}\) stays below \(q/4\) . Let’s evaluate this concretely.

Step 1: the distribution of the accumulated error. With \(\mathbf{r}\in\{0,1\}^m\) and each error component \(e_i\) i.i.d. \(\mathcal{N}(0,\sigma^2)\) (treating the rounding as a continuous approximation), let \(k=\sum_i r_i\) be the Hamming weight of \(\mathbf{r}\) . Conditional on \(\mathbf{r}\) , this is a linear combination of independent Gaussians, so exactly (not merely by CLT):

\[ \mathbf{r}^\top\mathbf{e} \mid \mathbf{r} \sim \mathcal{N}(0,\, k\sigma^2) \tag{5} \]

Step 2: a rigorous worst-case bound (provable). Since \(0 \le k \le m\) always holds, applying the standard Gaussian tail bound \(P(|Z|>t) \le 2\exp(-t^2/2v)\) for \(Z\sim\mathcal{N}(0,v)\) with \(t=q/4\) , \(v=k\sigma^2 \le m\sigma^2\) gives, regardless of \(\mathbf{r}\) :

\[ P(\text{decryption fails}\mid \mathbf{r}) \le 2\exp\!\left(-\frac{q^2}{32\,k\,\sigma^2}\right) \le 2\exp\!\left(-\frac{q^2}{32\,m\,\sigma^2}\right) \tag{6} \]

To keep the failure probability under \(2^{-\lambda}\) , this gives the design constraint

\[ q \;\gtrsim\; 4\sigma\sqrt{2m\lambda\ln 2} \;=\; \Theta\!\left(\sigma\sqrt{m\lambda}\right) \tag{7} \]

— the basic noise-growth law that recurs throughout LWE-based cryptosystem design: the modulus \(q\) must scale with the noise standard deviation \(\sigma\) times roughly the square root of the number of samples \(m\) being combined. The dimension \(n\) doesn’t appear directly, but since \(m\) is usually chosen proportional to \(n\) (this article uses \(m=4n\) ), a larger \(n\) indirectly forces a larger \(q\) to keep the same safety margin.

Step 3: a sharper practical estimate. Equation (6) is a provable bound using the worst case \(k\le m\) , but in practice \(\mathbf{r}\) is drawn uniformly from \(\{0,1\}^m\) , so \(k\) follows \(\mathrm{Binomial}(m, 1/2)\) and concentrates tightly around \(m/2\) (Chernoff bound). Substituting \(k\approx m/2\) gives the closer-to-reality approximation

\[ P(\text{decryption fails}) \approx 2\left(1-\Phi\!\left(\frac{q/4}{\sigma\sqrt{m/2}}\right)\right) \tag{8} \]

which we check directly against measurement in Experiment 2 below.

Experiment 1: Verifying Decryption Correctness

Using toy parameters \(n=32\) (lattice dimension), \(q=3329\) (the same modulus Kyber uses), \(m=128\) (LWE samples in the public key), and \(\sigma=2.0\) (error standard deviation), with seed 20260715 fixed, we ran 2000 trials of encrypting and decrypting a random bit.

correct decryptions: 2000/2000 (100.00%)

All 2000 trials decrypted correctly. At \(\sigma=2.0\) , equation (8) predicts a failure probability far below \(10^{-100}\) (\(q/4\approx 832\) against \(\sigma\sqrt{m/2}=2\times 8=16\) — the threshold is more than 50 standard deviations away), so 0 failures out of 2000 is exactly what the theory predicts.

Experiment 2: The Noise σ vs. Correctness Trade-Off (Theory vs. Measurement)

The central design dilemma in post-quantum cryptography is that “a larger error \(\mathbf{e}\) is more secure (the LWE problem gets harder), but too large and even the legitimate recipient fails to decrypt.” To test the prediction of equation (8), we swept \(\sigma\) across 27 points from 2 to 300, running 20 key generations × 400 encrypt/decrypt trials at each point (8000 trials per point), and overlaid the measured success rate on the theoretical curves from equations (6) and (8).

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm

n, q, m = 32, 3329, 128
SEED = 20260715

def sample_error(size, sigma, q, rng):
    return np.round(rng.normal(0, sigma, size)).astype(np.int64) % q

def keygen(rng, sigma):
    s = rng.integers(0, q, size=n)
    A = rng.integers(0, q, size=(m, n))
    e = sample_error(m, sigma, q, rng)
    b = (A @ s + e) % q
    return (A, b), s

def encrypt(pub, bit, rng):
    A, b = pub
    r = rng.integers(0, 2, size=A.shape[0])
    u = (r @ A) % q
    v = (int(r @ b) + bit * (q // 2)) % q
    return u, v

def decrypt(sk, ct):
    u, v = ct
    raw = (v - int(u @ sk)) % q
    return 1 if abs(raw - q // 2) < q // 4 else 0

def theory_typical_success(sigma):  # equation (8)
    z = (q / 4) / (sigma * np.sqrt(m / 2))
    return 100 * (1 - 2 * norm.sf(z))

sigmas = [2, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112,
          120, 128, 140, 150, 165, 175, 190, 200, 225, 250, 275, 300]
n_keygens, trials_per_keygen = 20, 400
rng_master = np.random.default_rng(SEED)
for sigma in sigmas:
    correct, total = 0, 0
    for _ in range(n_keygens):
        rng = np.random.default_rng(rng_master.integers(0, 2**31 - 1))
        pub, sk = keygen(rng, sigma)
        for _ in range(trials_per_keygen):
            bit = int(rng.integers(0, 2))
            ct = encrypt(pub, bit, rng)
            correct += decrypt(sk, ct) == bit
            total += 1
    print(sigma, 100 * correct / total, theory_typical_success(sigma))
\(\sigma\)Measured successEq. (8) prediction
3299.99%99.88%
6491.50%89.59%
9669.65%72.15%
12861.83%58.36%
15053.50%51.20%
20050.89%39.70%
30050.02%27.12%

Regev decryption success rate vs. noise standard deviation sigma. Measured points (black dots) closely track the practical approximation from equation (8) (blue line) for sigma up to about 100; the rigorous worst-case bound from equation (6) (red dashed line) gives a more conservative estimate

For \(\sigma \lesssim 100\) , measurement and the theoretical prediction from equation (8) agree closely. For \(\sigma \gtrsim 150\) , however, the theoretical predictions (equations (6) and (8)) keep decreasing toward 0%, while the measured success rate plateaus at 50% (a coin flip) and never drops further. This is because the “continuous Gaussian \(e_i\) ” approximation of equation (5) breaks down: the implementation’s sample_error reduces the error mod \(q\) , and once \(\sigma\) grows to the same order as \(q\) , the error is no longer “small Gaussian noise” but nearly uniform on \(\mathbb{Z}_q\) . In that regime raw is also nearly uniform on \(\mathbb{Z}_q\) , and since the decision interval \((q/4, 3q/4)\) spans exactly half of \(\mathbb{Z}_q\) , the probability of returning 1 converges to exactly 1/2 regardless of the true bit. Equation (8) doesn’t model this modular wraparound, so it predicts a pessimistically low success rate at large \(\sigma\) — a useful failure case, since it shows exactly where the simplified Gaussian approximation stops applying. Real Kyber carefully tunes this trade-off, using a far more sophisticated error distribution and parameter selection than this toy implementation, to keep the decryption failure probability around \(2^{-140}\) while maintaining strong security.

Edge Case (a): Decryption Actually Fails Once the Threshold Is Crossed

The theory and the figure suggest that pushing \(\sigma\) far past the safe zone should make decryption actually return the wrong bit. We verify this with a single fixed key. From the same seed 20260715, we first generate a key, then run 1000 encrypt/decrypt trials (since the true-bit sequence is drawn from the RNG state left over after key generation, the following “unsafe” and “safe” runs encrypt the exact same sequence of bits).

def demo(sigma, n_show, n_total, seed):
    rng = np.random.default_rng(seed)
    pub, sk = keygen(rng, sigma)
    mismatches = 0
    for t in range(n_total):
        bit = int(rng.integers(0, 2))
        ct = encrypt(pub, bit, rng)
        u, v = ct
        raw = (v - int(u @ sk)) % q
        dec = 1 if abs(raw - q // 2) < q // 4 else 0
        if t < n_show:
            print(t, bit, dec, raw, "OK" if dec == bit else "FAIL")
        mismatches += dec != bit
    print(f"correct: {n_total - mismatches}/{n_total} ({100*(n_total-mismatches)/n_total:.2f}%)")

demo(sigma=150, n_show=20, n_total=1000, seed=20260715)  # unsafe regime
demo(sigma=2,   n_show=20, n_total=1000, seed=20260715)  # safe regime (same seed)

First 20 trials in the unsafe regime (\(\sigma=150\) , equation (8) predicts 51.20% success):

trial true_bit decrypted_bit    raw  match
    0        1             1   1213     OK
    1        0             1   1071   FAIL
    2        0             1   1819   FAIL
    3        1             0    686   FAIL
    4        1             0    505   FAIL
    5        0             0    312     OK
    6        1             0   3128   FAIL
    7        1             0    649   FAIL
    8        1             0   2807   FAIL
    9        1             0   3068   FAIL
   10        0             0    667     OK
   11        1             0   3119   FAIL
   12        1             0   3107   FAIL
   13        0             1   1302   FAIL
   14        1             0   2626   FAIL
   15        0             0    614     OK
   16        0             0    635     OK
   17        1             0   3301   FAIL
   18        1             1   1752     OK
   19        0             0   3316     OK
... (1000 trials total)
correct decryptions: 308/1000 (30.80%)

At σ=150, only 308 of 1000 trials (30.80%) decrypted correctly — worse than a coin flip. This happens because the particular error vector \(\mathbf{e}\) generated for this key happens to carry a bias: \(\mathbb{E}_{\mathbf{r}}[\mathbf{r}^\top\mathbf{e}\mid\mathbf{e}] = \frac{1}{2}\sum_i e_i\) is a key-specific systematic shift that, for this particular key, pushed the threshold test the wrong way. (Equation (8) predicts the average behavior across many keys — it doesn’t guarantee the behavior of any single specific key, and this is a concrete example of that gap.)

Rewinding to \(\sigma=2\) (safe regime) with the same seed:

correct decryptions: 1000/1000 (100.00%)

With the same random seed and the same plaintext-bit sequence, dropping σ from 150 to 2 alone brings decryption back to 1000/1000 correct. The importance of keeping the noise in the safe regime is confirmed with concrete numbers.

As an aside, \(\sigma=32\) — which looked like “100.00%” in Experiment 2’s table — showed 4 failures out of 1000 trials (99.60%) once we ran enough trials to see it. A failure event too rare to show up in 300 trials becomes visible at 1000: decryption correctness is a high-probability guarantee, not an absolute one, and this boundary case makes that concrete.

Experiment 3: Without the Error, the Secret Key Is Recovered Instantly

To directly confirm that LWE’s hardness comes specifically from the error term, we tested whether the secret key could be recovered in the error-free case (\(\mathbf{b} = A\mathbf{s}\) , an ordinary linear system).

import sympy

A0 = np.array(rng.integers(1, q, size=(n, n)))
s_true = rng.integers(0, q, size=n)
b0 = (A0 @ s_true) % q  # no error term

A0_inv_mod = sympy.Matrix(A0.tolist()).inv_mod(q)  # matrix inverse mod q
s_recovered = np.array([int(x) for x in (A0_inv_mod * sympy.Matrix(b0.tolist())) % q]).flatten()
max |recovered - true| (should be 0): 0
s fully recovered: True

Computing the matrix inverse mod \(q\) recovered the secret key completely and instantly. This shows that an error-free system of equations is solvable by simple linear algebra (\(O(n^3)\) ). The error is essential to the LWE problem’s hardness — it’s exactly what enables the reduction to the “shortest vector problem on a lattice,” a problem with no known efficient solution, even on a quantum computer.

Edge Case (b): The Parameter-Size Security/Efficiency Trade-Off

In this article’s Regev scheme, the ciphertext is \((\mathbf{u}, v) \in \mathbb{Z}_q^n \times \mathbb{Z}_q\) and the public key is \((A, \mathbf{b}) \in \mathbb{Z}_q^{m\times n} \times \mathbb{Z}_q^m\) . Counting bits with \(\lceil\log_2 q\rceil = 12\) (\(q=3329\) ):

\[ \begin{aligned} \text{ciphertext size} &= (n+1)\lceil\log_2 q\rceil \text{ bits} \\ \text{public key size} &= m(n+1)\lceil\log_2 q\rceil \text{ bits} \end{aligned} \tag{9} \]

(keeping this article’s toy ratio \(m=4n\) as \(n\) varies).

ns = np.array([32, 64, 128, 256, 512, 768, 1024])
ms = 4 * ns
bits_q = 12  # ceil(log2(3329))
ciphertext_bytes = (ns + 1) * bits_q / 8
pubkey_bytes = ms * (ns + 1) * bits_q / 8
\(n\)\(m\)Ciphertext sizePublic-key size
3212849.5 B6.2 KB
128512193.5 B96.8 KB
5122048769.5 B1.50 MB
102440961537.5 B6.01 MB

Ciphertext and public-key size vs. n. This article’s toy scheme (blue/green lines) shows the public key exploding as O(n^2), while real ML-KEM (red markers) keeps a similar ciphertext size at the same n but a public-key size of only a few KB

Ciphertext size grows only roughly linearly with \(n\) (about 1.5KB even at \(n=1024\) ), but assuming \(m\propto n\) , the public-key size grows quadratically (\(O(n^2)\) ) with \(n\) , reaching about 6MB at \(n=1024\) . This is the concrete number behind the claim in the “Relationship to CRYSTALS-Kyber” section below that “the public key grows as \(O(nm)\) .” The figure also overlays real ML-KEM (Kyber) published figures. ML-KEM-512/768/1024 (\(n=k\times 256\) , \(k=2,3,4\) ) have ciphertext sizes of 768/1088/1568 bytes respectively — remarkably close to this article’s toy ciphertext sizes at the same \(n\) (769.5/1153.5/1537.5 bytes), since we matched \(q\) to Kyber’s value. However, public-key sizes for ML-KEM are 800/1184/1568 bytes — three to four orders of magnitude smaller than this toy scheme’s 1.50MB–6.01MB. That gap is exactly the payoff of regenerating the matrix \(A\) from a short seed via the structure of a polynomial ring, instead of transmitting it in full — one of the core ideas behind Module-LWE.

On the security-cost side, informally, the following is known. Standard methods for estimating the cost of the most practical attacks against LWE/Module-LWE (lattice-basis reduction such as BKZ) — the “core-SVP” methodology — estimate that attack cost grows roughly exponentially with the dimension. The Kyber specification submitted to NIST reports that ML-KEM-512 (\(n=512\) ) offers roughly 118 bits of classical / 107 bits of quantum hardness, ML-KEM-768 (\(n=768\) ) roughly 182/165 bits, and ML-KEM-1024 (\(n=1024\) ) roughly 256/232 bits. Note that this is simply quoting published figures — we have not actually estimated a comparable attack cost for this article’s toy scheme (\(n=32\) ). The toy parameters \(n=32\) , \(q=3329\) are a pedagogical simplification and make no security claim. Still, the qualitative structure — that increasing \(n\) trades off an efficiency cost (larger keys/ciphertexts) against a security gain (harder lattice problem) — is visible both in this figure and in Kyber’s published numbers.

Edge Case (c): Why LWE Is Believed to Resist Shor’s Algorithm

The integer-factoring problem behind RSA and the discrete-log problems behind Diffie-Hellman/ECC all reduce to the same underlying mathematical structure: the Hidden Subgroup Problem (HSP) over abelian groups. The heart of Shor’s algorithm is that the quantum Fourier transform (QFT) solves the abelian HSP in polynomial time. Factoring reduces to order-finding in \((\mathbb{Z}/N\mathbb{Z})^*\) , and discrete log reduces to an HSP over \(\mathbb{Z}\times\mathbb{Z}\) — both are attacked through the same “abelian group + QFT” framework.

The LWE problem (and the underlying lattice problems — shortest vector problem, bounded-distance decoding) has no known efficient reduction to an abelian HSP. The hidden-subgroup analogue for lattice problems is believed to be closer to the HSP over the non-abelian dihedral group (or the closely related “hidden lattice problem”), and because the dihedral group is non-abelian, the standard QFT-based attack does not apply. Indeed, the best known quantum algorithm for the dihedral HSP (Kuperberg, 2005) runs in subexponential time \(2^{O(\sqrt{n})}\) — nowhere near the polynomial time Shor’s algorithm achieves. Regev (2004) also shows a connection between lattice problems and the dihedral coset problem, while arguing that this connection does not translate into an efficient quantum algorithm.

It’s important to be honest here: there is no proof that LWE resists quantum computers. What we do know is (1) no polynomial-time quantum algorithm for lattice problems has been found over more than two decades of effort, and (2) lattice problems don’t naturally fit the “abelian group + QFT” attack pattern that breaks RSA/discrete-log. This is circumstantial evidence that no efficient attack is known — not a mathematical proof that none exists. In fact, improving classical and quantum attacks on lattice problems remains an active research area (see “Recent Research” below), so this circumstantial picture could change in the future.

Relationship to CRYSTALS-Kyber

The Regev encryption in this article is a simplified, pedagogical version: it can only encrypt one bit at a time, and — as confirmed concretely in the previous section — the public key grows as \(O(nm)\) . Real CRYSTALS-Kyber solves this by using LWE over a polynomial ring (Module-LWE). Instead of integer vectors, it uses elements of the polynomial ring \(\mathbb{Z}_q[x]/(x^n+1)\) , and instead of matrix operations, polynomial multiplication (which pairs well with fast NTT — Number Theoretic Transform — acceleration). This dramatically reduces key size and computation while allowing multiple bits to be encrypted at once. The core properties this toy implementation confirmed — that the error is the source of hardness, that error size trades off against correctness, and that key size trades off against security — hold just as much for Module-LWE.

Recent Research (2024-2025)

  • Alongside FIPS 203 (ML-KEM) and FIPS 204 (ML-DSA), NIST also finalized FIPS 205 (SLH-DSA, a hash-based signature scheme built on SPHINCS+) in August 2024. It is positioned as a conservative alternative signature scheme that depends only on hash-function hardness rather than lattice problems.
  • In March 2025, NIST selected the code-based scheme HQC (Hamming Quasi-Cyclic) as a fifth PQC algorithm, to serve as a backup to ML-KEM. It rests on a completely different mathematical foundation (error-correcting codes) from lattice problems, part of a diversification strategy to have an alternative ready in case ML-KEM’s underlying assumption is ever broken (a draft standard is expected around 2026, with finalization targeted for 2027).
  • Wenger, Saxena, Malhou, Thieu, & Lauter (2025), “Benchmarking Attacks on Learning with Errors,” IEEE Symposium on Security and Privacy (S&P) 2025, systematically benchmarks major attack algorithms (uSVP, SALSA, Cool & Cruel, Dual Hybrid Meet-in-the-Middle) against Kyber-style sparse secrets. Traditional uSVP attacks turn out to be ineffective in this setting, while ML-based attacks recover binomial secrets in 28-36 hours under certain configurations — underscoring that estimating the real-world cost of attacking LWE is still very much an open, evolving problem.
  • Stevens, Wenger, Li, Nolte, Saxena, Charton, & Lauter (2024), “Salsa Fresca: Angular Embeddings and Pre-Training for ML Attacks on Learning With Errors,” arXiv:2402.01082, improves transformer-based ML attacks for recovering sparse LWE secrets, reporting the first instance of such attacks recovering sparse binary secrets at dimension \(n=1024\) — a practically-sized cryptographic parameter. Together with the previous section’s point that “attack cost is only known through published estimates,” this shows that how ML-based attacks affect LWE’s practical security margin is an actively evolving question.

References

  • Regev, O. (2005). On lattices, learning with errors, random linear codes, and cryptography. Proceedings of the 37th Annual ACM Symposium on Theory of Computing (STOC).
  • Regev, O. (2004). Quantum computation and lattice problems. SIAM Journal on Computing, 33(3), 738-760.
  • Kuperberg, G. (2005). A subexponential-time quantum algorithm for the dihedral hidden subgroup problem. SIAM Journal on Computing, 35(1), 170-188.
  • Peikert, C. (2016). A decade of lattice cryptography. Foundations and Trends in Theoretical Computer Science, 10(4), 283-424.
  • Shor, P. W. (1997). Polynomial-time algorithms for prime factorization and discrete logarithms on a quantum computer. SIAM Journal on Computing, 26(5), 1484-1509.
  • National Institute of Standards and Technology (2024). Module-Lattice-Based Key-Encapsulation Mechanism Standard. FIPS 203 (CRYSTALS-Kyber).
  • National Institute of Standards and Technology (2024). Module-Lattice-Based Digital Signature Standard. FIPS 204 (CRYSTALS-Dilithium).
  • National Institute of Standards and Technology (2024). Stateless Hash-Based Digital Signature Standard. FIPS 205 (SLH-DSA).
  • National Institute of Standards and Technology (2025). NIST Selects HQC as Fifth Algorithm for Post-Quantum Encryption. NIST News, March 11, 2025.
  • Wenger, E., Saxena, E., Malhou, M., Thieu, E., & Lauter, K. (2025). Benchmarking attacks on learning with errors. IEEE Symposium on Security and Privacy (S&P) 2025.
  • Stevens, S., Wenger, E., Li, C., Nolte, N., Saxena, E., Charton, F., & Lauter, K. (2024). Salsa Fresca: Angular embeddings and pre-training for ML attacks on Learning With Errors. arXiv:2402.01082.