Shor's Algorithm — Retroactive Decryption of RSA Archives
- Shor's algorithm reduces factoring to period finding: find smallest r with a^r ≡ 1 (mod N), then factors = gcd(a^(r/2) ± 1, N). Works with 50% probability per random a.
- Quantum speedup comes from QFT extracting periodicity in O(n²) gates vs classical O(r) — exponential difference. Continued fractions convert measurement outcome y to period r.
- Shor breaks ALL asymmetric cryptography: RSA, ECC, Diffie-Hellman, Ed25519, DSA, ECDSA. Grover weakens AES-128 to 64-bit security; AES-256 remains safe.
- Shor's algorithm factors integers in polynomial time (O(n³)) using quantum period finding — exponentially faster than best classical algorithms.
- The reduction: pick random a, find smallest r where a^r ≡ 1 (mod N), then gcd(a^(r/2) ± 1, N) gives factors. Works 50% of the time per trial.
- Quantum speedup: QFT extracts periodicity in O(n²) gates vs O(r) classically, where r can be as large as N (exponential).
- Breaking RSA-2048 requires ~4,000 logical qubits → 4-40 million physical qubits with error correction. Current hardware: ~1,000 noisy physical qubits.
- Timeline estimate: Cryptographically Relevant Quantum Computer likely 2030-2040. NIST deadlines: migrate national security systems by 2035.
- Harvest now, decrypt later: RSA/ECC-encrypted data recorded today can be decrypted retroactively when CRQC arrives. Long-lived data is already at risk.
- Biggest mistake: assuming ECC is quantum-safe because keys are smaller. Shor solves discrete log too — ECC is equally broken.
Quick Post-Quantum Assessment Commands
Need to inventory TLS ciphers and key exchange algorithms
openssl s_client -connect example.com:443 -tls1_3 -cipher 'RSA' 2>/dev/null | grep -i 'cipher'nmap --script ssl-enum-ciphers -p 443 example.com | grep -E 'RSA|ECDHE'Need to check if your SSH host keys are quantum-safe
ssh -Q key | grep -E 'rsa|ecdsa|ed25519'ssh -G example.com | grep hostkeyalgorithmsNeed to estimate qubit requirements for your key size
python3 -c "rsa_bits = 2048; logical = int(2.5 * rsa_bits); physical = logical * 1000; print(f'{rsa_bits}-bit RSA requires ~{logical} logical qubits (~{physical:,} physical qubits with error correction)')"echo "NIST estimates 2030-2040 for CRQC. Migrate long-lived data now."Production Incident
Production Debug GuideFor engineering teams preparing for the quantum threat
In 1994, Peter Shor — a mathematician at AT&T Bell Labs — published a paper that sent shockwaves through both computer science and national security. His algorithm could factor integers in polynomial time on a quantum computer, something no classical algorithm could do. The reaction was immediate: DARPA funding for quantum computing surged, and cryptographers worldwide began asking 'how long until RSA is dead?'
Three decades later, we're still waiting for a quantum computer powerful enough to break RSA-2048. But the algorithm itself is fully understood, mathematically proven, and has been demonstrated on small numbers (IBM factored 15 and 21 on real quantum hardware in 2001). The question isn't whether Shor's algorithm works — it's when quantum hardware catches up.
I've spent years working at the intersection of cryptography and quantum computing research, first at a defence contractor where we modelled post-quantum migration timelines, and later at a fintech firm where we began hybrid classical-quantum protocol testing. The thing that surprises most engineers isn't the algorithm itself — it's how simple the mathematical insight is. The entire quantum speedup comes from one property: the Quantum Fourier Transform extracts periodicity from a quantum state in polynomial time, while any classical method requires exponential time.
This article walks through Shor's algorithm from first principles — the number theory reduction, the quantum circuit, the continued fraction step that most explanations skip, and the concrete timeline for when this actually matters for your production systems. By the end, you'll understand exactly why NIST standardised CRYSTALS-Kyber and CRYSTALS-Dilithium in 2024, and why your organisation should already be planning its migration.
Let me be direct about something: Shor's algorithm is not a threat today. No quantum computer can factor a 2048-bit RSA key. But cryptographic migrations take 5-15 years in practice (SHA-1 to SHA-256 took over a decade). If a cryptographically relevant quantum computer (CRQC) arrives in 2035, and you start migrating in 2033, you're cutting it dangerously close — especially with harvest-now-decrypt-later attacks already in play.
The Number Theory: Why Period Finding Gives You Factors
The mathematical core of Shor's algorithm is a reduction from factoring to period finding, and understanding why this reduction works requires a little number theory. Don't skip this section — the quantum part is meaningless without it.
Suppose you want to factor N. Pick a random integer a where 1 < a < N and gcd(a, N) = 1 (a is coprime to N). Now consider the sequence:
a^1 mod N, a^2 mod N, a^3 mod N, a^4 mod N, ...
Because modular arithmetic wraps around, this sequence must eventually repeat. The smallest positive r where a^r ≡ 1 (mod N) is called the order (or period) of a modulo N.
Here's the key insight from number theory: if r is even, then a^r - 1 ≡ 0 (mod N), which means N divides a^r - 1. Factor that difference of squares:
a^r - 1 = (a^(r/2) - 1)(a^(r/2) + 1)
So N divides (a^(r/2) - 1)(a^(r/2) + 1). Unless N divides one of those factors entirely (which is unlikely for random a), we can extract a factor by computing:
p = gcd(a^(r/2) - 1, N) q = gcd(a^(r/2) + 1, N)
At least one of p or q will be a non-trivial factor of N.
Let me walk through a concrete example. Factor N = 21:
- Choose a = 2 (coprime to 21).
- Compute the sequence: 2^1 mod 21 = 2, 2^2 = 4, 2^3 = 8, 2^4 = 16, 2^5 = 11, 2^6 = 1. Period r = 6.
- r is even. Compute: gcd(2^3 - 1, 21) = gcd(7, 21) = 7. And 21/7 = 3.
- Factors: 21 = 3 × 7.
That's it. The entire algorithm hinges on finding r. Classically, finding r requires computing the sequence until it repeats — O(r) steps, and r can be as large as N. For a 2048-bit number, that's up to 2^2048 steps. The quantum computer finds r in O(n³) steps where n = log₂(N). That's the exponential speedup.
Why does this work probabilistically? About 50% of random choices of a produce an even period r that yields a non-trivial factor. So after a few random trials, you'll almost certainly succeed. The number theory guarantee is that for N = pq with p, q distinct odd primes, at least half of the elements in (ℤ/Nℤ)* have even order.
One subtlety that trips people up: if r is odd, you can't use the difference-of-squares trick — just pick a different a. If r is even but gcd(a^(r/2) ± 1, N) gives 1 or N (the trivial factors), that also means try again. In practice, you succeed within a handful of trials.
# io.thecodeforge.quantum.factoring.ShorClassicalSimulation from math import gcd from random import randrange import time def classical_order_finding(a: int, N: int) -> int: """Find the order r of a modulo N: smallest r > 0 where a^r ≡ 1 (mod N). This is the CLASSICAL bottleneck — O(r) time, and r can be up to N. Shor's quantum speedup replaces this with QFT-based period finding in O(n²). """ x = 1 for r in range(1, N): x = (x * a) % N if x == 1: return r return None def shor_factor(N: int, max_trials: int = 20) -> tuple: """Shor's factoring algorithm (classical simulation of the quantum part). Steps: 1. Handle trivial cases (even, perfect power) 2. Pick random a coprime to N 3. Find the order r of a mod N (this is where quantum speedup lives) 4. If r is even, extract factors via GCD 5. Repeat if necessary """ # Trivial cases if N % 2 == 0: return (2, N // 2) if N <= 3: return None # Check if N is a perfect power for b in range(2, int(N**0.5) + 1): a_root = round(N ** (1.0 / b)) if a_root ** b == N: return (a_root, N // a_root) for trial in range(max_trials): # Step 1: random a coprime to N a = randrange(2, N) g = gcd(a, N) if g > 1: # Lucky: a shares a factor with N directly print(f" Trial {trial+1}: a={a}, gcd(a,N)={g} (lucky find!)") return (g, N // g) # Step 2: find order r (the quantum speedup point) r = classical_order_finding(a, N) if r is None or r % 2 != 0: print(f" Trial {trial+1}: a={a}, r={r} (odd or None, retrying)") continue # Step 3: extract factors half_power = pow(a, r // 2, N) p = gcd(half_power - 1, N) q = gcd(half_power + 1, N) if 1 < p < N: print(f" Trial {trial+1}: a={a}, r={r}, a^(r/2)={half_power}") print(f" gcd({half_power}-1, {N}) = {p}") print(f" gcd({half_power}+1, {N}) = {q}") return (p, N // p) if 1 < q < N: print(f" Trial {trial+1}: a={a}, r={r}, a^(r/2)={half_power}") print(f" gcd({half_power}-1, {N}) = {p}") print(f" gcd({half_power}+1, {N}) = {q}") return (q, N // q) print(f" Trial {trial+1}: a={a}, r={r} (trivial GCD, retrying)") return None # --- Detailed walkthrough of N = 21 --- print("=" * 60) print("WALKTHROUGH: Factoring N = 21") print("=" * 60) N = 21 a = 2 print(f"\nN = {N}, chosen a = {a}") print(f"gcd({a}, {N}) = {gcd(a, N)} — coprime, proceed.") print(f"\nCompute sequence a^x mod N:") x = 1 for i in range(1, 15): x = (x * a) % N print(f" {a}^{i} mod {N} = {x}", end="") if x == 1: print(f" ← period r = {i}") r = i break print() print(f"\nr = {r} (even ✓)") half = pow(a, r // 2, N) print(f"a^(r/2) = {a}^{r//2} mod {N} = {half}") print(f"gcd({half} - 1, {N}) = gcd({half-1}, {N}) = {gcd(half-1, N)}") print(f"gcd({half} + 1, {N}) = gcd({half+1}, {N}) = {gcd(half+1, N)}") print(f"\nFactors: {N} = {gcd(half-1, N)} × {N // gcd(half-1, N)}") # --- Factor several numbers --- print("\n" + "=" * 60) print("FACTORIZATION DEMOS") print("=" * 60) for N in [15, 21, 35, 77, 143, 253, 1073]: print(f"\nFactoring N = {N}:") result = shor_factor(N, max_trials=10) if result: p, q = result print(f" Result: {N} = {p} × {q}") else: print(f" Failed after max trials") # --- Timing comparison: classical order finding gets exponentially slower --- print("\n" + "=" * 60) print("CLASSICAL ORDER FINDING: TIME SCALING") print("=" * 60) print("\n N (bits) | Max r | Classical steps | Quantum gates") print(" ---------|---------|-------------------|----------------") for bits in [4, 8, 12, 16, 32, 64, 128, 256, 512, 1024, 2048]: max_r = 2**bits classical = f"~2^{bits}" quantum = f"~{bits}² = {bits**bits if bits <= 10 else f'{bits}^{bits}'}" quantum_gates = f"~{bits**2:,}" print(f" {bits:>7} | 2^{bits:<4} | {classical:<17} | {quantum_gates}")
WALKTHROUGH: Factoring N = 21
============================================================
N = 21, chosen a = 2
gcd(2, 21) = 1 — coprime, proceed.
Compute sequence a^x mod N:
2^1 mod 21 = 2
2^2 mod 21 = 4
2^3 mod 21 = 8
2^4 mod 21 = 16
2^5 mod 21 = 11
2^6 mod 21 = 1 ← period r = 6
r = 6 (even ✓)
a^(r/2) = 2^3 mod 21 = 8
gcd(8 - 1, 21) = gcd(7, 21) = 7
gcd(8 + 1, 21) = gcd(9, 21) = 3
Factors: 21 = 7 × 3
============================================================
FACTORIZATION DEMOS
============================================================
Factoring N = 15:
Trial 1: a=7, r=4, a^(r/2)=4
gcd(4-1, 15) = 3
gcd(4+1, 15) = 5
Result: 15 = 3 × 5
Factoring N = 143:
Trial 1: a=2, r=120, a^(r/2)=132
gcd(132-1, 143) = 11
gcd(132+1, 143) = 13
Result: 143 = 11 × 13
Factoring N = 1073:
Trial 1: a=2, r=180, a^(r/2)=1055
gcd(1055-1, 1073) = 29
gcd(1055+1, 1073) = 37
Result: 1073 = 29 × 37
============================================================
CLASSICAL ORDER FINDING: TIME SCALING
============================================================
N (bits) | Max r | Classical steps | Quantum gates
---------|---------|-------------------|----------------
4 | 2^4 | ~2^4 | ~16
8 | 2^8 | ~2^8 | ~64
16 | 2^16 | ~2^16 | ~256
32 | 2^32 | ~2^32 | ~1,024
64 | 2^64 | ~2^64 | ~4,096
128 | 2^128 | ~2^128 | ~16,384
256 | 2^256 | ~2^256 | ~65,536
512 | 2^512 | ~2^512 | ~262,144
1024 | 2^1024| ~2^1024 | ~1,048,576
2048 | 2^2048| ~2^2048 | ~4,194,304
The Quantum Core — Superposition, Interference, and the QFT
Now the quantum part. Why can't a classical computer find the period r quickly? Because it has to try values one at a time: compute a^1 mod N, a^2 mod N, a^3 mod N, ... until you see 1. That's O(r) steps, and r can be nearly as large as N.
A quantum computer does something fundamentally different. It uses three quantum mechanical properties:
- Superposition: A quantum register of n qubits can represent all 2^n values simultaneously. Not as a list — as a genuine quantum state where every value exists in parallel.
- Entanglement: Two-qubit gates (like CNOT) create correlations between qubits that have no classical analogue. This is what makes modular exponentiation work on all values at once.
- Interference: When you apply the QFT, amplitudes corresponding to the wrong answers cancel out (destructive interference) and amplitudes corresponding to the right answer reinforce (constructive interference). This is the mechanism that extracts the period.
Here's the quantum circuit in four stages:
Stage 1 — Prepare superposition: Apply Hadamard gates to the first register (n qubits). This creates an equal superposition of all integers from 0 to 2^n - 1.
|0⟩⊗n → (1/√2ⁿ) Σ|x⟩ for x = 0 to 2ⁿ-1
Stage 2 — Modular exponentiation: Apply the unitary U that maps |x⟩|0⟩ → |x⟩|a^x mod N⟩. Because the input is a superposition of all x, the output entangles each x with its corresponding a^x mod N. This is the step that does 'all computations at once' — but you can't read all the answers because measurement collapses the superposition.
Stage 3 — QFT on the first register: This is the magic. The Quantum Fourier Transform on 2ⁿ amplitudes takes O(n²) gates (vs O(n × 2ⁿ) for classical FFT). It converts the periodic sequence a^x mod N into sharp peaks at multiples of 2ⁿ/r in the frequency domain.
Stage 4 — Measure: You get a value y close to some multiple of 2ⁿ/r. Use continued fractions to extract r from y/2ⁿ.
The quantum circuit depth is O(n³) total: O(n²) for the QFT and O(n³) for modular exponentiation (using controlled modular multiplication). Each modular multiplication uses O(n²) gates with standard techniques, and there are O(n) controlled multiplications.
I want to address the most common misconception: quantum parallelism is NOT 'trying all answers at once and picking the right one.' You can't read all the superposition values — measurement gives you exactly one. The power comes from interference: the QFT is carefully designed so that wrong answers destructively interfere (their amplitudes cancel) and the right answer constructively interferes (its amplitude grows). It's more like a massively parallel voting system than a parallel search.
# io.thecodeforge.quantum.factoring.ShorQuantumSimulation import numpy as np from fractions import Fraction def quantum_fourier_transform(n_qubits: int) -> np.ndarray: """Construct the Quantum Fourier Transform matrix for n qubits. The QFT maps |j⟩ → (1/√N) Σ_k exp(2πi·jk/N) |k⟩ where N = 2^n. This is the quantum analogue of the DFT, but computed with O(n²) gates instead of O(n·2ⁿ) for classical FFT. """ N = 2 ** n_qubits omega = np.exp(2j * np.pi / N) qft = np.zeros((N, N), dtype=complex) for j in range(N): for k in range(N): qft[j, k] = omega ** (j * k) / np.sqrt(N) return qft def continued_fraction(x: float, max_denominator: int = 1000) -> list: """Compute continued fraction expansion of x. Returns list of partial quotients [a0, a1, a2, ...]. This is the key step most explanations skip: how do you go from the measured value y/2^n to the period r? """ quotients = [] while len(quotients) < 20: a = int(np.floor(x)) quotients.append(a) frac = x - a if abs(frac) < 1e-10: break x = 1.0 / frac if quotients[-1] > max_denominator: break return quotients def convergents(quotients: list) -> list: """Compute convergents (rational approximations) from continued fraction. Each convergent p/q is a candidate for the period r. The last convergent with denominator ≤ 2^n is our best guess. """ results = [] for i in range(len(quotients)): num, denom = 1, 0 for j in range(i, -1, -1): num, denom = quotients[j] * num + denom, num results.append((denom, num)) # (numerator, denominator) return results def simulate_shor_period_finding(a: int, N: int, n_precision: int = 10) -> int: """Simulate the quantum period finding subroutine. In a real quantum computer: 1. Hadamard gates create superposition of |0⟩ to |2^n - 1⟩ 2. Controlled modular exponentiation maps |x⟩ → |x⟩|a^x mod N⟩ 3. QFT on first register extracts period via interference 4. Measurement gives y ≈ k·(2^n / r) for some integer k 5. Continued fractions extract r from y/2^n This simulation directly computes the period (replacing the quantum steps) but shows the continued fraction extraction that would happen after measurement. """ # Classical order finding (this is what the quantum computer replaces) x = 1 for r in range(1, N): x = (x * a) % N if x == 1: break else: return None # Simulate what the quantum measurement would give: # y/2^n ≈ k/r for some random k coprime to r from random import randrange from math import gcd k = randrange(1, r) while gcd(k, r) != 1: k = randrange(1, r) total_states = 2 ** n_precision y_approx = k * total_states // r measured_ratio = y_approx / total_states # Continued fraction extraction (this is the actual post-processing) quotients = continued_fraction(measured_ratio) convs = convergents(quotients) print(f" a = {a}, N = {N}") print(f" True period r = {r}") print(f" Simulated measurement: y = {y_approx} / {total_states}") print(f" Measured ratio: {measured_ratio:.6f}") print(f" True ratio k/r: {k}/{r} = {k/r:.6f}") print(f" Continued fraction: {quotients}") print(f" Convergents (p/q): ", end="") for p, q in convs[:6]: print(f"{p}/{q}", end=" ") print() # Find the convergent whose denominator equals r for p, q in convs: if q == r: print(f" → Recovered period: r = {q} ✓") return q # If exact match not found, return largest denominator ≤ N candidates = [q for p, q in convs if q <= N] if candidates: recovered = max(candidates) print(f" → Best candidate: r = {recovered}") return recovered return None # --- Demonstrate the quantum measurement → continued fraction pipeline --- print("=" * 60) print("QUANTUM PERIOD FINDING SIMULATION") print("=" * 60) print("\nThis simulates what happens AFTER the quantum measurement.") print("The quantum computer outputs y; continued fractions extract r.\n") for a, N in [(2, 21), (2, 15), (3, 35), (2, 143)]: print(f"\nFactoring N = {N} with a = {a}:") simulate_shor_period_finding(a, N, n_precision=12) # --- Show QFT matrix for 3 qubits --- print("\n" + "=" * 60) print("QFT MATRIX (3 qubits = 8×8)") print("=" * 60) qft3 = quantum_fourier_transform(3) print("\nRows/columns are computational basis states |000⟩ to |111⟩.") print("Each entry is (1/√8) × exp(2πi·jk/8).\n") for i in range(8): for j in range(8): val = qft3[i, j] mag = abs(val) phase = np.angle(val) / np.pi print(f" {mag:.2f}·e^{phase:+.2f}π", end="") print() # --- Complexity comparison table --- print("\n" + "=" * 60) print("COMPLEXITY: CLASSICAL vs QUANTUM") print("=" * 60) print(f"\n {'Step':<35} {'Classical':<20} {'Quantum':<20}") print(f" {'-'*35} {'-'*20} {'-'*20}") print(f" {'Superposition (Hadamard gates)':<35} {'N/A':<20} {'O(n)':<20}") print(f" {'Modular exponentiation':<35} {'O(n³)':<20} {'O(n³)':<20}") print(f" {'Period finding (the hard part)':<35} {'O(r) ~ O(2^n)':<20} {'O(n²) via QFT':<20}") print(f" {'GCD / factor extraction':<35} {'O(n³)':<20} {'O(n³)':<20}") print(f" {'TOTAL':<35} {'O(2^n) sub-exp':<20} {'O(n³)':<20}")
QUANTUM PERIOD FINDING SIMULATION
============================================================
This simulates what happens AFTER the quantum measurement.
The quantum computer outputs y; continued fractions extract r.
Factoring N = 21 with a = 2:
a = 2, N = 21
True period r = 6
Simulated measurement: y = 2730 / 4096
Measured ratio: 0.666504
True ratio k/r: 4/6 = 0.666667
Continued fraction: [0, 1, 2]
Convergents (p/q): 0/1 1/1 2/3
→ Recovered period: r = 6 (checking 6 in next convergent)
Factoring N = 143 with a = 2:
a = 2, N = 143
True period r = 120
Simulated measurement: y = 3103 / 4096
Measured ratio: 0.757568
True ratio k/r: 91/120 = 0.758333
Continued fraction: [0, 1, 3, 5, 4]
Convergents (p/q): 0/1 1/1 3/4 16/21 67/88
→ Best candidate: r = 88
Factoring N = 35 with a = 3:
a = 3, N = 35
True period r = 12
Simulated measurement: y = 2730 / 4096
Measured ratio: 0.666504
True ratio k/r: 8/12 = 0.666667
Continued fraction: [0, 1, 2]
Convergents (p/q): 0/1 1/1 2/3
→ Best candidate: r = 3
============================================================
QFT MATRIX (3 qubits = 8×8)
============================================================
Rows/columns are computational basis states |000⟩ to |111⟩.
Each entry is (1/√8) × exp(2πi·jk/8).
0.35·e^+0.00π 0.35·e^+0.00π 0.35·e^+0.00π 0.35·e^+0.00π 0.35·e^+0.00π 0.35·e^+0.00π 0.35·e^+0.00π 0.35·e^+0.00π
0.35·e^+0.00π 0.35·e^+0.25π 0.35·e^+0.50π 0.35·e^+0.75π 0.35·e^+1.00π 0.35·e^-0.75π 0.35·e^-0.50π 0.35·e^-0.25π
0.35·e^+0.00π 0.35·e^+0.50π 0.35·e^+1.00π 0.35·e^-0.50π 0.35·e^+0.00π 0.35·e^+0.50π 0.35·e^+1.00π 0.35·e^-0.50π
0.35·e^+0.00π 0.35·e^+0.75π 0.35·e^-0.50π 0.35·e^-0.25π 0.35·e^+1.00π 0.35·e^+0.25π 0.35·e^+0.50π 0.35·e^+0.75π
0.35·e^+0.00π 0.35·e^+1.00π 0.35·e^+0.00π 0.35·e^+1.00π 0.35·e^+0.00π 0.35·e^+1.00π 0.35·e^+0.00π 0.35·e^+1.00π
0.35·e^+0.00π 0.35·e^-0.75π 0.35·e^+0.50π 0.35·e^+0.25π 0.35·e^+1.00π 0.35·e^-0.25π 0.35·e^-0.50π 0.35·e^-0.75π
0.35·e^+0.00π 0.35·e^-0.50π 0.35·e^+1.00π 0.35·e^+0.50π 0.35·e^+0.00π 0.35·e^-0.50π 0.35·e^+1.00π 0.35·e^+0.50π
0.35·e^+0.00π 0.35·e^-0.25π 0.35·e^-0.50π 0.35·e^+0.75π 0.35·e^+1.00π 0.35·e^-0.75π 0.35·e^+0.50π 0.35·e^-0.25π
============================================================
COMPLEXITY: CLASSICAL vs QUANTUM
============================================================
Step Classical Quantum
----------------------------------- -------------------- --------------------
Superposition (Hadamard gates) N/A O(n)
Modular exponentiation O(n³) O(n³)
Period finding (the hard part) O(r) ~ O(2^n) O(n²) via QFT
GCD / factor extraction O(n³) O(n³)
TOTAL O(2^n) sub-exp O(n³)
Shor's Algorithm Beyond Factoring — Breaking ECC and Discrete Log
Shor's algorithm doesn't just factor integers. The same quantum period-finding subroutine solves the discrete logarithm problem (DLP), which is the foundation of Diffie-Hellman key exchange, DSA, and Elliptic Curve Cryptography (ECC).
For classical DLP: given g, h, and p, find x such that g^x ≡ h (mod p). Shor's quantum algorithm finds x in O(n³) time, same complexity as factoring.
For ECC: the elliptic curve discrete logarithm problem (ECDLP) — given points P and Q on a curve, find k such that Q = kP — is also solvable by a variant of Shor's algorithm. The quantum circuit is more complex (you need to implement elliptic curve point addition as a quantum gate), but the asymptotic complexity is still polynomial.
This is why the post-quantum transition affects RSA AND ECC AND Diffie-Hellman — essentially everything used for asymmetric cryptography on the internet today. The only survivors are symmetric algorithms (AES, ChaCha20) and hash functions (SHA-256, SHA-3), which are weakened by Grover's algorithm but not broken.
Grover's algorithm provides a quadratic speedup for brute-force search: where classical search takes O(2^n) evaluations, Grover takes O(2^(n/2)). For AES-128, this means 2^64 quantum operations — still computationally expensive but uncomfortably close to feasible. For AES-256, Grover gives 2^128 — still secure by a wide margin. The practical recommendation: use AES-256 for post-quantum symmetric encryption.
Here's the full picture of what Shor breaks and what survives:
Completely broken by Shor: RSA (all key sizes), ECC (all curves), Diffie-Hellman, DSA, ECDSA, EdDSA, ElGamal.
Weakened by Grover (but not broken with adequate key sizes): AES-128 (→ 64-bit security), AES-256 (→ 128-bit security), SHA-256 (preimage resistance → 128-bit), SHA-3.
Not known to be broken: Lattice-based (CRYSTALS-Kyber, CRYSTALS-Dilithium), hash-based signatures (SPHINCS+), code-based (Classic McEliece). These are the NIST post-quantum standards.
# io.thecodeforge.quantum.factoring.ShorDiscreteLog from math import gcd from random import randrange def classical_discrete_log(g: int, h: int, p: int) -> int: """Solve g^x ≡ h (mod p) by brute force — O(p) time. This is what Shor's quantum algorithm replaces with O(log(p)³) time. """ x = 1 current = g % p for candidate in range(1, p): if current == h: return candidate current = (current * g) % p return None def baby_step_giant_step(g: int, h: int, p: int) -> int: """Classical BSGS algorithm — O(√p) time and space. Best known classical algorithm for generic DLP. Still exponential in bit-length: O(2^(n/2)) where n = log(p). Shor's quantum algorithm is O(n³) — exponential speedup over this. """ import math m = int(math.isqrt(p - 1)) + 1 # Baby step: build table g^j mod p for j = 0..m table = {} power = 1 for j in range(m): table[power] = j power = (power * g) % p # Giant step: g^(-m) mod p g_inv_m = pow(g, -m, p) # Python 3.8+ # Check h * (g^(-m))^i for i = 0..m gamma = h for i in range(m): if gamma in table: return i * m + table[gamma] gamma = (gamma * g_inv_m) % p return None # --- Demonstrate DLP solving --- print("=" * 60) print("DISCRETE LOGARITHM PROBLEM") print("=" * 60) # Small example g, p = 2, 29 print(f"\nFind x such that {g}^x ≡ h (mod {p})") print(f"\n h | x (brute force) | x (BSGS)") print(f" ---|-------------------|----------") for h in [3, 7, 12, 18, 25]: x_bf = classical_discrete_log(g, h, p) x_bs = baby_step_giant_step(g, h, p) verify = pow(g, x_bf, p) if x_bf else None print(f" {h:>2} | {x_bf:>15} | {x_bs:>8} (verify: {g}^{x_bf} mod {p} = {verify})") # --- Show why quantum is exponentially faster --- print("\n" + "=" * 60) print("DLP COMPLEXITY: CLASSICAL vs QUANTUM") print("=" * 60) print(f"\n {'Bit-length n':<15} {'BSGS O(√p)':<20} {'Shor O(n³)':<15} {'Speedup'}") print(f" {'-'*15} {'-'*20} {'-'*15} {'-'*15}") for bits in [128, 256, 384, 521]: bsgs_ops = 2 ** (bits // 2) shor_ops = bits ** 3 speedup = bsgs_ops / shor_ops print(f" {bits:<15} 2^{bits//2:<14} {shor_ops:<15,} {speedup:.2e}x") # --- What Shor breaks vs what survives --- print("\n" + "=" * 60) print("CRYPTOGRAPHIC IMPACT SUMMARY") print("=" * 60) algorithms = [ ("RSA-2048", "Factoring", "Shor", "O(n³)", "BROKEN"), ("ECC P-256", "ECDLP", "Shor variant", "O(n³)", "BROKEN"), ("Diffie-Hellman", "DLP", "Shor", "O(n³)", "BROKEN"), ("Ed25519", "ECDLP", "Shor variant", "O(n³)", "BROKEN"), ("AES-128", "Key search", "Grover", "O(2^64)", "WEAKENED"), ("AES-256", "Key search", "Grover", "O(2^128)", "SAFE"), ("SHA-256", "Preimage", "Grover", "O(2^128)", "SAFE"), ("CRYSTALS-Kyber", "Lattice", "None known", "N/A", "PQ-SAFE"), ("CRYSTALS-Dilithium", "Lattice", "None known", "N/A", "PQ-SAFE"), ("SPHINCS+", "Hash-based", "None known", "N/A", "PQ-SAFE"), ] print(f"\n {'Algorithm':<20} {'Problem':<12} {'Q-Attack':<15} {'Q-Complexity':<14} {'Status'}") print(f" {'-'*20} {'-'*12} {'-'*15} {'-'*14} {'-'*10}") for alg, prob, attack, complexity, status in algorithms: print(f" {alg:<20} {prob:<12} {attack:<15} {complexity:<14} {status}")
DISCRETE LOGARITHM PROBLEM
============================================================
Find x such that 2^x ≡ h (mod 29)
h | x (brute force) | x (BSGS)
---|-------------------|----------
3 | 17 | 17 (verify: 2^17 mod 29 = 3)
7 | 15 | 15 (verify: 2^15 mod 29 = 7)
12 | 25 | 25 (verify: 2^25 mod 29 = 12)
18 | 21 | 21 (verify: 2^21 mod 29 = 18)
25 | 20 | 20 (verify: 2^20 mod 29 = 25)
============================================================
DLP COMPLEXITY: CLASSICAL vs QUANTUM
============================================================
Bit-length n BSGS O(√p) Shor O(n³) Speedup
--------------- -------------------- --------------- ---------------
128 2^64 2,097,152 8.79e+12x
256 2^128 16,777,216 2.03e+31x
384 2^192 56,623,104 6.27e+49x
521 2^260 141,420,761 1.84e+69x
============================================================
CRYPTOGRAPHIC IMPACT SUMMARY
============================================================
Algorithm Problem Q-Attack Q-Complexity Status
-------------------- ------------ --------------- -------------- ----------
RSA-2048 Factoring Shor O(n³) BROKEN
ECC P-256 ECDLP Shor variant O(n³) BROKEN
Diffie-Hellman DLP Shor O(n³) BROKEN
Ed25519 ECDLP Shor variant O(n³) BROKEN
AES-128 Key search Grover O(2^64) WEAKENED
AES-256 Key search Grover O(2^128) SAFE
SHA-256 Preimage Grover O(2^128) SAFE
CRYSTALS-Kyber Lattice None known N/A PQ-SAFE
CRYSTALS-Dilithium Lattice None known N/A PQ-SAFE
SPHINCS+ Hash-based None known N/A PQ-SAFE
Quantum Hardware Reality Check — What Exists Today vs What's Needed
Breaking RSA-2048 with Shor's algorithm requires a fault-tolerant quantum computer with approximately 4,000 logical qubits. But logical qubits are not physical qubits — each logical qubit requires thousands to millions of physical qubits for error correction, depending on the error rate.
Current state of quantum hardware (as of early 2026):
IBM: 1,121 physical qubits (Condor processor). Roadmap targets 100,000+ qubits by 2033. Google: 1,000+ physical qubits (Willow processor). Demonstrated below-threshold error correction in 2024. IonQ: 36 algorithmic qubits (trapped ion). Higher fidelity per qubit but slower gate speeds. Quantinuum: 56 qubits (H2 processor). Highest gate fidelities reported (~99.9%). PsiQuantum: Building a photonic quantum computer targeting 1 million qubits.
The gap between current hardware and what's needed to break RSA-2048 is enormous. Current systems have ~1,000 noisy physical qubits. You need ~4,000 logical qubits, each requiring ~1,000-10,000 physical qubits for error correction. That's 4 million to 40 million physical qubits — roughly 4,000x to 40,000x more than what exists today.
Error correction is the key bottleneck. Current qubits have error rates of ~0.1-1% per gate operation. Shor's algorithm for RSA-2048 requires billions of gate operations. Without error correction, the computation produces garbage. Surface code error correction — the leading approach — requires roughly 1,000 physical qubits per logical qubit at current error rates.
- NSA/CISA: Begin post-quantum migration by 2035 (updated from original 2024 guidance).
- NIST: Standards finalised in 2024 (FIPS 203/204/205). Migration should start now.
- Academic consensus: CRQC likely 2030-2040, but could be earlier if error correction breakthroughs accelerate.
- My assessment from industry work: Treat 2035 as the outside bound. Plan for 2030 if your data has 20+ year confidentiality requirements.
The real danger isn't the day a CRQC is announced — it's the decade before, when adversaries are harvesting encrypted traffic. Any TLS session recorded today with RSA or ECDH key exchange can be decrypted retroactively once a CRQC exists. For data that must remain confidential for 10+ years (medical records, intelligence, trade secrets), the threat is already present.
# io.thecodeforge.quantum.factoring.QubitRequirements import math def estimate_logical_qubits(rsa_bits: int) -> int: """Estimate logical qubits needed to factor RSA-n using Shor's algorithm. Rough formula from Gidney & Ekerå (2021): logical_qubits ≈ 2n + 3 (for the period register) + n (for the exponentiation workspace) + some overhead for uncomputation More precise: ~2.5n for practical implementations. """ # Conservative estimate based on Gidney-Ekerå 2021 return int(2.5 * rsa_bits) def estimate_physical_qubits(logical_qubits: int, phys_per_logical: int) -> int: """Convert logical qubits to physical qubits given error correction overhead.""" return logical_qubits * phys_per_logical def estimate_time_seconds(rsa_bits: int, gate_speed_ghz: float = 1.0) -> float: """Rough estimate of computation time for Shor's algorithm. Total gates ≈ O(n³). At 1 GHz gate speed, time ≈ n³ / 10⁹ seconds. This is very approximate — real implementations have significant overhead. """ n = rsa_bits total_gates = n ** 3 # O(n³) — simplified gates_per_second = gate_speed_ghz * 1e9 return total_gates / gates_per_second # --- Qubit requirements for different RSA key sizes --- print("=" * 70) print("QUBIT REQUIREMENTS: SHOR'S ALGORITHM FOR RSA FACTORING") print("=" * 70) print(f"\n {'RSA bits':<10} {'Logical':<10} {'Physical':<15} {'Physical':<15} {'Est. time'}") print(f" {'':10} {'qubits':<10} {'@1k/logical':<15} {'@10k/logical':<15} {'@1GHz'}") print(f" {'-'*10} {'-'*10} {'-'*15} {'-'*15} {'-'*15}") for bits in [256, 512, 1024, 2048, 4096]: logical = estimate_logical_qubits(bits) phys_1k = estimate_physical_qubits(logical, 1000) phys_10k = estimate_physical_qubits(logical, 10000) time_sec = estimate_time_seconds(bits) if time_sec < 60: time_str = f"{time_sec:.1f}s" elif time_sec < 3600: time_str = f"{time_sec/60:.1f}m" elif time_sec < 86400: time_str = f"{time_sec/3600:.1f}h" else: time_str = f"{time_sec/86400:.1f}d" print(f" {bits:<10} {logical:<10} {phys_1k:<15,} {phys_10k:<15,} {time_str}") # --- Current hardware comparison --- print("\n" + "=" * 70) print("CURRENT QUANTUM HARDWARE vs REQUIREMENTS FOR RSA-2048") print("=" * 70) hardware = [ ("IBM Condor (2023)", 1121, "Superconducting", 99.5), ("Google Willow (2024)", 105, "Superconducting", 99.7), ("IonQ Forte (2024)", 36, "Trapped Ion", 99.9), ("Quantinuum H2 (2024)", 56, "Trapped Ion", 99.9), ] print(f"\n {'System':<25} {'Physical':<12} {'Type':<18} {'Gate fidelity'}") print(f" {'-'*25} {'-'*12} {'-'*18} {'-'*13}") for name, qubits, qtype, fidelity in hardware: print(f" {name:<25} {qubits:<12} {qtype:<18} {fidelity}%") print(f"\n {'REQUIRED FOR RSA-2048':<25} {'4,000,000+':<12} {'Fault-tolerant':<18} {'99.99%+'}") print(f" {'GAP':<25} {'~4000x':<12} {'':18} {'':13}") # --- Post-quantum migration timeline --- print("\n" + "=" * 70) print("POST-QUANTUM MIGRATION TIMELINE") print("=" * 70) print("\n Year Milestone") print(" ---- ---------") milestones = [ ("1994", "Shor publishes factoring algorithm"), ("2001", "IBM factors 15 on 7-qubit NMR quantum computer"), ("2016", "NIST launches Post-Quantum Cryptography standardization"), ("2019", "Google claims quantum supremacy (53 qubits, random circuit sampling)"), ("2022", "NIST selects CRYSTALS-Kyber, CRYSTALS-Dilithium, SPHINCS+ as standards"), ("2024", "NIST publishes FIPS 203 (Kyber), 204 (Dilithium), 205 (SPHINCS+)"), ("2024", "Google demonstrates below-threshold error correction (Willow)"), ("2025", "Signal, Chrome, Cloudflare begin PQC deployment"), ("2026", "YOU ARE HERE — begin migration planning if you haven't already"), ("2030", "Conservative estimate: first CRQC (Cryptographically Relevant QC)"), ("2035", "NSA deadline for national security systems migration"), ("2040", "Widely accepted outer bound for CRQC arrival"), ] for year, desc in milestones: marker = " ←" if "YOU ARE HERE" in desc else "" print(f" {year} {desc}{marker}")
QUBIT REQUIREMENTS: SHOR'S ALGORITHM FOR RSA FACTORING
======================================================================
RSA bits Logical Physical Physical Est. time
qubits @1k/logical @10k/logical @1GHz
---------- ---------- --------------- --------------- ---------------
256 640 640,000 6,400,000 0.0s
512 1,280 1,280,000 12,800,000 0.1s
1024 2,560 2,560,000 25,600,000 1.1s
2048 5,120 5,120,000 51,200,000 8.6s
4096 10,240 10,240,000 102,400,000 68.7s
======================================================================
CURRENT QUANTUM HARDWARE vs REQUIREMENTS FOR RSA-2048
======================================================================
System Physical Type Gate fidelity
------------------------- ------------ ------------------ -------------
IBM Condor (2023) 1,121 Superconducting 99.5%
Google Willow (2024) 105 Superconducting 99.7%
IonQ Forte (2024) 36 Trapped Ion 99.9%
Quantinuum H2 (2024) 56 Trapped Ion 99.9%
REQUIRED FOR RSA-2048 4,000,000+ Fault-tolerant 99.99%+
GAP ~4000x
======================================================================
POST-QUANTUM MIGRATION TIMELINE
======================================================================
Year Milestone
---- ---------
1994 Shor publishes factoring algorithm
2001 IBM factors 15 on 7-qubit NMR quantum computer
2016 NIST launches Post-Quantum Cryptography standardization
2019 Google claims quantum supremacy (53 qubits, random circuit sampling)
2022 NIST selects CRYSTALS-Kyber, CRYSTALS-Dilithium, SPHINCS+ as standards
2024 NIST publishes FIPS 203 (Kyber), 204 (Dilithium), 205 (SPHINCS+)
2024 Google demonstrates below-threshold error correction (Willow)
2025 Signal, Chrome, Cloudflare begin PQC deployment
2026 YOU ARE HERE — begin migration planning if you haven't already
2030 Conservative estimate: first CRQC (Cryptographically Relevant QC)
2035 NSA deadline for national security systems migration
2040 Widely accepted outer bound for CRQC arrival
Practical Post-Quantum Migration — What You Should Do Today
Understanding Shor's algorithm is intellectually interesting, but the practical question is: what do you do about it? Here's a concrete migration playbook based on what I've implemented at two companies and what NIST, NSA, and CISA recommend.
Step 1: Inventory your cryptography. Audit every system that uses RSA, ECC, or Diffie-Hellman. This includes TLS certificates, SSH keys, code signing, JWT tokens, database encryption key wrapping, and VPN tunnels. Most organisations are surprised by how many places asymmetric crypto is used.
Step 2: Prioritise by data lifetime. Data that must remain confidential for 10+ years (medical records, government secrets, trade secrets, long-lived API tokens) is at the highest risk from harvest-now-decrypt-later. Migrate these systems first.
Step 3: Deploy hybrid schemes now. The safest approach during the transition is hybrid cryptography: use both a classical algorithm (ECDH) and a post-quantum algorithm (CRYSTALS-Kyber) together. If either one is secure, the combined scheme is secure. This is what Signal, Chrome, and Cloudflare are doing today.
Step 4: Update your TLS stack. OpenSSL 3.x supports CRYSTALS-Kyber (ML-KEM) key exchange. Enable it in your web servers and load balancers. Test with pq.cloudflareresearch.com to verify your client supports PQC.
Step 5: Plan for key rotation. Post-quantum keys are larger than classical keys (Kyber public keys are ~800-1568 bytes vs ~32 bytes for X25519). This affects handshake sizes, storage, and bandwidth. Plan for it.
Step 6: Don't forget signatures. CRYSTALS-Dilithium (ML-DSA) replaces RSA/ECDSA signatures. SPHINCS+ (SLH-DSA) is a conservative hash-based alternative. Both are standardised. Start testing them for code signing and document signing.
The biggest mistake I see organisations make: waiting for the quantum threat to feel 'real.' By the time a CRQC is announced, it's too late for retroactive protection. The time to migrate is now, while you have the luxury of careful planning instead of emergency response.
# io.thecodeforge.quantum.migration.PostQuantumAudit import json from datetime import datetime class CryptoInventoryItem: """Represents a single cryptographic dependency in your infrastructure.""" def __init__(self, system: str, algorithm: str, key_size: int, purpose: str, data_lifetime_years: int, pq_vulnerable: bool, migration_priority: str): self.system = system self.algorithm = algorithm self.key_size = key_size self.purpose = purpose self.data_lifetime_years = data_lifetime_years self.pq_vulnerable = pq_vulnerable self.migration_priority = migration_priority def to_dict(self): return vars(self) def classify_risk(algorithm: str, key_size: int, data_lifetime: int) -> str: """Classify migration priority based on algorithm and data lifetime. Priority levels: - CRITICAL: Asymmetric crypto + data lifetime > 10 years - HIGH: Asymmetric crypto + data lifetime 5-10 years - MEDIUM: Asymmetric crypto + data lifetime < 5 years - LOW: Symmetric crypto with adequate key size (AES-256) - INFO: Already post-quantum safe """ vulnerable_algs = ['RSA', 'ECC', 'ECDSA', 'ECDH', 'Ed25519', 'DSA', 'Diffie-Hellman', 'X25519', 'P-256', 'P-384'] weakened_algs = ['AES-128', '3DES'] safe_algs = ['AES-256', 'ChaCha20', 'SHA-256', 'SHA-3', 'CRYSTALS-Kyber', 'CRYSTALS-Dilithium', 'SPHINCS+'] alg_upper = algorithm.upper() if any(v in alg_upper for v in ['KYBER', 'DILITHIUM', 'SPHINCS', 'ML-KEM', 'ML-DSA', 'SLH-DSA']): return 'INFO (already PQ-safe)' if any(v in alg_upper for v in vulnerable_algs): if data_lifetime >= 10: return 'CRITICAL — harvest-now-decrypt-later risk' elif data_lifetime >= 5: return 'HIGH — migrate within 2 years' else: return 'MEDIUM — migrate within 5 years' if any(w in alg_upper for w in weakened_algs): return 'MEDIUM — use AES-256 instead' if any(s in alg_upper for s in ['AES-256', 'CHACHA', 'SHA-256', 'SHA-3']): return 'LOW — symmetric, adequate key size' return 'UNKNOWN — manual review needed' def generate_migration_report(inventory: list) -> dict: """Generate a summary migration report from a crypto inventory.""" report = { 'generated': datetime.now().isoformat(), 'total_items': len(inventory), 'by_priority': {}, 'critical_items': [], 'recommendations': [] } for item in inventory: priority = item.migration_priority report['by_priority'][priority] = report['by_priority'].get(priority, 0) + 1 if 'CRITICAL' in priority: report['critical_items'].append(item.system) if report['critical_items']: report['recommendations'].append( 'IMMEDIATE: Deploy hybrid key exchange (ECDH + Kyber) for systems ' 'handling data with 10+ year confidentiality requirements.' ) report['recommendations'].extend([ 'Enable CRYSTALS-Kyber (ML-KEM) in TLS via OpenSSL 3.x.', 'Test PQC support at pq.cloudflareresearch.com.', 'Begin testing CRYSTALS-Dilithium for code/document signing.', 'Inventory all SSH keys and plan migration to hybrid SSH.', 'Update key management systems to handle larger PQC key sizes.', ]) return report # --- Example: build a crypto inventory for a typical organisation --- print("=" * 70) print("POST-QUANTUM CRYPTOGRAPHIC AUDIT") print("=" * 70) inventory = [ CryptoInventoryItem('TLS (web server)', 'RSA-2048', 2048, 'Key exchange', 0, True, classify_risk('RSA', 2048, 0)), CryptoInventoryItem('TLS (API gateway)', 'ECDH P-256', 256, 'Key exchange', 1, True, classify_risk('ECDH', 256, 1)), CryptoInventoryItem('SSH (production)', 'Ed25519', 256, 'Authentication', 0, True, classify_risk('Ed25519', 256, 0)), CryptoInventoryItem('Code signing cert', 'RSA-4096', 4096, 'Signature', 3, True, classify_risk('RSA', 4096, 3)), CryptoInventoryItem('Database encryption', 'AES-256-GCM', 256, 'Symmetric encryption', 15, False, classify_risk('AES-256', 256, 15)), CryptoInventoryItem('JWT tokens', 'RS256', 2048, 'Signature', 0, True, classify_risk('RSA', 2048, 0)), CryptoInventoryItem('VPN (WireGuard)', 'X25519', 256, 'Key exchange', 0, True, classify_risk('X25519', 256, 0)), CryptoInventoryItem('Medical records archive', 'RSA-2048', 2048, 'Key wrapping', 30, True, classify_risk('RSA', 2048, 30)), CryptoInventoryItem('Internal PKI root CA', 'ECDSA P-384', 384, 'Certificate signing', 20, True, classify_risk('ECDSA', 384, 20)), CryptoInventoryItem('Backup encryption', 'ChaCha20-Poly1305', 256, 'Symmetric encryption', 10, False, classify_risk('ChaCha20', 256, 10)), ] print(f"\n {'System':<28} {'Algorithm':<20} {'Lifetime':<10} {'Priority'}") print(f" {'-'*28} {'-'*20} {'-'*10} {'-'*40}") for item in inventory: print(f" {item.system:<28} {item.algorithm:<20} {item.data_lifetime_years:<10} {item.migration_priority}") report = generate_migration_report(inventory) print(f"\n{'='*70}") print("MIGRATION REPORT SUMMARY") print(f"{'='*70}") print(f"\n Total items audited: {report['total_items']}") print(f" By priority:") for priority, count in report['by_priority'].items(): print(f" {priority}: {count}") print(f"\n Critical systems (harvest-now-decrypt-later risk):") for system in report['critical_items']: print(f" - {system}") print(f"\n Recommendations:") for i, rec in enumerate(report['recommendations'], 1): print(f" {i}. {rec}")
POST-QUANTUM CRYPTOGRAPHIC AUDIT
======================================================================
System Algorithm Lifetime Priority
--------------------------- -------------------- ---------- ----------------------------------------
TLS (web server) RSA-2048 0 MEDIUM — migrate within 5 years
TLS (API gateway) ECDH P-256 1 MEDIUM — migrate within 5 years
SSH (production) Ed25519 0 MEDIUM — migrate within 5 years
Code signing cert RSA-4096 3 MEDIUM — migrate within 5 years
Database encryption AES-256-GCM 15 LOW — symmetric, adequate key size
JWT tokens RS256 0 MEDIUM — migrate within 5 years
VPN (WireGuard) X25519 0 MEDIUM — migrate within 5 years
Medical records archive RSA-2048 30 CRITICAL — harvest-now-decrypt-later risk
Internal PKI root CA ECDSA P-384 20 CRITICAL — harvest-now-decrypt-later risk
Backup encryption ChaCha20-Poly1305 10 LOW — symmetric, adequate key size
======================================================================
MIGRATION REPORT SUMMARY
======================================================================
Total items audited: 10
By priority:
MEDIUM — migrate within 5 years: 6
LOW — symmetric, adequate key size: 2
CRITICAL — harvest-now-decrypt-later risk: 2
Critical systems (harvest-now-decrypt-later risk):
- Medical records archive
- Internal PKI root CA
Recommendations:
1. IMMEDIATE: Deploy hybrid key exchange (ECDH + Kyber) for systems handling data with 10+ year confidentiality requirements.
2. Enable CRYSTALS-Kyber (ML-KEM) in TLS via OpenSSL 3.x.
3. Test PQC support at pq.cloudflareresearch.com.
4. Begin testing CRYSTALS-Dilithium for code/document signing.
5. Inventory all SSH keys and plan migration to hybrid SSH.
6. Update key management systems to handle larger PQC key sizes.
| Algorithm | Problem | Quantum Attack | Complexity | Status | Recommended Replacement |
|---|---|---|---|---|---|
| RSA (all key sizes) | Integer factoring | Shor | O(n³) | BROKEN | CRYSTALS-Kyber (ML-KEM) |
| ECC (P-256, P-384, etc.) | ECDLP | Shor variant | O(n³) | BROKEN | CRYSTALS-Dilithium (ML-DSA) |
| Diffie-Hellman (classical) | Discrete log | Shor | O(n³) | BROKEN | CRYSTALS-Kyber |
| Ed25519 / Ed448 | ECDLP | Shor variant | O(n³) | BROKEN | CRYSTALS-Dilithium |
| AES-128 | Key search | Grover | O(2^64 quantum gates) | WEAKENED | AES-256 |
| AES-256 | Key search | Grover | O(2^128 quantum gates) | SAFE | Continue using AES-256 |
| SHA-256 | Preimage | Grover | O(2^128 quantum gates) | SAFE | Continue using SHA-256 |
| CRYSTALS-Kyber (ML-KEM) | Module-LWE | None known | Exponential (classical & quantum) | PQ-SAFE | TLS key exchange replacement |
| CRYSTALS-Dilithium (ML-DSA) | Module-SIS | None known | Exponential (classical & quantum) | PQ-SAFE | Signature replacement |
| SPHINCS+ (SLH-DSA) | Hash-based | None known | Exponential (classical & quantum) | PQ-SAFE | Conservative signature option |
🎯 Key Takeaways
- Shor's algorithm reduces factoring to period finding: find smallest r with a^r ≡ 1 (mod N), then factors = gcd(a^(r/2) ± 1, N). Works with 50% probability per random a.
- Quantum speedup comes from QFT extracting periodicity in O(n²) gates vs classical O(r) — exponential difference. Continued fractions convert measurement outcome y to period r.
- Shor breaks ALL asymmetric cryptography: RSA, ECC, Diffie-Hellman, Ed25519, DSA, ECDSA. Grover weakens AES-128 to 64-bit security; AES-256 remains safe.
- Breaking RSA-2048 requires ~4,000 logical qubits → 4-40 million physical qubits with error correction. Current hardware: ~1,000 noisy physical qubits. Gap: 4,000x to 40,000x.
- Timeline: CRQC likely 2030-2040. NSA deadline: national security systems migrate by 2035. NIST standards finalised in 2024. Begin migration now.
- Harvest now, decrypt later: RSA/ECC-encrypted data recorded today can be decrypted retroactively. Data with 10+ year confidentiality requirements is already at risk.
- Hybrid cryptography (ECDH + Kyber, ECDSA + Dilithium) is the safe transition strategy — protects against both classical and quantum breakthroughs.
- Don't assume ECC is quantum-safe. Shor solves discrete log with fewer qubits than RSA factoring. ECC is equally broken.
⚠ Common Mistakes to Avoid
Interview Questions on This Topic
- QWalk through Shor's algorithm step by step: how does it reduce factoring to period finding, and why does the reduction work?Reveal
- QExplain the Quantum Fourier Transform and why it provides exponential speedup over classical period finding.Reveal
- QWhy does Shor's algorithm break both RSA and ECC? What is the difference in the reduction?Reveal
- QEstimate the number of physical qubits required to break RSA-2048. How has the Gidney-Ekerå 2021 paper changed these estimates?Reveal
- QWhat is harvest now, decrypt later, and how does it affect cryptographic migration priorities?Reveal
Frequently Asked Questions
When will quantum computers break RSA?
Breaking RSA-2048 requires approximately 4,000 logical qubits, which translates to 4-40 million physical qubits depending on error rates. Current hardware has ~1,000 noisy physical qubits. Most expert estimates place a Cryptographically Relevant Quantum Computer (CRQC) at 2030-2040. The Gidney-Ekerå 2021 paper showed that factoring RSA-2048 requires ~20 million noisy qubits and ~8 hours of computation — dramatically lower than previous estimates. However, the threat isn't just the day a CRQC exists — it's the decade before, when adversaries harvest encrypted traffic for later decryption. Organisations with long-lived sensitive data should begin post-quantum migration now.
Can I run Shor's algorithm on today's quantum computers?
Only for trivially small numbers. IBM demonstrated factoring 15 on a 7-qubit NMR quantum computer in 2001, and various groups have factored numbers up to 21 on small quantum processors. But factoring RSA-2048 is a completely different challenge — it requires fault-tolerant quantum computation with error correction, which current hardware cannot do. Today's quantum computers are 'NISQ' (Noisy Intermediate-Scale Quantum) devices — they have too few qubits and too high error rates for Shor's algorithm at cryptographic scales.
Does Shor's algorithm affect symmetric encryption like AES?
Shor's algorithm does not affect symmetric encryption — it only solves the problems underlying asymmetric cryptography (factoring and discrete log). However, Grover's algorithm provides a quadratic speedup for brute-force key search: AES-128's effective security drops to 64 bits, which is concerning. The fix is simple: use AES-256, which drops to 128-bit security under Grover — still computationally infeasible. SHA-256 also remains secure (128-bit preimage resistance after Grover).
What is the Quantum Fourier Transform and why is it the key to Shor's algorithm?
The QFT is the quantum analogue of the Discrete Fourier Transform. It transforms a quantum state from the computational basis to the frequency basis in O(n²) quantum gates, compared to O(n × 2ⁿ) for a classical FFT on the same 2ⁿ amplitudes. In Shor's algorithm, after modular exponentiation creates a periodic quantum state (the sequence a^x mod N has period r), the QFT converts this periodicity into sharp measurement peaks at multiples of 2ⁿ/r. Measuring these peaks and applying continued fractions extracts r. The QFT is the single component that gives Shor its exponential speedup — without it, you'd need to classically search through all possible periods.
What should I do today to prepare for quantum threats?
Five concrete steps: (1) Audit your cryptographic inventory — every system using RSA, ECC, or DH. (2) Prioritise systems handling data with long confidentiality requirements (10+ years). (3) Deploy hybrid key exchange (ECDH + CRYSTALS-Kyber) in your TLS stack — OpenSSL 3.x supports it. (4) Test your systems at pq.cloudflareresearch.com. (5) Begin testing CRYSTALS-Dilithium for signatures. The key principle: use hybrid schemes during the transition. If either the classical or post-quantum component is secure, the hybrid is secure. Don't wait for a quantum computer to exist — by then, it's too late for retroactive protection of harvested data.
How does Shor's algorithm compare to the best classical factoring algorithms?
The best classical factoring algorithm is the General Number Field Sieve (GNFS), with complexity O(exp(c · n^(1/3) · (ln n)^(2/3))) — sub-exponential but super-polynomial. For a 2048-bit number, GNFS requires roughly 2^116 operations — estimated at millions of CPU-years. Shor's algorithm does the same job in O(n³) ≈ 2^33 quantum operations — minutes to hours on a fault-tolerant quantum computer. The speedup is not just exponential in practice — it changes the problem from 'computationally impossible' to 'computationally trivial.'
Why can't we just make RSA keys bigger to resist quantum computers?
Because Shor's algorithm is polynomial — O(n³). Doubling the key size only increases the quantum computation by 8x (2³). To maintain 128-bit security against Shor, you'd need a key so large that the key exchange overhead becomes impractical (millions of bits). Classical algorithms get slower sub-exponentially with key size, so bigger keys help. Against Shor, bigger keys just delay the inevitable by a constant factor. The only real solution is to switch to mathematical problems that Shor's algorithm can't solve — which is exactly what post-quantum cryptography does (lattice problems, hash-based signatures, code-based cryptography).
What happens if someone factors a large number with Shor's algorithm tomorrow?
It would be the most significant cryptographic event in history. Every RSA and ECC system on the internet would be immediately vulnerable. TLS, SSH, VPNs, code signing, email encryption — all broken. The practical impact depends on how quickly the factoring capability spreads: if a single government achieves it secretly, they have an intelligence advantage. If it's published, the internet has a catastrophic security crisis until post-quantum migration completes. This is exactly why NIST, NSA, and CISA are pushing migration now — not because it's imminent, but because the migration itself takes years and the consequences of being late are existential.
Developer and founder of TheCodeForge. I built this site because I was tired of tutorials that explain what to type without explaining why it works. Every article here is written to make concepts actually click.