Skip to content

Commit 5dd57cf

Browse files
abhishekchak52pre-commit-ci[bot]cclaussMaximSmolskiy
authored andcommitted
BB84 QKD algorithm (TheAlgorithms#7898)
* Added BB84 algorithm. * Function name lowercase + imports fix I thought uppercase was appropriate because they're initials. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update quantum/bb84.py Co-authored-by: Christian Clauss <[email protected]> * Removed python < 3.11 restriction from qiskit * Removed python < 3.11 restriction from qiskit * scikit-learn * Update quantum/bb84.py Correct typo in `default_rng()` call Co-authored-by: Maxim Smolskiy <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Christian Clauss <[email protected]> Co-authored-by: Maxim Smolskiy <[email protected]>
1 parent b55c7ad commit 5dd57cf

File tree

2 files changed

+135
-2
lines changed

2 files changed

+135
-2
lines changed

Diff for: quantum/bb84.py

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Simulation of the Quantum Key Distribution (QKD) protocol called BB84,
4+
created by Charles Bennett and Gilles Brassard in 1984.
5+
6+
BB84 is a key-distribution protocol that ensures secure key distribution
7+
using qubits instead of classical bits. The generated key is the result
8+
of simulating a quantum circuit. Our algorithm to construct the circuit
9+
is as follows:
10+
11+
Alice generates two binary strings. One encodes the basis for each qubit:
12+
13+
- 0 -> {0,1} basis.
14+
- 1 -> {+,-} basis.
15+
16+
The other encodes the state:
17+
18+
- 0 -> |0> or |+>.
19+
- 1 -> |1> or |->.
20+
21+
Bob also generates a binary string and uses the same convention to choose
22+
a basis for measurement. Based on the following results, we follow the
23+
algorithm below:
24+
25+
X|0> = |1>
26+
27+
H|0> = |+>
28+
29+
HX|0> = |->
30+
31+
1. Whenever Alice wants to encode 1 in a qubit, she applies an
32+
X (NOT) gate to the qubit. To encode 0, no action is needed.
33+
34+
2. Wherever she wants to encode it in the {+,-} basis, she applies
35+
an H (Hadamard) gate. No action is necessary to encode a qubit in
36+
the {0,1} basis.
37+
38+
3. She then sends the qubits to Bob (symbolically represented in
39+
this circuit using wires).
40+
41+
4. Bob measures the qubits according to his binary string for
42+
measurement. To measure a qubit in the {+,-} basis, he applies
43+
an H gate to the corresponding qubit and then performs a measurement.
44+
45+
References:
46+
https://en.wikipedia.org/wiki/BB84
47+
https://qiskit.org/textbook/ch-algorithms/quantum-key-distribution.html
48+
"""
49+
import numpy as np
50+
import qiskit
51+
52+
53+
def bb84(key_len: int = 8, seed: int | None = None) -> str:
54+
"""
55+
Performs the BB84 protocol using a key made of `key_len` bits.
56+
The two parties in the key distribution are called Alice and Bob.
57+
Args:
58+
key_len: The length of the generated key in bits. The default is 8.
59+
60+
seed: Seed for the random number generator.
61+
Mostly used for testing. Default is None.
62+
63+
Returns:
64+
key: The key generated using BB84 protocol.
65+
66+
>>> bb84(16, seed=0)
67+
'1101101100010000'
68+
69+
>>> bb84(8, seed=0)
70+
'01011011'
71+
"""
72+
# Set up the random number generator.
73+
rng = np.random.default_rng(seed=seed)
74+
75+
# Roughly 25% of the qubits will contribute to the key.
76+
# So we take more than we need.
77+
num_qubits = 6 * key_len
78+
# Measurement basis for Alice's qubits.
79+
alice_basis = rng.integers(2, size=num_qubits)
80+
# The set of states Alice will prepare.
81+
alice_state = rng.integers(2, size=num_qubits)
82+
# Measurement basis for Bob's qubits.
83+
bob_basis = rng.integers(2, size=num_qubits)
84+
85+
# Quantum Circuit to simulate BB84
86+
bb84_circ = qiskit.QuantumCircuit(num_qubits, name="BB84")
87+
88+
# Alice prepares her qubits according to rules above.
89+
for index, _ in enumerate(alice_basis):
90+
if alice_state[index] == 1:
91+
bb84_circ.x(index)
92+
if alice_basis[index] == 1:
93+
bb84_circ.h(index)
94+
bb84_circ.barrier()
95+
96+
# Bob measures the received qubits according to rules above.
97+
for index, _ in enumerate(bob_basis):
98+
if bob_basis[index] == 1:
99+
bb84_circ.h(index)
100+
101+
bb84_circ.barrier()
102+
bb84_circ.measure_all()
103+
104+
# Simulate the quantum circuit.
105+
sim = qiskit.Aer.get_backend("aer_simulator")
106+
# We only need to run one shot because the key is unique.
107+
# Multiple shots will produce the same key.
108+
job = qiskit.execute(bb84_circ, sim, shots=1, seed_simulator=seed)
109+
# Returns the result of measurement.
110+
result = job.result().get_counts(bb84_circ).most_frequent()
111+
112+
# Extracting the generated key from the simulation results.
113+
# Only keep measurement results where Alice and Bob chose the same basis.
114+
gen_key = "".join(
115+
[
116+
result_bit
117+
for alice_basis_bit, bob_basis_bit, result_bit in zip(
118+
alice_basis, bob_basis, result
119+
)
120+
if alice_basis_bit == bob_basis_bit
121+
]
122+
)
123+
124+
# Get final key. Pad with 0 if too short, otherwise truncate.
125+
key = gen_key[:key_len] if len(gen_key) >= key_len else gen_key.ljust(key_len, "0")
126+
return key
127+
128+
129+
if __name__ == "__main__":
130+
print(f"The generated key is : {bb84(8, seed=0)}")
131+
from doctest import testmod
132+
133+
testmod()

Diff for: requirements.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ opencv-python
88
pandas
99
pillow
1010
projectq
11-
qiskit; python_version < "3.11"
11+
qiskit
1212
requests
1313
rich
1414
scikit-fuzzy
15-
sklearn
15+
scikit-learn
1616
statsmodels
1717
sympy
1818
tensorflow; python_version < "3.11"

0 commit comments

Comments
 (0)