Browse Source

Graphics for eve, fixes

master
Lev 3 years ago
parent
commit
5aed59bd44
  1. 17
      model/alice.py
  2. 20
      model/bob.py
  3. 17
      model/channel.py
  4. 8
      model/eve.py
  5. 82
      model/main.py

17
model/alice.py

@ -9,22 +9,23 @@ from utils import bin_encode, bin_decode
class Alice: class Alice:
channel: Channel channel: Channel
sent: typing.List[bool] = field(default_factory=list) sent: typing.List[bool] = field(default_factory=list)
my_basises: typing.List[bool] = field(default_factory=list) my_bases: typing.List[bool] = field(default_factory=list)
key: typing.List[bool] = field(default_factory=list) key: typing.List[bool] = field(default_factory=list)
correctness: typing.List[bool] = field(default_factory=list)
def generate_key_and_send(self, n: int = 100): def generate_key_and_send(self, n: int = 100):
self.sent = [bool(r.randint(0, 1)) for _ in range(n)] self.sent = [bool(r.randint(0, 1)) for _ in range(n)]
self.my_basises = [bool(r.randint(0, 1)) for _ in range(n)] self.my_bases = [bool(r.randint(0, 1)) for _ in range(n)]
for key, basis in zip(self.sent, self.my_basises): for key, basis in zip(self.sent, self.my_bases):
self.channel.send_bit(key, basis) self.channel.send_bit(key, basis)
def generate_key(self, n: int = 100): def generate_key(self, n: int = 100):
self.generate_key_and_send(n) self.generate_key_and_send(n)
bobs_basises, bobs_correctness = bin_decode(self.channel.recv_classical(n, is_bob=False)), bin_decode( bobs_bases, bobs_correctness = bin_decode(self.channel.recv_classical(n, is_bob=False)), bin_decode(
self.channel.recv_classical(n, is_bob=False)) self.channel.recv_classical(n, is_bob=False))
acceptance = [ self.correctness = [
my_basis == bobs_basis and bobs_correctness my_basis == bobs_basis and bobs_correctness
for my_basis, bobs_basis, bobs_correctness in for my_basis, bobs_basis, bobs_correctness in
zip(self.my_basises, bobs_basises, bobs_correctness)] zip(self.my_bases, bobs_bases, bobs_correctness)]
self.channel.send_classical(bin_encode(acceptance), is_bob=False) self.channel.send_classical(bin_encode(self.correctness), is_bob=False)
self.key = [k for k, c in zip(self.sent, acceptance) if c] self.key = [k for k, c in zip(self.sent, self.correctness) if c]

20
model/bob.py

@ -11,19 +11,19 @@ class Bob:
channel: Channel channel: Channel
my_results: typing.List[typing.Tuple[bool, bool]] = field(default_factory=list) my_results: typing.List[typing.Tuple[bool, bool]] = field(default_factory=list)
key: typing.List[bool] = field(default_factory=list) key: typing.List[bool] = field(default_factory=list)
true_basises: typing.List[bool] = field(default_factory=list) correctness: typing.List[bool] = field(default_factory=list)
my_basises: typing.List[bool] = field(default_factory=list) my_bases: typing.List[bool] = field(default_factory=list)
def recv_photons(self, n: int = 100): def recv_photons(self, n: int = 100):
self.my_basises = [bool(r.randint(0, 1)) for _ in range(n)] self.my_bases = [bool(r.randint(0, 1)) for _ in range(n)]
self.my_results = self.channel.get_photon_results(self.my_basises) self.my_results = self.channel.get_photon_results(self.my_bases)
def send_basises_and_correctness(self): def send_bases_and_correctness(self):
self.channel.send_classical(bin_encode(self.my_basises)) self.channel.send_classical(bin_encode(self.my_bases))
self.channel.send_classical(bin_encode([left + right == 1 for left, right in self.my_results])) self.channel.send_classical(bin_encode([left + right >= 1 for left, right in self.my_results]))
def generate_key(self, n: int = 100): def generate_key(self, n: int = 100):
self.recv_photons(n) self.recv_photons(n)
self.send_basises_and_correctness() self.send_bases_and_correctness()
correctness = bin_decode(self.channel.recv_classical(n)) self.correctness = bin_decode(self.channel.recv_classical(n))
self.key = [(False if k[0] else True) for k, c in zip(self.my_results, correctness) if c] self.key = [(False if k[0] else True) for k, c in zip(self.my_results, self.correctness) if c]

17
model/channel.py

