Créer un site internet

RSX218

Simulateur NETSQUID

Pour l'unité d'enseignement RSX218 - réseaux avancés, nous devions utiliser le simulateur de réseau quantique NETSQUID afin de démontrer ses capacités.

Pour cela en trinôme nous avons créé 2 programmes basés sur le protocole BB84 et E91

Voici BB84 :

"""

                    Programme créé par Oziol Joris.  Utilise le simulateur Netsquid afin d'implémenter le protocole BB84

"""

import netsquid as ns

from netsquid.nodes import Network

from netsquid.nodes.node import Node

from netsquid.components import QuantumChannel

from netsquid.components.cchannel import ClassicalChannel

from netsquid.qubits.operators import X, Z

from netsquid.qubits.qubitapi import create_qubits, operate, measure

from netsquid.components.models.delaymodels import FibreDelayModel, FixedDelayModel

from netsquid.components.models.qerrormodels import FibreLossModel, DepolarNoiseModel

import random, time, os, datetime

import matplotlib.pyplot as plt

 

def alice_protocol(quantum_channel, classical_channel, num_qubits):

                    ''' Fonction responsable de la génération des qubits par Alice et de leur préparation en utilisant les bases aléatoires '''

                    alice_qubits = create_qubits(num_qubits)                                            # Alice créée des qubits au nombre demandé dans la fonction principale.

                    alice_bases = [random.choice(['X', 'Z']) for _ in range(num_qubits)] # Elle choisi une base polarisante aléatoirement pour chaque qubit créé.

                    for i in range(num_qubits):                                                             # Pour chaque qubit :

                                         qubit = alice_qubits[i]                                                      # On prépare un qubit à être polarisé.

                                         if alice_bases[i] == 'X':                                            # Si la base d'Alice est égale à X...

                                                             operate(qubit, ns.X)                                      # ... alors le qubit est polarisé par cette base.

                                         elif alice_bases[i] == 'Z':                                          # Si la base d'Alice est égale à Z...

                                                             operate(qubit, ns.Z)                                       # ... alors le qubit est polarisé par cette base.

                                         quantum_channel.send(qubit)                                          # Les qubits ainsi polarisés sont envoyés sur le canal quantique.

                    classical_channel.send(alice_bases)                 # Les bases choisies par Alice sont envoyées sur le canal classique.

                    return alice_qubits, alice_bases

 

def bob_protocol(quantum_channel, classical_channel, num_qubits, loss_model, noise_model):

                    ''' Fonction responsable de la réception des qubits par Bob, de leur mesure en utilisant des bases aléatoires et de la comparaison des bases avec celles reçues d'Alice pour générer la clé secrète '''

                    bob_qubits_t = quantum_channel.receive()                                            # Bob réceptionne les qubits sur le canal quantique.

                    bob_qubits = bob_qubits_t[0]                                                                # On prépare les qubits à être lu dans un tableau.

                    bob_bases = [random.choice(['X', 'Z']) for _ in range(num_qubits)]    # Il choisi aléatoirement une base polarisante pour chaque qubit reçu.

                    bob_results = []                                                                                      # On initialise sa liste de résultats.

                    for i in range(num_qubits):                                                              # Pour chaque qubit :

                          if i < len(bob_qubits):                                                               # S'il reste des qubits à mesurer...

                                  if random.random() < 1 - loss_model.p_loss_init - loss_model.p_loss_length * quantum_channel.length:         # Si le qubit n'a pas été perdu par nos modèles de perte, alors :

                                            if bob_bases[i] == 'X':                                             # Si la base de Bob est égale à X...

                                                                 result = measure(bob_qubits[i], observable=ns.X)      # ... alors il pourra visualiser le qubit s'il a été polarisé avec la base X d'Alice.

                                            elif bob_bases[i] == 'Z':                                           # Si la base de Bob est égale à Z...

                                                                  result = measure(bob_qubits[i], observable=ns.Z)     # ... alors il pourra visualiser le qubit s'il a été polarisé avec la base Z d'Alice.

                                                                  noise_model.error_operation(result)                           # On calcule l'erreur liée au bruit.

                                                                  bob_results.append(result)                                         # Bob complète sa liste de résultats.

                                 else:                                                                              # Sinon on affiche un message d'erreur.

                                           print("Longueur du canal quantique insuffisante. Tous les qubits ont été mesurés.")                                                                                              

                                           return None, None, None

                    classical_channel.send(bob_bases)                                                             # Les bases choisies par Bob sont envoyées sur le canal classique.

                    alice_bases_received = classical_channel.receive()[0]                              # Alice réceptionne les bases de Bob.

                    loss_count = num_qubits - len(bob_results)                                               # Le nombre de qubits perdu est calculé.

                    loss_rate = loss_count / num_qubits                                                            # On en génère un taux de perte.

                if loss_rate > 0.5:                                                  # Si le taux de perte est supérieur à 50%, on affiche un message d'erreur :

                      print("Taux de perte de qubits supérieur à 50%. La clé ne peut pas être créée.\n")

                      return None, None, None

                   secret_key = []                                                                                          # On initialise la clé secrète.

                for i in range(num_qubits):                                                                  # Pour chaque qubit.

                     if i < len(alice_bases_received):                                                   # S'il reste des bases à compter...

                           if alice_bases_received[i] == bob_bases[i]:                      # Si la base d'Alice est égale à la base de Bob...

                                       secret_key.append(alice_bases_received[i])         # Alors le qubit est conservé pour former la clé secrète.

                    num_bits = len(secret_key)                                                                          # On conserve le nombre de bits en fonction de la longueur de la clé.

                secret_key_error_rate = sum(a != b for a, b in zip(alice_bases_received, secret_key)) / num_bits           # On calcule le taux d'erreur de la clé.

                return bob_results, secret_key, secret_key_error_rate

                   

                   

