Skip to content

Commit 69ef334

Browse files
Added Implementation for E91 QKD Protocol
Covers the implementation of E91 QKD, for a predefined num_bits = 2000.
1 parent 7944ed3 commit 69ef334

1 file changed

Lines changed: 167 additions & 0 deletions

File tree

quantum/e91_qkd.py

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
import math
2+
import random
3+
import numpy as np
4+
import qiskit
5+
from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
6+
from qiskit_aer import AerSimulator
7+
8+
9+
def e91_protocol(n_bits: int = 2000) -> dict:
10+
"""
11+
Simulates the E91 QKD protocol for a specified number of bits.
12+
13+
Args:
14+
n_bits: The total number of entangled pairs to be generated and
15+
measured. This determines the potential length of the raw key.
16+
17+
Returns:
18+
A dictionary containing the simulation results:
19+
- "alice_key": Alice's final, sifted secret key.
20+
- "bob_key": Bob's final, sifted secret key.
21+
- "s_value": The calculated CHSH inequality parameter 'S'.
22+
- "eavesdropper_detected": A boolean indicating if |S| <= 2.
23+
- "key_match": A boolean indicating if Alice's and Bob's keys match.
24+
- "key_length": The final length of the sifted keys.
25+
26+
>>> e91_protocol(100) # doctest: +SKIP
27+
{'alice_key': '1011110', 'bob_key': '1011110', 's_value': 2.73, ...}
28+
29+
>>> e91_protocol(-10)
30+
Traceback (most recent call last):
31+
...
32+
ValueError: Number of bits must be > 0.
33+
34+
>>> e91_protocol('abc')
35+
Traceback (most recent call last):
36+
...
37+
TypeError: Number of bits must be an integer.
38+
39+
>>> e91_protocol(10001)
40+
Traceback (most recent call last):
41+
...
42+
ValueError: Number of bits is too large to simulate efficiently (>10000).
43+
"""
44+
# --- Input Validation ---
45+
if not isinstance(n_bits, int):
46+
raise TypeError("Number of bits must be an integer.")
47+
if n_bits <= 0:
48+
raise ValueError("Number of bits must be > 0.")
49+
if n_bits > 10000:
50+
raise ValueError("Number of bits is too large to simulate efficiently (>10000).")
51+
52+
# Define the measurement angles for Alice and Bob's bases as constants.
53+
# The keys correspond to the basis name, and values are angles in radians.
54+
ALICE_BASES = {'A1': 0, 'A2': np.pi / 8, 'A3': np.pi / 4}
55+
BOB_BASES = {'B1': np.pi / 8, 'B2': np.pi / 4, 'B3': 3 * np.pi / 8}
56+
57+
# Lists to store the choices and results for each bit.
58+
alice_chosen_bases, bob_chosen_bases = [], []
59+
alice_results, bob_results = [], []
60+
61+
# Get the quantum simulator backend.
62+
backend = AerSimulator()
63+
64+
for _ in range(n_bits):
65+
# Alice and Bob randomly choose their measurement bases.
66+
alice_basis_name = random.choice(list(ALICE_BASES.keys()))
67+
bob_basis_name = random.choice(list(BOB_BASES.keys()))
68+
alice_angle = ALICE_BASES[alice_basis_name]
69+
bob_angle = BOB_BASES[bob_basis_name]
70+
71+
# Create a quantum circuit for one entangled pair.
72+
qr = QuantumRegister(2, 'q')
73+
cr = ClassicalRegister(2, 'c')
74+
circuit = QuantumCircuit(qr, cr)
75+
76+
# Create a Bell state |Φ+⟩ = (|00⟩ + |11⟩)/sqrt(2)
77+
circuit.h(qr[0])
78+
circuit.cx(qr[0], qr[1])
79+
80+
# Apply rotations to simulate measurements in the chosen bases.
81+
circuit.ry(-2 * alice_angle, qr[0])
82+
circuit.ry(-2 * bob_angle, qr[1])
83+
84+
# Measure the qubits.
85+
circuit.measure(qr, cr)
86+
87+
# Execute the circuit and get the result.
88+
job = backend.run(circuit, shots=1)
89+
result = list(job.result().get_counts().keys())[0]
90+
91+
# Store choices and results. Qiskit's bit order is reversed.
92+
alice_chosen_bases.append(alice_basis_name)
93+
bob_chosen_bases.append(bob_basis_name)
94+
alice_results.append(int(result[1]))
95+
bob_results.append(int(result[0]))
96+
97+
98+
# Sift for generating the secret key.
99+
# The key is formed when Alice and Bob choose compatible bases.
100+
# Here, compatible means A2/B1 or A3/B2, where angles are identical.
101+
alice_key, bob_key = [], []
102+
for i in range(n_bits):
103+
is_a2b1 = alice_chosen_bases[i] == 'A2' and bob_chosen_bases[i] == 'B1'
104+
is_a3b2 = alice_chosen_bases[i] == 'A3' and bob_chosen_bases[i] == 'B2'
105+
if is_a2b1 or is_a3b2:
106+
alice_key.append(alice_results[i])
107+
bob_key.append(bob_results[i])
108+
109+
# Sift for the CHSH inequality test (Eve detection).
110+
# We use four specific combinations of bases for the test: a = A1, a' = A3 | b = B1, b' = B3
111+
chsh_correlations = {'ab': [], 'ab_': [], 'a_b': [], 'a_b_': []}
112+
113+
for i in range(n_bits):
114+
# Convert results {0, 1} to {-1, 1} for calculating correlation.
115+
a_val = 1 if alice_results[i] == 0 else -1
116+
b_val = 1 if bob_results[i] == 0 else -1
117+
product = a_val * b_val # +1 if correlated, -1 if anti-correlated
118+
119+
alice_basis = alice_chosen_bases[i]
120+
bob_basis = bob_chosen_bases[i]
121+
122+
if alice_basis == 'A1' and bob_basis == 'B1':
123+
chsh_correlations['ab'].append(product)
124+
elif alice_basis == 'A1' and bob_basis == 'B3':
125+
chsh_correlations['ab_'].append(product)
126+
elif alice_basis == 'A3' and bob_basis == 'B1':
127+
chsh_correlations['a_b'].append(product)
128+
elif alice_basis == 'A3' and bob_basis == 'B3':
129+
chsh_correlations['a_b_'].append(product)
130+
131+
# Calculate the expectation value (average correlation) for each combination.
132+
E = {}
133+
for key, values in chsh_correlations.items():
134+
E[key] = np.mean(values) if values else 0
135+
136+
# Calculate the S-value: S = E(a,b) - E(a,b') + E(a',b) + E(a',b')
137+
s_value = E['ab'] - E['ab_'] + E['a_b'] + E['a_b_']
138+
139+
# Check for eavesdropper: |S| > 2 indicates security.
140+
eavesdropper_detected = abs(s_value) <= 2
141+
142+
return {
143+
"alice_key": "".join(map(str, alice_key)),
144+
"bob_key": "".join(map(str, bob_key)),
145+
"s_value": s_value,
146+
"eavesdropper_detected": eavesdropper_detected,
147+
"key_match": alice_key == bob_key,
148+
"key_length": len(alice_key)
149+
}
150+
151+
152+
if __name__ == "__main__":
153+
# num_bits is initialized to 2000
154+
num_bits = 2000
155+
results = e91_protocol(num_bits)
156+
157+
print(f"CHSH S-value: {results['s_value']:.4f}")
158+
print(f"Eavesdropper detected: {results['eavesdropper_detected']}")
159+
print(f"Final key length: {results['key_length']}")
160+
print(f"Keys match: {results['key_match']}")
161+
162+
if not results['eavesdropper_detected'] and results['key_match'] and results['key_length'] > 0:
163+
print("\nProtocol successful! Secret key generated securely.")
164+
print(f" Alice's key: {results['alice_key']}")
165+
print(f" Bob's key: {results['bob_key']}")
166+
else:
167+
print("\nProtocol failed or eavesdropper detected. Key discarded.")

0 commit comments

Comments
 (0)