Eavesdropping on channels

In this example we see how we can add an eavesdropper, or packet sniffer, to the network. First, as always, we initialize our network:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
network = Network.get_instance()
nodes = ["Alice", "Bob", "Eve"]
network.start(nodes)
network.delay = 0.0

host_alice = Host('Alice')
host_alice.add_connection('Bob')
host_alice.start()

host_bob = Host('Bob')
host_bob.add_connection('Alice')
host_bob.add_connection('Eve')
host_bob.start()

host_eve = Host('Eve')
host_eve.add_connection('Bob')
host_eve.delay = 0.2
host_eve.start()

network.add_host(host_alice)
network.add_host(host_bob)
network.add_host(host_eve)

Next we can define the protocols for Alice and Eve. First Alice is sending classical messages to Eve and next prepares qubits in the excited state and also sends them the Eve. Eve simply prints her messages and measures her qubits.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
amount_to_transmit = 5
def alice(host):
    for _ in range(amount_to_transmit):
        s = 'Hi Eve.'
        print("Alice sends: %s" % s)
        host.send_classical('Eve', s, await_ack=True)

    for _ in range(amount_to_transmit):
        print("Alice sends qubit in the |1> state")
        q = Qubit(host)
        q.X()
        host.send_qubit('Eve', q, await_ack=True)

def eve(host):
    for i in range(amount_to_transmit):
        alice_message = host.get_classical('Alice', wait=5, seq_num=i)
        print("Eve Received classical: %s." % alice_message.content)

    for i in range(amount_to_transmit):
        q = host.get_qubit('Alice', wait=10)
        m = q.measure()
        print("Eve measured: %d." % m)

Now we want to program Bob who sits between Alice and Eve in the network to manipulate the content of the messages being sent between them. For packets that contain qubits, Bob performs an \(X\) operation on them, which will undo Alice’s \(X\) operation. For packets with classical messages, Bob changes the content so as to let the receiver know that he saw that message.

1
2
3
4
5
6
7
8
def bob_sniffing_quantum(sender, receiver, qubit):
    # Bob applies an X operation to all qubits that are routed through him
    qubit.X()


def bob_sniffing_classical(sender, receiver, msg):
    # Bob modifies the message content of all classical messages routed through him
    msg.content = "** Bob was here :) ** " + msg.content

We set these protocols to the hosts via the following code:

1
2
3
4
5
6
7
8
host_bob.q_relay_sniffing = True
host_bob.q_relay_sniffing_fn = eve_sniffing_quantum

host_bob.c_relay_sniffing = True
host_bob.c_relay_sniffing_fn = bob_sniffing_classical

t1 = host_alice.run_protocol(alice)
t2 = host_eve.run_protocol(eve)

We should see the following output:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
Alice sends: Hi Eve.
Eve Received classical: ** Bob was here :) ** Hi Eve..
Alice sends: Hi Eve.
Eve Received classical: ** Bob was here :) ** Hi Eve..
Alice sends: Hi Eve.
Eve Received classical: ** Bob was here :) ** Hi Eve..
Alice sends: Hi Eve.
Eve Received classical: ** Bob was here :) ** Hi Eve..
Alice sends: Hi Eve.
Eve Received classical: ** Bob was here :) ** Hi Eve..
Alice sends qubit in the |1> state
Eve measured: 0.
Alice sends qubit in the |1> state
Eve measured: 0.
Alice sends qubit in the |1> state
Eve measured: 0.
Alice sends qubit in the |1> state
Eve measured: 0.
Alice sends qubit in the |1> state
Eve measured: 0.

The full example is below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
from qunetsim.components import Host
from qunetsim.components import Network
from qunetsim.objects import Message
from qunetsim.objects import Qubit
from qunetsim.objects import Logger

Logger.DISABLED = True

amount_transmit = 5


def alice(host):
    for _ in range(amount_transmit):
        s = 'Hi Eve.'
        print("Alice sends: %s" % s)
        host.send_classical('Eve', s, await_ack=True)

    for _ in range(amount_transmit):
        print("Alice sends qubit in the |1> state")
        q = Qubit(host)
        q.X()
        host.send_qubit('Eve', q, await_ack=True)


def bob_sniffing_quantum(sender, receiver, qubit):
    # Bob applies an X operation to all qubits that are routed through him
    qubit.X()


def bob_sniffing_classical(sender, receiver, msg):
    # Bob modifies the message content of all classical messages routed through him
    if isinstance(msg, Message):
        msg.content = "** Bob was here :) ** " + msg.content


def eve(host):
    for i in range(amount_transmit):
        alice_message = host.get_classical('Alice', wait=5, seq_num=i)
        print("Eve Received classical: %s." % alice_message.content)

    for i in range(amount_transmit):
        q = host.get_qubit('Alice', wait=10)
        m = q.measure()
        print("Eve measured: %d." % m)


def main():
    network = Network.get_instance()
    nodes = ["Alice", "Bob", "Eve"]
    network.start(nodes)
    network.delay = 0.0

    host_alice = Host('Alice')
    host_alice.add_connection('Bob')
    host_alice.start()

    host_bob = Host('Bob')
    host_bob.add_connection('Alice')
    host_bob.add_connection('Eve')
    host_bob.start()

    host_eve = Host('Eve')
    host_eve.add_connection('Bob')
    host_eve.delay = 0.2
    host_eve.start()

    network.add_host(host_alice)
    network.add_host(host_bob)
    network.add_host(host_eve)

    host_bob.q_relay_sniffing = True
    host_bob.q_relay_sniffing_fn = eve_sniffing_quantum

    host_bob.c_relay_sniffing = True
    host_bob.c_relay_sniffing_fn = bob_sniffing_classical

    t1 = host_alice.run_protocol(alice)
    t2 = host_eve.run_protocol(eve)

    t1.join()
    t2.join()

    network.stop(True)
    exit()


if __name__ == '__main__':
    main()