def eve_protocol(quantum_channel, num_qubits):

                    ''' Fonction responsable de la réception des qubits par Eve et de leur mesure en utilisant des bases aléatoires '''

                   

                    eve_qubits_t = quantum_channel.receive()                                                                                                                                                   # Eve capte les qubits sur le canal quantique.

                    eve_qubits = eve_qubits_t[0]                                                                                                                                                                                                                    # On prépare les qubits à être lu dans un tableau.

                    eve_bases = [random.choice(['X', 'Z']) for _ in range(num_qubits)]    # Elle choisi aléatoirement une base polarisante pour chaque qubit reçu.

                    eve_results = []                                                                                                                                                                                                                                                                                      # On initialise sa liste de résultats.

                    for i in range(num_qubits):                                                                                                                                                                              # Pour chaque qubit :

                                         if i < len(eve_qubits):                                                                                                                                                                                          # S'il reste des qubits à mesurer :

                                                             if eve_bases[i] == 'X':                                                                                                                                                                                         # Si la base d'Eve est égale à X...

                                                                                 result = measure(eve_qubits[i], observable=ns.X)                                                                           # ... alors elle pourra visualiser le qubit s'il a été polarisé avec la base X d'Alice.

                                                             elif eve_bases[i] == 'Z':                                                                                                                                                                                         # Si la base d'Eve est égale à Z...

                                                                                 result = measure(eve_qubits[i], observable=ns.Z)                                                                           # ... alors elle poura visaliser le qubit s'il a été polarisé avec la base Z d'Alice.

                                                             eve_results.append(result)                                                                                                                                                               # Eve complète sa liste de résultats.

                    return eve_bases, eve_results

def encrypt_message(message, secret_key):

                    '''Fonction utilisée pour chiffrer le message en utilisant la clé secrète générée '''

                   

                    encrypted_message = ''                                                                                                                                                                                                                                                                         # On initialise le message chiffré.

                    for i, bit in enumerate(secret_key):                                                                                                                                                                                       # Pour chaque bit qu'il y a dans la clé secrète...

                                         if i < len(message):                                                                                                                                                                                                                                                             # On vérifie si l'index est inférieur à la longueur du message

                                                             if bit == 'X':                                                                                                                                                                                                                                                                                                                 # Si le bit de la base est égale à X...

                                                                                 encrypted_message += str(int(message[i]) ^ 1)                                                                                                                                             # ... alors on opère la transformation cryptographique associée au bit du message.

                                                             elif bit == 'Z':                                                                                                                                                                                                                                                                                           # Si le bit de la base est égale à Z...

                                                                                 encrypted_message += message[i]                                                                                                                                                                                                              # ... alors on opère la transformation cryptographique associée au bit du message.

                    print("Le message chiffré avec la clé secrète d'Alice est envoyé sur la canal classique : ",encrypted_message,"\n")

                    return encrypted_message

