Пример #1
0
 def run_protocol(self, protocol, arguments=(), blocking=False):
     """
     Run the protocol *protocol*.
     Args:
         protocol (function): The protocol that the host should run.
         arguments (tuple): The set of (ordered) arguments for the protocol
         blocking (bool): Wait for thread to stop before proceeding
     """
     arguments = (self, ) + arguments
     if blocking:
         DaemonThread(protocol, args=arguments).join()
     else:
         DaemonThread(protocol, args=arguments)
Пример #2
0
    def get_data_qubit(self, partner_id, q_id=None, wait=-1):
        """
        Gets the data qubit received from another host in the network. If qubit ID is specified,
        qubit with that ID is returned, else, the last qubit received is returned.

        Args:
            partner_id (string): The ID of the host that data qubit to be returned is received from.
            q_id (string): The qubit ID of the data qubit to get.
            wait (float): The amount of time to wait for the a qubit to arrive
        Returns:
             Qubit: Qubit received from the host with *partner_id* and *q_id*.
        """
        if not isinstance(wait, float) and not isinstance(wait, int):
            raise Exception('wait parameter should be a number')

        def _wait():
            nonlocal q
            nonlocal wait
            wait_start_time = time.time()
            while time.time() - wait_start_time < wait and q is None:
                q = _get_qubit(self._data_qubit_store, partner_id, q_id)
            return q

        if wait > 0:
            q = None
            DaemonThread(_wait).join()
            return q
        else:
            return _get_qubit(self._data_qubit_store, partner_id, q_id)
Пример #3
0
    def get_epr(self, partner_id, q_id=None, wait=-1):
        """
        Gets the EPR that is entangled with another host in the network. If qubit ID is specified,
        EPR with that ID is returned, else, the last EPR added is returned.

        Args:
            partner_id (string): The ID of the host that returned EPR is entangled to.
            q_id (string): The qubit ID of the EPR to get.
            wait (float): the amount of time to wait
        Returns:
             Qubit: Qubit shared with the host with *partner_id* and *q_id*.
        """
        if not isinstance(wait, float) and not isinstance(wait, int):
            raise Exception('wait parameter should be a number')

        def _wait():
            nonlocal q
            nonlocal wait
            wait_start_time = time.time()
            while time.time() - wait_start_time < wait and q is None:
                q = _get_qubit(self._EPR_store, partner_id, q_id)
            return q

        if wait > 0:
            q = None
            DaemonThread(_wait).join()
            return q
        else:
            return _get_qubit(self._EPR_store, partner_id, q_id)
Пример #4
0
    def get_classical(self, partner_id, wait=-1):
        """
        Get the classical messages from partner host *partner_id*.

        Args:
            partner_id (string): The ID of the partner who sent the clasical messages
            wait (float): How long in seconds to wait for the messages if none are set.

        Returns:
            A list of classical messages from Host with ID *partner_id*.
        """
        if not isinstance(wait, float) and not isinstance(wait, int):
            raise Exception('wait parameter should be a number')

        def process_messages():
            nonlocal cla
            cla = self._classical_messages.get_all_from_sender(partner_id)

        def _wait():
            nonlocal cla
            nonlocal wait
            wait_start_time = time.time()
            while time.time() - wait_start_time < wait and len(cla) == 0:
                process_messages()
            return cla

        if wait > 0:
            cla = []
            DaemonThread(_wait).join()
            return sorted(cla, key=lambda x: x.seq_num, reverse=True)
        else:
            cla = []
            process_messages()
            return sorted(cla, key=lambda x: x.seq_num, reverse=True)
Пример #5
0
    def get_message_w_seq_num(self, sender_id, seq_num, wait=-1):
        """
        Get a message from a sender with a specific sequence number.
        Args:
            sender_id (str): The ID of the sender
            seq_num (int): The sequence number
            wait (int):

        Returns:

        """
        def _wait():
            nonlocal m
            nonlocal wait
            wait_start_time = time.time()
            while time.time() - wait_start_time < wait and m is None:
                filter_messages()

        def filter_messages():
            nonlocal m
            for message in self.classical:
                if message.sender == sender_id and message.seq_num == seq_num:
                    m = message

        m = None
        if wait > 0:
            DaemonThread(_wait).join()
            return m
        else:
            filter_messages()
            return m
