Unbreakable Secrets: Simulating Quantum Key Distribution (BB84)
Project Overview:
How do you share a secret password with someone when you can't trust that nobody's listening in? Classical encryption relies on math problems being hard to solve, but a powerful enough computer could eventually crack them. Quantum key distribution (QKD) takes a completely different approach: instead of hiding a key with math, it uses the laws of physics themselves to guarantee that any eavesdropper gets caught.
In this project, you'll write a Python simulation of BB84, the first and most famous QKD protocol, invented in 1984 and still the foundation of real quantum cryptography systems used today. You'll simulate two people, Alice and Bob, generating a shared secret key using quantum bits, and you'll simulate an eavesdropper, Eve, trying to spy on them, then watch how her presence gets detected without her ever being directly observed.
This builds directly on the idea from polarized filters: measuring a quantum state disturbs it. BB84 turns that disturbance into a built in alarm system.
Materials Required:
A computer with internet access
A free Google account (to use Google Colab), no installation needed
Basic comfort reading Python (loops, lists, if statements)
Background: How BB84 Actually Works (read before coding)
Alice wants to send Bob a secret key. She generates a random string of bits (0s and 1s), this will become the key if all goes well.
For each bit, Alice also randomly picks one of two bases (think of these as two different filter angles, like in the polarization project) to encode it in, a straight basis or a diagonal basis.
Bob doesn't know which basis Alice used for each bit, so he guesses randomly, choosing his own basis for each bit as he measures it.
When Bob's guessed basis matches Alice's original basis, he reads the bit correctly. When it doesn't match, he gets a random, meaningless result, exactly like a photon reset by the wrong angle filter.
Afterward, Alice and Bob publicly compare which bases they each used per bit, but never the bit values themselves. They keep only the bits where their bases happened to match, and throw away the rest. What's left is the shared secret key.
If an eavesdropper, Eve, intercepts and measures the bits in between, she has to guess a basis too, and her wrong guesses disturb the original bits, meaning Alice and Bob's final matching basis bits won't agree as often as they should. By comparing a small sample of their key out loud, they can detect this mismatch rate and know if someone was listening.
Instructions:
Set up your notebook.
Go to Google Colab at colab.research.google.com and create a new notebook.
Generate Alice's random bits and bases.
Type the following into a code cell and run it:
import random
n = 20
alice_bits = [random.randint(0, 1) for _ in range(n)]
alice_bases = [random.choice(['+', 'x']) for _ in range(n)]
print("Alice's bits: ", alice_bits)
print("Alice's bases:", alice_bases)
Simulate Bob measuring with his own random bases.
Add this to a new cell:
bob_bases = [random.choice(['+', 'x']) for _ in range(n)]
bob_results = []
for i in range(n):
if bob_bases[i] == alice_bases[i]:
bob_results.append(alice_bits[i])
else:
bob_results.append(random.randint(0, 1))
print("Bob's bases: ", bob_bases)
print("Bob's results:", bob_results)
Keep only the bits where bases matched, this is called the sifted key.
Add this next:
alice_key = []
bob_key = []
for i in range(n):
if alice_bases[i] == bob_bases[i]:
alice_key.append(alice_bits[i])
bob_key.append(bob_results[i])
print("Alice's sifted key:", alice_key)
print("Bob's sifted key: ", bob_key)
print("Keys match:", alice_key == bob_key)
Run this a few times. With no eavesdropper, alice_key and bob_key should always match exactly.
Add an eavesdropper, Eve, and watch the key break.
Add this function:
def run_bb84_with_eve(n, eve_present):
alice_bits = [random.randint(0, 1) for _ in range(n)]
alice_bases = [random.choice(['+', 'x']) for _ in range(n)]
transmitted_bits = alice_bits.copy()
if eve_present:
eve_bases = [random.choice(['+', 'x']) for _ in range(n)]
for i in range(n):
if eve_bases[i] == alice_bases[i]:
pass
else:
transmitted_bits[i] = random.randint(0, 1)
bob_bases = [random.choice(['+', 'x']) for _ in range(n)]
bob_results = []
for i in range(n):
if bob_bases[i] == alice_bases[i]:
bob_results.append(transmitted_bits[i])
else:
bob_results.append(random.randint(0, 1))
alice_key, bob_key = [], []
for i in range(n):
if alice_bases[i] == bob_bases[i]:
alice_key.append(alice_bits[i])
bob_key.append(bob_results[i])
mismatches = sum(a != b for a, b in zip(alice_key, bob_key))
error_rate = mismatches / len(alice_key) if alice_key else 0
return error_rate
print("Error rate with no Eve: ", run_bb84_with_eve(200, eve_present=False))
print("Error rate with Eve spying:", run_bb84_with_eve(200, eve_present=True))
Compare the results.
Run step 5 a few times. Without Eve, the error rate should sit right around 0 percent. With Eve present, it jumps to roughly 25 percent, because whenever Eve guesses the wrong basis (about half the time) and Bob still happens to match Alice's original basis, there is a 50 percent chance the disturbed bit reads wrong. That 25 percent error rate is Eve's fingerprint, even though nobody ever saw her.
Stretch step: turn the error rate into a decision.
Add a simple check so Alice and Bob discard the key if it looks compromised:
error_rate = run_bb84_with_eve(200, eve_present=True)
threshold = 0.08
if error_rate > threshold:
print(f"Eavesdropper detected! Error rate {error_rate:.2%} - key discarded.")
else:
print(f"Key looks safe. Error rate {error_rate:.2%} - key accepted.")
Congratulations, you just simulated a real quantum cryptography protocol that's actually deployed in fiber optic QKD networks today, including experimental banking and government communication links.
Fun Fact:
BB84 isn't just theoretical. China's Micius satellite has used a version of quantum key distribution to send secure keys between ground stations thousands of kilometers apart, and several countries have since built experimental quantum secure communication networks using this exact eavesdropper detection principle.