@ -19,7 +19,7 @@ class Channel(abc.ABC):
pass pass
@abc.abstractmethod @abc.abstractmethod
def get_photon_results(self, basises: typing.Optional[typing.List[bool]]) -> typing.List[typing.Tuple[bool, bool]]: def get_photon_results(self, bases: typing.Optional[typing.List[bool]]) -> typing.List[typing.Tuple[bool, bool]]:
""" """
Returns tuple of clicks of 0 and 1 for each bit Returns tuple of clicks of 0 and 1 for each bit
""" """
@ -33,14 +33,14 @@ class ChannelSym(Channel):
bob_classical_data_pool: str = '' bob_classical_data_pool: str = ''
alice_classical_data_pool: str = '' alice_classical_data_pool: str = ''
# probability for a photon to go to the wrong detector # probability for a photon to go to the wrong detector
p_opt: float = 0.05 p_opt: float = 0.015
# dark count # dark count
p_dc: float = 0.05 p_dc: float = 0.05
# the average number of emitted photons # the average number of emitted photons
mu: float = 1 mu: float = 1
# eta - the probability for a detector to react to a photon # eta - the probability for a detector to react to a photon
detector_sensitivity: float = 0.8 detector_sensitivity: float = 0.8
transmittance: float = 0.8 transmittance: float = 0.9
eve: typing.Optional[typing.Any] = None eve: typing.Optional[typing.Any] = None
def get_number_of_photos(self) -> int: def get_number_of_photos(self) -> int:
@ -70,15 +70,16 @@ class ChannelSym(Channel):
# print(f'{["Alice", "Bob"][is_bob]} received {n} characters') # print(f'{["Alice", "Bob"][is_bob]} received {n} characters')
return data return data
def get_photon_results(self, basises: typing.Optional[typing.List[bool]]) -> typing.List[typing.Tuple[bool, bool]]: def get_photon_results(self, bases: typing.Optional[typing.List[bool]]) -> typing.List[typing.Tuple[bool, bool]]:
res = list() res = list()
while len(self.bob_photons) < len(basises): while len(self.bob_photons) < len(bases):
pass pass
for photons, basis in zip(self.bob_photons, basises): for photons, basis in zip(self.bob_photons, bases):
clicks = [random.uniform(0, 1) <= self.p_dc, random.uniform(0, 1) <= self.p_dc] clicks = [random.uniform(0, 1) <= self.p_dc, random.uniform(0, 1) <= self.p_dc]
for ph_bit, ph_basis in photons:
if random.uniform(0, 1) > self.transmittance: if random.uniform(0, 1) > self.transmittance:
res.append(clicks)
continue continue
for ph_bit, ph_basis in photons:
if random.uniform(0, 1) <= self.detector_sensitivity: # We detected everything correctly if random.uniform(0, 1) <= self.detector_sensitivity: # We detected everything correctly
if ph_basis != basis: if ph_basis != basis:
if random.uniform(0, 1) > 0.5: if random.uniform(0, 1) > 0.5:
@ -89,7 +90,7 @@ class ChannelSym(Channel):
if random.uniform(0, 1) > self.p_opt: # Photon doesn't flip if random.uniform(0, 1) > self.p_opt: # Photon doesn't flip
clicks[ph_bit] = True clicks[ph_bit] = True
else: else:
clicks[not ph_bit] = False clicks[not ph_bit] = True
res.append((clicks[0], clicks[1])) res.append((clicks[0], clicks[1]))
self.bob_photons = list() self.bob_photons = list()
return res return res

8
model/eve.py

@ -6,12 +6,12 @@ from random import choice, uniform
@dataclass @dataclass
class EveBS: class EveBS:
hijack_probability: float = 0.45 hijack_probability: float = 0.45
my_basises: typing.List[bool] = field(default_factory=list) my_bases: typing.List[bool] = field(default_factory=list)
obtained_data: typing.List[typing.Optional[bool]] = field(default_factory=list) obtained_data: typing.List[typing.Optional[bool]] = field(default_factory=list)
def process_photons(self, photons: typing.List[typing.Tuple[bool, bool]]) -> typing.List[typing.Tuple[bool, bool]]: def process_photons(self, photons: typing.List[typing.Tuple[bool, bool]]) -> typing.List[typing.Tuple[bool, bool]]:
basis = choice([False, True]) basis = choice([False, True])
self.my_basises.append(basis) self.my_bases.append(basis)
clicks = [0, 0] clicks = [0, 0]
passed = [] passed = []
for photon in photons: for photon in photons:
@ -33,12 +33,12 @@ class EveBS:
@dataclass @dataclass
class EvePNS: class EvePNS:
k: int = 1 k: int = 1
my_basises: typing.List[bool] = field(default_factory=list) my_bases: typing.List[bool] = field(default_factory=list)
obtained_data: typing.List[typing.Optional[bool]] = field(default_factory=list) obtained_data: typing.List[typing.Optional[bool]] = field(default_factory=list)
def process_photons(self, photons: typing.List[typing.Tuple[bool, bool]]) -> typing.List[typing.Tuple[bool, bool]]: def process_photons(self, photons: typing.List[typing.Tuple[bool, bool]]) -> typing.List[typing.Tuple[bool, bool]]:
basis = choice([False, True]) basis = choice([False, True])
self.my_basises.append(basis) self.my_bases.append(basis)
clicks = [0, 0] clicks = [0, 0]
passed = [] passed = []
captured = 0 captured = 0

