import json import os.path from alice import Alice from bob import Bob from channel import ChannelSym from threading import Thread import typing import sympy as sp from eve import EveBS def run_qkd(alice: Alice, bob: Bob, n: int = 1000): alice_thread = Thread(target=lambda: alice.generate_key(n)) bob_thread = Thread(target=lambda: bob.generate_key(n)) alice_thread.start() bob_thread.start() while alice_thread.is_alive() or bob_thread.is_alive(): pass def get_e_and_r(alice, bob, n=1000) -> typing.Tuple[float, float]: return 1 - sum(k1 == k2 for k1, k2 in zip(alice.key, bob.key)) / len(alice.key), len(alice.key) / n def common_alice_bob_eve(alice: Alice, eve, n=1000) -> float: return sum(correctness and alice_bit == eve_bit for alice_bit, eve_bit, correctness in zip(alice.key, eve.obtained_data, alice.correctness)) / n channel_parameters = {'p_opt': 0.05, 'p_dc': 0.05, 'mu': 1, 'detector_sensitivity': 0.8, 'transmittance': 0.8} PAR_NAMES = {'p_opt': 'p_{opt}', 'p_dc': 'p_{dc}', 'mu': r'\mu', 'detector_sensitivity': r'\eta', 'transmittance': 't', 'eve:hijack_probability': r'p_{Eve}'} mu, t, p_dc, p_opt, eta = sp.symbols(r'\mu t p_{dc} p_{opt} \eta') p1 = 2 * p_dc - p_dc ** 2 p_ea, p_eb = sp.exp(-mu * (1 - eta) * p_opt), sp.exp(mu * (eta + p_opt - eta * p_opt - 1)) e_theory = 0.5 * (p_dc + t * (1 - p_ea) - p_dc * t * (1 - p_ea)) \ * (1 - p_dc / 2 - 0.5 * t * (1 - p_eb) + 0.5 * p_dc * t * (1 - p_eb)) q_theory = 0.5 * (p1 + (1 - p1) * (1 - sp.exp(-mu * eta)) * t) e_theory /= q_theory def plot(parameter, values, add_eve: bool = False, show=False): data_q, data_e, eve_gains = [], [], [] data_q_theoretical, data_e_theoretical = [], [] parameters_sp = {PAR_NAMES[pname]: channel_parameters[pname] for pname in channel_parameters.keys()} n = 10000 for val in values: print(val) channel = ChannelSym(**({parameter: val} if not parameter.startswith('eve:') else {}), **{par: channel_parameters[par] for par in channel_parameters.keys() if par != parameter}) alice, bob = Alice(channel), Bob(channel) if add_eve: eve = EveBS(**({parameter.removeprefix('eve:'): val} if parameter.startswith('eve:') else {})) channel.eve = eve run_qkd(alice, bob, n) e, r = get_e_and_r(alice, bob, n) data_q.append(r) data_e.append(e) if add_eve: eve_gains.append(common_alice_bob_eve(alice, eve, n)) parameters_sp[PAR_NAMES.get(parameter, parameter)] = val data_q_theoretical.append(float(q_theory.evalf(subs=parameters_sp))) data_e_theoretical.append(float(e_theory.evalf(subs=parameters_sp))) from matplotlib import pyplot as plt plt.plot(values, data_q, label='$Q$') plt.plot(values, data_q_theoretical, label='$Q_{theory}$') plt.legend() if not os.path.exists('output'): os.mkdir('output') with open(f'output/dep_{parameter}.json', 'w') as f: f.write(json.dumps([list(values), data_q, data_e, data_q_theoretical, data_e_theoretical])) plt.xlabel('$' + PAR_NAMES.get(parameter, parameter) + '$') plt.title('$Q$ vs. $' + PAR_NAMES.get(parameter, parameter) + '$' + ' with Eve' * add_eve) plt.savefig(f'output/dep_{parameter}_q{"_with_eve" * add_eve}.png') if show: plt.show() else: plt.cla() plt.plot(values, data_e, label='$E$') plt.plot(values, data_e_theoretical, label='$E_{theory}$') plt.legend() plt.xlabel('$' + PAR_NAMES.get(parameter, parameter) + '$') plt.title('$E$ vs. $' + PAR_NAMES.get(parameter, parameter) + '$' + ' with Eve' * add_eve) plt.savefig(f'output/dep_{parameter}_e{"_with_eve" * add_eve}.png') if show: plt.show() else: plt.cla() if add_eve: plt.plot(values, [g / q for g, q in zip(eve_gains, data_q)], label='$Q_{Eve}$') plt.title('Eve\'s gains') plt.legend() plt.ylabel(r'$\dfrac{Q_{Eve}}{Q}$') plt.xlabel('$' + PAR_NAMES.get(parameter, parameter) + '$') plt.savefig(f'output/dep_{parameter}_eve_q.png') if show: plt.show() else: plt.cla() def run_one(): N = 1000 channel = ChannelSym() alice, bob = Alice(channel), Bob(channel) run_qkd(alice, bob) # print(list(map(int, alice.key))) # print(list(map(int, bob.key))) print('Alice bits: ', *list(map(int, alice.sent))) print('Bob bits: ', *list(map(lambda t: {(0, 1): 1, (1, 0): 0, (0, 0): 2, (1, 1): 3}[(int(t[0]), int(t[1]))], bob.my_results))) print('Alice basises:', *list(map(int, alice.my_basises))) print('Bob basises: ', *list(map(int, bob.my_basises))) bob_correctness = [left + right == 1 for left, right in bob.my_results] print(' ', *[ int(k) if c and b1 == b2 else ' ' for c, k, b1, b2 in zip(bob_correctness, alice.sent, bob.my_basises, alice.my_basises)]) print(' ', *[ {(0, 1): 1, (1, 0): 0, (0, 0): 2, (1, 1): 3}[(int(k[0]), int(k[1]))] if c and b1 == b2 else ' ' for c, k, b1, b2 in zip(bob_correctness, bob.my_results, bob.my_basises, alice.my_basises)]) print( f'{100 * sum(k1 == k2 for k1, k2 in zip(alice.key, bob.key)) / len(alice.key):.2f}%, ' f'key length: {len(alice.key)}') e, r = get_e_and_r(alice, bob, N) print(f'E: {e * 100:.1f}%, R: {r}') if __name__ == '__main__': import numpy as np plot('p_dc', np.arange(0, 0.15, 0.01)) plot('p_opt', np.arange(0, 0.15, 0.01)) plot('detector_sensitivity', np.arange(0.1, 1, 0.05)) plot('mu', np.arange(0.5, 2.5, 0.1)) plot('transmittance', np.arange(0.4, 1, 0.05)) # plot('eve:hijack_probability', np.arange(0, 1, 0.05))