Пример #6
0
    def start(self, nodes=None, backend=None):
        """
        Starts the network.

        """
        if backend is None:
            self._backend = EQSNBackend()
        else:
            self._backend = backend
        if nodes is not None:
            self._backend.start(nodes=nodes)
        self._queue_processor_thread = DaemonThread(target=self._process_queue)
Пример #7
0
    def _process_queue(self):
        """
        Runs a thread for processing the packets in the packet queue.
        """

        self.logger.log('Host ' + self.host_id + ' started processing')
        while True:
            if self._stop_thread:
                break

            time.sleep(self.delay)
            if not self._packet_queue.empty():
                packet = self._packet_queue.get()
                if not packet:
                    raise Exception('empty message')
                DaemonThread(self._process_packet, args=(packet, ))
Пример #8
0
def main():
    # Initialize a network
    network = Network.get_instance()

    # Define the host IDs in the network
    nodes = ['Alice', 'Bob', 'Eve']

    network.delay = 0.0

    # Start the network with the defined hosts
    network.start(nodes)

    # Initialize the host Alice
    host_alice = Host('Alice')

    # Add a one-way connection (classical and quantum) to Bob
    host_alice.add_connection('Bob')

    # Start listening
    host_alice.start()

    host_bob = Host('Bob')
    # Bob adds his own one-way connection to Alice and Eve
    host_bob.add_connection('Alice')
    host_bob.add_connection('Eve')
    host_bob.start()

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

    # Add the hosts to the network
    # The network is: Alice <--> Bob <--> Eve
    network.add_host(host_alice)
    network.add_host(host_bob)
    network.add_host(host_eve)

    # Generate random key
    key_size = 8  # the size of the key in bit
    secret_key = np.random.randint(2, size=key_size)

    hosts = {'Alice': host_alice,
             'Bob': host_bob,
             'Eve': host_eve}

    # Concatentate functions
    def Alice_func(alice=host_alice):
        msg_buff = []
        Alice_qkd(alice, msg_buff, secret_key, hosts)
        Alice_send_message(alice, msg_buff, secret_key, hosts)

    def Eve_func(eve=host_eve):
        msg_buff = []
        eve_key = Eve_qkd(eve, msg_buff, key_size, hosts)
        Eve_receive_message(eve, msg_buff, eve_key, hosts)

    # Run Bob and Alice
    thread_alice = DaemonThread(Alice_func)
    thread_eve = DaemonThread(Eve_func)

    thread_alice.join()
    thread_eve.join()

    for h in hosts.values():
        h.stop()
    network.stop()
