Intermediate

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.

- Whenever Alice wants to encode 1 in a qubit, she applies an X gate to the qubit. To encode 0, no action is needed as the qubits in qiskit are by default initialized to state 0 and applying an X gate is the equivalent of applying NOT.
- Wherever she wants to encode it in the Hadamard basis, she applies an hadamard gate. No action is necessary to encode a qubit in the computational basis as the default basis in qiskit is the computational basis
- She then
*sends*the qubits to Bob - Bob measures the qubits according to his binary string. To measure a qubit in the Hadamard basis, he applies an hadamard gate to the corresponding qubit and then performs a measurement on the computational basis.

```
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.