Imagine two people, Alice wants to communicate a secret message to Bob over an insecure medium such as the Internet. Since the Internet is publicly available for anyone to intercept, a special encryption scheme must be developed such that Bob can only access Alice's message with a special "key". We will focus on the BB84 algorithm, which is a symmetric key distribution algorithm enabling Alice to securely communicate her message to Bob.
We will first import the required libraries
from qiskit import QuantumCircuit, execute, Aer
from qiskit.visualization import plot_histogram, plot_bloch_multivector
from numpy.random import randint
import numpy as np
from qiskit.providers.aer import QasmSimulator
But what are the quantum and classical channels? A classical channel could be a communication wire like a telephone line where electrical signals represent bits or encoded information we send. A quantum communication channel can be a fiber optic cable( as quantum cryptography is implemented using polarization scrambling) through which we can send individual photons (particles of light). The polarization states are used to represent qubits.
Alice will generate two strings(consisting of 0s and 1s). One string will encode the basis for each qubit and the other string will encode its state.
0 in the Hadamard basis will be represented as state |+> and 1 in the Hadamard basis is represented as state |- >. The Hadamard basis can be seen as the result of applying a Hadamard gate on the computational basis |0> or |1>. The computational basis will be represented by 0 and Hadamard basis by 1. Let us suppose that Alice wants to generate a 32 bit string. The number of qubits needed is 32. We will generate two random strings that represent Alice's state and the basis that Alice uses for encoding the state (the information about which basis Alice uses for encoding the state is very important for Bob to decrypt the message using the key).
num_qubits = 32
alice_basis = np.random.randint(2, size=num_qubits)
alice_state = np.random.randint(2, size=num_qubits)
bob_basis = np.random.randint(2, size=num_qubits)
print(f"Alice's State:\t {np.array2string(alice_state})
print(f"Alice's Bases:\t {np.array2string(alice_basis})
print(f"Bob's Bases:\t {np.array2string(bob_basis})
An example of the output we get is
Now, when Alice's State is 1 and her basis is 0, this means that she is using the computational basis to encode the state 1. However, if Alice's state is 1 and her basis is 1, that means she is using the Hadamard gate to encode the state 1 which will result in |- >
We will use this algorithm to construct the circuit.
def bb84_circuit(state, basis, measurement_basis):
#state: array of 0s and 1s denoting the state to be encoded
#basis: array of 0s and 1s denoting the basis to be used for encoding
#0 -> Computational Basis
#1 -> Hadamard Basis
#meas_basis: array of 0s and 1s denoting the basis to be used for measurement
#0 -> Computational Basis
#1 -> Hadamard Basis
'''
num_qubits = len(state)
circuit = QuantumCircuit(num_qubits)
# Sender prepares qubits
for i in range(len(basis)):
if state[i] == 1:
bb84_circuit.x(i)
if basis[i] == 1:
bb84_circuit.h(i)
# Measuring action performed by Bob
for i in range(len(measurement_basis)):
if measurement_basis[i] == 1:
bb84_circuit.h(i)
bb84_circuit.measure_all()
return bb84_circuit
Alice and Bob only keep the bits in the strings where the bases match. For example, in the example above only if Alice's encoding basis is 0 and Bob's measuring basis is 0 or its 1 and 1 the bits are kept
The probability that their bases match is 1/2 as the probability that Alice chooses computational basis is 1/2 and probability that Bob chooses computational basis is 1/2 so the probability that both choose computational basis is 1/4 or the probability that both choose hadamard basis is ((1/2)*(1/2)) so in total the probability that both their bases match is 1/2.
Here are all the possibilities for the BB84 protocol.
We will keep the bits that match so when alice_basis[i] == bob_basis[i]
circuit = bb84_circuit(alice_state, alice_basis, bob_basis)
key = execute(circuit.reverse_bits(),backend=QasmSimulator(),shots=1).result().get_counts().most_frequent()
encryption_key = ''
for i in range(num_qubits):
if alice_basis[i] == bob_basis[i]:
encryption_key += str(key[i])
print(f"Key: {encryption_key}")
This is the key Bob will use for decrypting Alice's message.
About
Support
Every week, our team curates the most important news, events, and opportunities in the quantum space. Our subscribers gain early access to opportunities and exclusive interviews with prominent individuals. You don't want to miss out.