82
model/main.py

@ -24,46 +24,82 @@ 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 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} 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'} 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') mu, t, p_dc, p_opt, eta = sp.symbols(r'\mu t p_{dc} p_{opt} \eta')
e_theory = 0.5 * (p_dc + p_opt * mu * t * eta) / (2 * p_dc + mu * t * eta) p1 = 2 * p_dc - p_dc ** 2
q_theory = (mu * t * eta + 2 * p_dc) / 2 * (1 - e_theory * 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): def plot(parameter, values, add_eve: bool = False, show=False):
data_r, data_e = [], [] data_q, data_e, eve_gains = [], [], []
data_r_theoretical, data_e_theoretical = [], [] data_q_theoretical, data_e_theoretical = [], []
parameters_sp = {PAR_NAMES[pname]: channel_parameters[pname] for pname in PAR_NAMES.keys()} parameters_sp = {PAR_NAMES[pname]: channel_parameters[pname] for pname in channel_parameters.keys()}
n = 10000 n = 10000
for val in values: for val in values:
print(val) print(val)
channel = ChannelSym(**{parameter: 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) alice, bob = Alice(channel), Bob(channel)
if add_eve: if add_eve:
eve = EveBS() eve = EveBS(**({parameter.removeprefix('eve:'): val} if parameter.startswith('eve:') else {}))
channel.eve = eve channel.eve = eve
run_qkd(alice, bob, n) run_qkd(alice, bob, n)
e, r = get_e_and_r(alice, bob, n) e, r = get_e_and_r(alice, bob, n)
data_r.append(r) data_q.append(r)
data_e.append(e) 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 parameters_sp[PAR_NAMES.get(parameter, parameter)] = val
data_r_theoretical.append(float(q_theory.evalf(subs=parameters_sp))) data_q_theoretical.append(float(q_theory.evalf(subs=parameters_sp)))
data_e_theoretical.append(float(e_theory.evalf(subs=parameters_sp))) data_e_theoretical.append(float(e_theory.evalf(subs=parameters_sp)))
from matplotlib import pyplot as plt from matplotlib import pyplot as plt
plt.plot(values, data_r, label='$R$') plt.plot(values, data_q, label='$Q$')
plt.plot(values, data_e, label='$E$') plt.plot(values, data_q_theoretical, label='$Q_{theory}$')
plt.plot(values, data_r_theoretical, label='$R_{theory}$')
plt.plot(values, data_e_theoretical, label='$E_{theory}$')
plt.legend() plt.legend()
if not os.path.exists('output'): if not os.path.exists('output'):
os.mkdir('output') os.mkdir('output')
with open(f'output/dep_{parameter}.json', 'w') as f: with open(f'output/dep_{parameter}.json', 'w') as f:
f.write(json.dumps([list(values), data_r, data_e, data_r_theoretical, data_e_theoretical])) f.write(json.dumps([list(values), data_q, data_e, data_q_theoretical, data_e_theoretical]))
plt.xlabel('$' + PAR_NAMES.get(parameter, parameter) + '$') plt.xlabel('$' + PAR_NAMES.get(parameter, parameter) + '$')
plt.title('$R$ and $E$ vs. $' + PAR_NAMES.get(parameter, parameter) + '$' + ' with Eve' * add_eve) plt.title('$Q$ vs. $' + PAR_NAMES.get(parameter, parameter) + '$' + ' with Eve' * add_eve)
plt.savefig(f'output/dep_{parameter}.png') plt.savefig(f'output/dep_{parameter}_q{"_with_eve" * add_eve}.png')
if show:
plt.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(): def run_one():
@ -94,6 +130,10 @@ def run_one():
if __name__ == '__main__': if __name__ == '__main__':
import numpy as np import numpy as np
plot('p_dc', np.arange(0, 0.1, 0.01))
plot('detector_sensitivity', np.arange(0.5, 1, 0.05)) plot('p_dc', np.arange(0, 0.15, 0.01))
plot('mu', np.arange(0.5, 1.5, 0.1)) 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))

Loading…
Cancel
Save