Implementing The BB84 Protocol Simulation

Learning Lab
My Journey Through Books, Discoveries, and Ideas

Implementing the BB84 protocol simulation

In my simulation of quantum cryptography, I implemented the Bennett and Brassard 1984 (BB84) quantum key distribution protocol. This implementation models the key generation, transmission (with potential eavesdropping), and reconciliation steps.

Representing qubits

In the BB84 protocol, information is encoded in the state of individual qubits. For this simulation, I represent a qubit with its classical bit value (0 or 1) and the basis used to encode it (0 for rectilinear \{| \boldsymbol + \rangle, | \boldsymbol + \rangle \}, 1 for diagonal \{| + \mathbf i \rangle, | -\mathbf i \rangle \}). The BB84Qubit class handles this:


class BB84Qubit:
    def __init__(self, bit: int, basis: int):
        self._mBit = bit      # 0 or 1
        self._mBasis = basis  # 0: rectilinear (+), 1: diagonal (x)

    # ... properties ...

    def Measure(self, measurementBasis: int):
        if measurementBasis == self._mBasis:
            # Measurement in the same basis yields the original bit
            return self._mBit
        else:
            # Measurement in a different basis yields a random outcome
            return np.random.randint(0, 2)

Measurement is simulated by the Measure method. If the measurement basis matches the preparation basis, the original bit is returned deterministically. If the bases differ, the outcome is random (0 or 1 with 50\% probability each), reflecting the principles of quantum measurement.

The BB84 protocol simulation

The BB84Protocol class manages the key exchange.

1. Key generation (Alice)

Alice initiates the protocol by generating a sequence of random bits and preparing qubits using randomly chosen bases for each bit.


    def generateKey(self, seed: int = None):
        if seed is not None:
            np.random.seed(seed)
        length = self._cfg.KEY_LENGTH
        bits = np.random.randint(0, 2, length)
        bases = np.random.randint(0, 2, length)
        self._qubits_a = [BB84Qubit(b, ba) for b, ba in zip(bits, bases)]
        # ...
2. Transmission and potential eavesdropping (quantum channel)

Alice sends her qubits to Bob. This stage is susceptible to eavesdropping. My simulation includes an option (eavesdropping=True) where an eavesdropper (Eve) intercepts each qubit, measures it using a random basis, and resends a new qubit based on her measurement outcome and basis.


    def sendKey(self, eavesdropping=False, seed: int = None):
        if eavesdropping:
            # ... setup ...
            for q, b_e in zip(self._qubits_a, bases_e):
                m = q.Measure(b_e) # Eve measures
                # Eve resends based on her measurement
                self._qubits_e.append(BB84Qubit(m, b_e))
                self._qubits_b.append(BB84Qubit(m, b_e)) # Bob receives tampered qubit
        else:
            # No eavesdropping, Bob receives original qubits
            self._qubits_b = [BB84Qubit(q.mBit, q.mBasis)
                              for q in self._qubits_a]

Eve’s actions inevitably introduce errors if she guesses the wrong basis, which Alice and Bob can later detect.

3. Measurement (Bob)

Bob receives the qubits (potentially altered by Eve) and measures each one using his own randomly chosen sequence of bases.

4. Reconciliation (public classical channel)

Alice and Bob communicate over a public classical channel (assumed authenticated) to reconcile their key.

  • They compare the bases they used for each qubit.
  • They discard the measurement results where their bases did not match. The remaining bits form the “sifted key”.

        # Part of reconcileKey method
        bases_b = np.random.randint(0, 2, length) # Bob's random bases
        bits_b = [q.Measure(b) for q, b in zip(self._qubits_b, bases_b)] # Bob measures

        bases_a = [q.mBasis for q in self._qubits_a] # Alice's original bases

        # Identify indices where bases match
        matches = [i for i in range(length) if bases_a[i] == bases_b[i]]
        bits_a_matched = [bits_a[i] for i in matches] # Alice's bits at matched indices
        bits_b_matched = [bits_b[i] for i in matches] # Bob's bits at matched indices
5. Error Estimation (QBER)

To detect eavesdropping, Alice and Bob compare a randomly chosen subset of their sifted key bits over the public channel. They calculate the Quantum Bit Error Rate (QBER):

\text{QBER} = \frac{\text{Number of mismatched bits in subset}}{\text{Total number of bits in subset}}

If the QBER exceeds a predefined threshold (self._cfg.QBER), they assume an eavesdropper was present and abort the protocol. Eve’s measurements in random bases will cause disagreements between Alice’s and Bob’s bits even when they used the same basis, increasing the QBER.


        # Part of reconcileKey method (continued)
        # ... select subset_idx ...
        a_subset = [bits_a_matched[i] for i in subset_idx]
        b_subset = [bits_b_matched[i] for i in subset_idx]

        qber = sum(a != b for a, b in zip(a_subset, b_subset)) / subset_size

        if qber < self._cfg.QBER:
            # Key is likely secure
            # ... generate final key from remaining bits ...
            self._isKeyValid = True
            self._isKeyCompromised = False
        else:
            # Eavesdropping detected
            self._key = None
            self._isKeyValid = False
            self._isKeyCompromised = True
6. Final key generation

If the QBER is below the threshold, Alice and Bob use the remaining sifted bits (those not used for QBER estimation) as their shared secret key. The simulation packs these bits into a byte string. Error correction and privacy amplification, which are subsequent steps in a full QKD protocol, are not included in this basic simulation.

Testing

Unit tests verify the simulation’s behavior:

  • a valid key can be generated when no eavesdropping occurs,
  • eavesdropping leads to a high QBER and prevents valid key generation,
  • encryption and decryption using the generated key work correctly if the key is valid.

This simulation provides a practical demonstration of the fundamental principles behind the BB84 protocol and how it uses quantum properties to detect eavesdropping during key exchange.

I previously discussed the theoretical framework in a previous posts here.

For access to the complete simulation code, please visit the GitHub repository here.