Beruflich Dokumente
Kultur Dokumente
Le programme fournit une fonction de déchiffrement (enc, dec, n, clé) pour déchiffrer un message
chiffré à partir de la clé :
• dec est un pointeur vers une zone mémoire de n octets (la même longueur que le message
chiffré), qui doit être pré-allouée par l'appelant, et qui à la fin de l'appel contiendra le
message déchiffré ;
• key est le pointeur vers la clé à utiliser pour déchiffrer; la clé a une longueur de 8 octets.
L'algorithme de décryptage utilisé (Data Encryption Standard, DES) produit toujours un message
décrypté avec n'importe quelle clé ; si la clé n'est pas la bonne, le message déchiffré contiendra des
caractères "absurdes". Dans notre cas, le message en clair est une chaîne de texte (terminée par un \0,
imprimable par printf()), dont les dix premiers caractères sont «0123456789» (sans guillemets).
Écrivez un programme pour effectuer une attaque "force brute" sur l'espace clé, en exploitant le
parallélisme OpenMP. Le programme doit essayer toutes les clés possibles de 00000000 à 99999999,
jusqu'à ce qu'il reçoive un message déchiffré commençant par la séquence «0123456789» ; trouvé la
clé, le programme doit imprimer le message déchiffré, qui est une citation d'un ancien film.
Notez que, en raison des caractéristiques de l'algorithme de chiffrement utilisé, il existe 28 = 256 clés
différentes qui déchiffrent correctement le message ; ceci est dû au fait que l'algorithme ignore le
huitième bit de chaque octet de la clé (la longueur réelle de la clé est donc de 56 bits au lieu de 64).
Pour les besoins de l'exercice, il suffit de trouver l'une des clés de déchiffrement correctes.
Il est conseillé d'utiliser une construction omp parallel en insérant dans quel code affectant un sous-
ensemble approprié de l'espace clé à chaque thread. Cependant, rappelez-vous que la construction
omp parallel s'applique aux blocs structurés, c'est-à-dire aux blocs avec un seul point d'entrée et un
seul point de sortie. Ainsi, un thread qui a trouvé la clé correcte ne peut pas quitter le bloc avec return,
break ou goto car cela devrait provoquer une erreur de compilation. Comme nous ne voulons pas
attendre que tous les threads aient exploré tout l'espace clé pour terminer, vous devez mettre en œuvre
un mécanisme de signalement pour qu'ils arrêtent dès que l'un des threads trouve la clé. Aucune
solution brutale comme exit() ou abort() n'est autorisée pour terminer le programme.
! 𝑣1[𝑖] × 𝑣2[𝑖]
$%&
Parallélisez la version série, en utilisant initialement la construction omp parallel avec les clauses que
vous jugez appropriées. Vous pouvez procéder comme suit : soit P le nombre de threads OpenMP, le
programme doit logiquement partitionner le tableau en P blocs de taille approximativement uniforme.
Le p-ième thread (0 ≤ p <P) calcule une partie du produit scalaire correspondant à la somme des
produits des éléments de v1[] et v2[] des indices my_start, ..., my_end-1, soit :
my_end"#
Il existe plusieurs façons d'accumuler des résultats partiels. Une possibilité est que la valeur calculée
par le p-ième thread soit stockée dans l'élément partial_p[p], où partial_p[] est un tableau de longueur
P. De cette façon, chaque thread gère un élément différent de partial_p[] et aucune condition de
concurrence ne se produit. Le maître calcule ensuite la somme des valeurs dans partial_p[],
déterminant ainsi le résultat recherché. Faites attention à gérer correctement le cas où la longueur n
des tableaux n'est pas un multiple de P. Une solution plus pratique consiste à utiliser la clause
reduction(), vous pouvez essayer les deux solutions.
MergeSort
Le fichier omp-mergesort.c contient une implémentation récursive de l'algorithme MergeSort (des
détails de l'algorithme se trouvent dans les commentaires du code source).
Paralléliser le programme à l'aide des tâches OpenMP, en vous assurant que chaque appel récursif
est délégué à une tâche OpenMP. Vérifiez si la version parallèle est plus rapide ou plus lente que la
version série en faisant varier le nombre de threads OpenMP. Utilisez une longueur appropriée pour
le tableau, afin d'obtenir des temps d'exécution pas trop courts (risque de variabilité excessive).