def decrypt_message(encrypted_message, secret_key):

                    '''Fonction utilisée pour déchiffrer le message en utilisant la clé secrète générée '''

                   

                    decrypted_text = ''                                                                                                                                                                                                                                                            # On initialise le message déchiffré.

                    for i, bit in enumerate(secret_key):                                                                                                                                                                                     # Pour chaque bit qu'il y a dans la clé secrète...

                                         if i < len(encrypted_message):                                                                                                                                                                            # On vérifie si l'index est inférieur à la longueur du message chiffré

                                                             if bit == 'X':                                                                                                                                                                                                                                                                          # Si le bit de la base est égale à X...

                                                                                 decrypted_text += str(int(encrypted_message[i]) ^ 1)                                                                      # ... alors on opère la transformation cryptographique associée au bit du message.

                                                             elif bit == 'Z':                                                                                                                                                                                                                                                                     # Si le bit de la base est égale à Z...

                                                                                 decrypted_text += encrypted_message[i]                                                                                                                                                       # ... alors on opère la transformation cryptographique associée au bit du message.

                    return decrypted_text

def main():

                    # Création d'un canal quantique avec un modèle de retard de transmission et un modèle de perte de fibre :

                    Fdelay_model = FibreDelayModel(c=200000)                                                                                                                                                                                                          # Vitesse des photons de 200000 km/s

                    noise_model = DepolarNoiseModel(depolar_rate=0.05, time_independent=False)                   # Taux de dépolarisation de 5%

                    delay_model = FixedDelayModel(delay_time=10)                                                                                                                                                                               # Temps nécessaire à l'envoie de qubit (période en ns)

                    loss_model = FibreLossModel(p_loss_init=0.0, p_loss_length=0.00045)                                                      # Modèle de perte exponentielle de photons sur les canaux de fibres optiques :

                    # Il utilise la longueur du canal de transmission pour échantillonner une probabilité de perte exponentielle. Ses paramètres sont les suivants :

                    # p_loss_init (float, optionnel) - Probabilité initiale de perte d'un photon une fois qu'il entre dans un canal, par exemple en raison d'une conversion de fréquence.

                    # p_loss_length (float, optionnel) - Probabilité de survie des photons par longueur de canal [dB/km].

                     

                    # Déclaration de tous les noeuds, les canaux et leurs interconnexions :

                    network = Network(name="réseau quantique simulé")

                    alice = Node("Alice")

                    bob = Node("Bob")

                    eve = Node("Eve")

                    qchannel = QuantumChannel("QuantumChannel", length=0, models={"delay_model": delay_model, "quantum_noise_model": noise_model, "fibre_delay_model": Fdelay_model, "quantum_loss_model": loss_model}, transmit_empty_items=True)

                    cchannel = ClassicalChannel("ClassicalChannel")

                    network.add_node(alice)

                    network.add_node(bob)

                    network.add_node(eve)

                    network.add_connection(alice, bob, channel_to=QuantumChannel("QuantumChannel"), label = "quantum")

                    network.add_connection(alice, eve, channel_to=QuantumChannel("QuantumChannel"), label = "quantum")

                    network.add_connection(eve, bob, channel_to=QuantumChannel("QuantumChannel"), label= "quantum")

                    network.add_connection(alice, bob, channel_to=ClassicalChannel("ClassicalChannel"), label = "classique")           

                    # Longueurs de fibre à tester :

                    fibre_lengths = [0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000# en km

                    # Message à envoyer :

                    message = "Test de Netsquid !"

                    print("\nLe message d'Alice avant chiffrement est le suivant : ",message,"\n")

                    # Listes pour stocker les taux de perte de qubits :

                    loss_counts = []

                    loss_rates = []

                    execution_times = []

                    secret_key_error_rates = []

                   

                    # Demande à l'utilisateur si vous voulez voir l'attaque d'Eve :

                    choice = input("Voulez-vous voir l'attaque d'Eve ? (y/n) ")

                    attaque = random.choice(fibre_lengths)

                    for length in fibre_lengths:

                                         print("################# Longueur = ",length,"Km ################################\n")

                                         start_time = time.time()

                                         # Réinitialisation du canal avec une nouvelle longueur de fibre :

                                         qchannel.length = length

                                         # Vérification de la longueur du canal quantique :

                                         if length > qchannel.length:

                                                             print("La longueur du canal quantique est insuffisante pour envoyer tous les qubits.")

                                                             continue

                                         # Appel du protocole Alice :

                                         num_qubits = 1000

                                         alice_qubits, alice_bases = alice_protocol(qchannel, cchannel, num_qubits)

                                        

                                         # Vérification si la clé secrète est générée :

                                         if alice_qubits is None:

                                                             print("clé trop courte")

                                                             continue

                                                            

                                         if choice.lower() == 'y' :

                                                             if length == attaque :

                                                                                 # Appel du protocole Eve :

                                                                                 eve_bases, eve_results = eve_protocol(qchannel, num_qubits)

                                         # Appel du protocole Bob :

                                         bob_results, secret_key, secret_key_error_rate = bob_protocol(qchannel, cchannel, num_qubits, loss_model, noise_model)

                                         print("Le message d'Alice avant chiffrement est le suivant : ",message)

                                         print("\nTaux d'erreur de la clé secrète : ", secret_key_error_rate,"\n")

                                        

                                         # Vérification si la clé secrète est générée :

                                         if secret_key is None:

                                                             print("La clé secrète n'a pas pu être générée.")                  

                                                            

                                         # Conversion du message en bits :

                                         message_bits = ''.join(format(ord(c), '08b') for c in message)

                                         if secret_key is not None:

                                                             encrypted_message = encrypt_message(message_bits, secret_key)

                                         else:

                                                             encrypted_message = None

                                         # Envoi du message chiffré :

                                         cchannel.send(encrypted_message)

                                        

                                         # Réception du message par Bob :

                                         message_reçu_t = cchannel.receive()

                                         message_reçu = [msg for msg in message_reçu_t[0]]

                                        

                                         # On transforme le tableau de bit en chaine de bit :

                                         message_reçu = ''.join(message_reçu)

                                         print("Le message reçu par Bob sur le canal classique est : ", message_reçu,"\n")

                                        

                                         # Déchiffrement du message :

                                         if secret_key is not None:

                                                             decrypted_message = decrypt_message(message_reçu, secret_key)

                                                             # Conversion des bits en texte :

                                                             decrypted_text = ''.join(chr(int(decrypted_message[i:i+8], 2)) for i in range(0, len(decrypted_message), 8))

                                                             print("Le message est donc déchiffré par Bob avec la clé secrète : ",decrypted_text,"\n")

                                         elif choice.lower() != 'y':

                                                             print("Trop de qubits perdus !!! \n")

                                         elif choice.lower() == 'y' and attaque == length:

                                                             eve_attaque = " ??????????? "                                           

                                                             print("\nL'attaque a eu lieue à une longueur de fibre de ",length,"Km le message est illisible : ",eve_attaque,"\n")

                                         else:

                                                             print("Trop de qubits perdus !!! \n")

                                                            

                                         end_time = time.time()

                                         execution_time = end_time - start_time

                                        

                                         if bob_results is not None:

                                                             loss_count = num_qubits - len(bob_results)

                                                             loss_rate = loss_count / num_qubits

                                                             loss_counts.append(loss_count)

                                                             print(f"Nombre de qubits envoyés : {num_qubits}")

                                                             print(f"Nombre de qubits reçus : {len(bob_results)}")

                                                             print(f"Nombre de qubits perdus : {loss_count}")

                                                             print(f"Taux de perte : {loss_rate}")

                                                             print(f"Temps d'exécution : {execution_time}\n")

                                         else:

                                                             loss_count = 0

                                                             loss_rate = 1

                                                             loss_counts.append(loss_count)

                                                             print(f"Nombre de qubits envoyés : {num_qubits}")

                                                             print(f"Nombre de qubits reçus : ?")

                                                             print(f"Nombre de qubits perdus : ?")

                                                             print(f"Taux de perte : {loss_rate}")

                                                             print(f"Temps d'exécution : {execution_time}\n")

                                                            

                                        

                                         # Ajout du taux de perte à la liste :

                                         loss_rates.append(loss_rate)

                                         secret_key_error_rates.append(secret_key_error_rate)                        

                                         execution_times.append(execution_time)

                    # Affichage des résultats :

                    print("\n################## Affichage des résultats #####################\n")

                    for length, loss_rate, secret_key_error_rate in zip(fibre_lengths, loss_rates, secret_key_error_rates):

                                         print(f"Longueur de fibre : {length} km")

                                         print(f"Taux de perte : {loss_rate*100}%")

                                         print(f"Taux d'erreur de la clé secrète : {secret_key_error_rate}")

                                         print()

                    if choice.lower() == 'y' :

                                         print("/!\  /!\ L'attaque a eu lieue à : ",attaque,"km ! /!\  /!\\")

                   

                    # Définition de la couleur de fond du graphe :

                    plt.rcParams['axes.facecolor'] = 'black'

                   

                    # Générer un identifiant unique basé sur la date et l'heure actuelles :

                    timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")

                   

                    # Tracé du taux de perte en fonction de la longueur de fibre :

                    plt.figure(figsize=(20, 5))

                    plt.subplot(1, 3, 1)

                    plt.plot(fibre_lengths, loss_rates, marker='o', color='red', label='Taux de perte')

                    plt.xlabel("Longueur de fibre (km)")

                    plt.ylabel("Taux de perte")

                    plt.title("Taux de perte de qubits en fonction de la longueur de fibre")

                    plt.legend(loc='upper right', facecolor='red')

                    # Tracé du temps d'exécution en fonction de la longueur de fibre :

                    plt.subplot(1, 3, 2)

                    plt.plot(fibre_lengths, execution_times, marker='o', color='cyan', label='Temps d\'exécution')

                    plt.xlabel("Longueur de fibre (km)")

                    plt.ylabel("Temps d'exécution (s)")

                    plt.title("Temps d'exécution en fonction de la longueur de fibre")

                    plt.legend(loc='upper right', facecolor='cyan')

                    # Tracé du temps d'exécution en fonction de la longueur de fibre :

                    plt.subplot(1, 3, 3)

                    plt.plot(fibre_lengths, secret_key_error_rates, marker='o', color='purple', label='Taux d\'erreur de la clé')

                    plt.xlabel("Longueur de fibre (km)")

                    plt.ylabel("Taux d'erreur de la clé")

                    plt.title("Taux d'erreur de la clé en fonction de la longueur de fibre")

                    plt.legend(loc='upper right', facecolor='purple')

                    # plt.tight_layout()

                    # plt.show()

                    # Enregistrement des graphiques dans une image :

                    output_dir = "output"

                    os.makedirs(output_dir, exist_ok=True)

                    output_file = os.path.join(output_dir, "bb84_results_{}.png".format(timestamp))

                    plt.savefig(output_file)

                    plt.tight_layout()

                    plt.show()

                    #plt.close()

                    print("Les graphiques ont été enregistrés dans l'image :", output_file)

                   

if __name__ == "__main__":

                    main()

 

 Annexe 1 les proprietes des atomesAnnexe 1 les proprietes des atomes (132.1 Ko)

Annexe 2 le protocole bb84Annexe 2 le protocole bb84 (803.79 Ko)

Annexe 3 le protocole e91Annexe 3 le protocole e91 (182.59 Ko)

Annexe 4 le protocole sarg04Annexe 4 le protocole sarg04 (490.41 Ko)

Annexe 5 les differences fondamentales entre les reseaux classiques et quantiquesAnnexe 5 les differences fondamentales entre les reseaux classiques et quantiques (196.98 Ko)

Annexe 6 mise en place du contexte technologiqueAnnexe 6 mise en place du contexte technologique (344.25 Ko)

Ajouter un commentaire