A working BB84 quantum key distribution prototype built on an optical bench, plus the signal processing that turns its oscilloscope traces back into a shared secret key.
Published as Constructing a Photonic Implementation of Quantum Key Distribution (arXiv:2509.04389), with Alec L. Riso, Connor Whiting, and Katherine Jimenez.
QKD gets its security from physics rather than from a hard math problem. An eavesdropper who measures a photon in the wrong basis disturbs it, and that disturbance shows up as error in the sifted key. This repository implements that end to end at benchtop scale.
Alice and Bob each hold a polarizer on a servo. For every bit, Alice picks a basis (rectilinear or diagonal) and a value, and rotates her polarizer to the matching angle. Bob independently picks his own basis and rotates his. A near-infrared laser sends the photon through both polarizers onto a pair of photodiodes read by an oscilloscope. Where the bases agree, Bob recovers Alice's bit. When they disagree the result is noise, and that bit gets discarded during sifting.
The demonstration transmits the word cat as 24 bits over a 5m fiber channel, at a 95% photon detection rate.
| File | What it is |
|---|---|
qkd_working.ino |
Arduino firmware driving both polarizer servos. Holds Alice's bit string and basis choices, Bob's independent basis choices, and the six calibrated servo angles for the rectilinear and diagonal states. |
processing.py |
Reads an oscilloscope CSV, strips the 21-row instrument header, and differences the two photodiode channels so the polarization signal separates from common-mode drift. |
processing.ipynb |
The full analysis: thresholding the differenced signal into bits, sifting against the basis records, and computing quantum bit error rate. |
cat_data*.csv, qkd_with_1s.csv |
Raw two-channel oscilloscope captures across several runs, including a longer-integration and a robustness run. |
qkd-notes.docx |
Bench notes: alignment procedure, servo calibration, and observed failure modes. |
Two details mattered more than expected. The photodiode channels drift together under ambient light and laser power fluctuation, so the differenced signal CH1 - CH2 is the actual measurement rather than either channel alone. And the servos need a settle delay proportional to their angular travel; sampling before the polarizer stops moving smears the bit boundary and inflates QBER without any eavesdropper present.
QBER analysis runs over 10K+ oscilloscope samples per run.
pip install pandas numpy matplotlib
python processing.pyPoint processing.py at whichever capture you want. cat_data_times.csv is the primary run.
To rerun the physical experiment you need two servo-mounted linear polarizers, a near-infrared laser, two photodiodes, a two-channel oscilloscope, and a 5m fiber. Flash qkd_working.ino, calibrate the six servo angles against maximum extinction, then capture both channels while the firmware steps through the bit sequence.