Пример #9
0
    def _process_queue(self):
        """
        Runs a thread for processing the packets in the packet queue.
        """

        while True:
            if self._stop_thread:
                break

            if not self._packet_queue.empty():
                # Artificially delay the network
                if self.delay > 0:
                    time.sleep(self.delay)

                packet = self._packet_queue.get()

                # Simulate packet loss
                packet_drop_var = random.random()
                if packet_drop_var > (1 - self.packet_drop_rate):
                    Logger.get_instance().log("PACKET DROPPED")
                    if packet.payload_type == protocols.QUANTUM:
                        packet.payload.release()
                    continue

                sender, receiver = packet.sender, packet.receiver

                if packet.payload_type == protocols.QUANTUM:
                    self._route_quantum_info(sender, receiver,
                                             [packet.payload])

                try:
                    if packet.protocol == protocols.RELAY and not self.use_hop_by_hop:
                        full_route = packet.route
                        route = full_route[full_route.index(sender):]
                    else:
                        if packet.protocol == protocols.REC_EPR:
                            route = self.get_classical_route(sender, receiver)
                        else:
                            route = self.get_classical_route(sender, receiver)

                    if len(route) < 2:
                        raise Exception('No route exists')

                    elif len(route) == 2:
                        if packet.protocol != protocols.RELAY:
                            if packet.protocol == protocols.REC_EPR:
                                host_sender = self.get_host(sender)
                                q = host_sender \
                                    .backend \
                                    .create_EPR(host_sender.host_id,
                                                receiver,
                                                q_id=packet.payload['q_id'],
                                                block=packet.payload['blocked'])
                                host_sender.add_epr(receiver, q)
                            self.ARP[receiver].rec_packet(packet)
                        else:
                            self.ARP[receiver].rec_packet(packet.payload)
                    else:
                        if packet.protocol == protocols.REC_EPR:
                            q_id = packet.payload['q_id']
                            blocked = packet.payload['blocked']
                            q_route = self.get_quantum_route(sender, receiver)

                            if self.use_ent_swap:
                                DaemonThread(self._entanglement_swap,
                                             args=(sender, receiver, q_route,
                                                   q_id, packet.seq_num,
                                                   blocked))
                            else:
                                DaemonThread(self._establish_epr,
                                             args=(sender, receiver, q_id,
                                                   packet.seq_num, blocked))

                        else:
                            network_packet = self._encode(route, packet)
                            self.ARP[route[1]].rec_packet(network_packet)

                except nx.NodeNotFound:
                    Logger.get_instance().error(
                        "route couldn't be calculated, node doesn't exist")
                except ValueError:
                    Logger.get_instance().error(
                        "route couldn't be calculated, value error")
                except Exception as e:
                    Logger.get_instance().error('Error in network: ' + str(e))
Пример #10
0
    def _entanglement_swap(self, sender, receiver, route, q_id, o_seq_num,
                           blocked):
        """
        Performs a chain of entanglement swaps with the hosts between sender and receiver to create a shared EPR pair
        between sender and receiver.

        Args:
            sender (Host): Sender of the EPR pair
            receiver (Host): Receiver of the EPR pair
            route (list): Route between the sender and receiver
            q_id (str): Qubit ID of the sent EPR pair
            o_seq_num (int): The original sequence number
            blocked (bool): If the pair being distributed is blocked or not
        """
        host_sender = self.get_host(sender)

        def establish_epr(net, s, r):
            if not net.shares_epr(s, r):
                self.get_host(s).send_epr(r, q_id, await_ack=True)
            else:
                old_id = self.get_host(s).change_epr_qubit_id(r, q_id)
                net.get_host(r).change_epr_qubit_id(route[i], q_id, old_id)

        # Create EPR pairs on the route, where all EPR qubits have the id q_id
        threads = []
        for i in range(len(route) - 1):
            threads.append(
                DaemonThread(establish_epr,
                             args=(self, route[i], route[i + 1])))

        for t in threads:
            t.join()

        for i in range(len(route) - 2):
            host = self.get_host(route[i + 1])
            q = host.get_epr(route[0], q_id, wait=10)
            if q is None:
                print("Host is %s" % host.host_id)
                print("Search host is %s" % route[0])
                print("Search id is %s" % q_id)
                print("EPR storage is")
                print(host.EPR_store)
                Logger.get_instance().error('Entanglement swap failed')
                return
            data = {
                'q': q,
                'eq_id': q_id,
                'node': sender,
                'o_seq_num': o_seq_num,
                'type': protocols.EPR
            }

            if route[i + 2] == route[-1]:
                data = {
                    'q': q,
                    'eq_id': q_id,
                    'node': sender,
                    'ack': True,
                    'o_seq_num': o_seq_num,
                    'type': protocols.EPR
                }

            host.send_teleport(route[i + 2],
                               None,
                               await_ack=True,
                               payload=data,
                               generate_epr_if_none=False)

        # Change in the storage that the EPR qubit is shared with the receiver
        q2 = host_sender.get_epr(route[1], q_id=q_id)
        host_sender.add_epr(receiver, q2, q_id, blocked)
        Logger.get_instance().log(
            'Entanglement swap was successful for pair with id ' + q_id +
            ' between ' + sender + ' and ' + receiver)
Пример #11
0
 def start(self):
     """
     Starts the host.
     """
     self._queue_processor_thread = DaemonThread(target=self._process_queue)