Écrire le code de la fonction expo qui prend en paramètres trois entiers g, a et p et qui calcule \(\texttt{g}^{\texttt{a}} \text{ mod } \texttt{p}\).
Au lieu de calculer les puissances successives, nous allons utiliser la formule récursive suivante :
\[
\texttt{expo}(x,n)=\left\{\begin{array}{ll} 1 & \text{si $n=0$}\\%
\texttt{expo}(x,n/2)^2 \text{ mod } p & \text{si $n$ est pair}\\%
x\times \texttt{expo}(x,n-1) \text{ mod } p & \text{si $n$ est impair} \end{array} \right.%
\]
Pour obtenir l'inverse d'un élément \(a\) de \(\mathbb{Z}/p\mathbb{Z}^*\), on peut utiliser la fonction ci-dessous, qui se base sur le lemme de Bezout :
###(Dés-)Active le code après la ligne # Tests (insensible à la casse) (Ctrl+I)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Évaluations restantes : ∞/∞
Exercice 13
On prend \(p=17\) et \(g=3\).
Choisir un nombre \(a\) et calculer \(A=g^a \text{ mod } p\).
Choisir un nombre \(b\) et calculer \(B=g^b \text{ mod } p\).
Vérifier que \(A^b= B^a \text{ mod } p\). On note \(S\) cette valeur.
Calculer l'inverse \(I\) de \(S\).
Calculer \(M=13\times S \text{ mod } p\).
Vérifier que \(M\times I=13 \text{ mod } p\).
###(Dés-)Active le code après la ligne # Tests (insensible à la casse) (Ctrl+I)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Évaluations restantes : ∞/∞
Exercice 14
On prend \(p=1033036853900310486020332713091\) et \(g=904062654916588875097610847452\).
Les nombres étant bien plus grands, on utilisera la fonction pow de Python, semblable à expo, mais qui est vraiment plus rapide.
Choisir un nombre \(a\), avec au moins 15 chiffres, et calculer \(A=g^a \text{ mod } p\).
Choisir un nombre \(b\), avec au moins 15 chiffres, et calculer \(B=g^b \text{ mod } p\).
Vérifier que \(A^b = B^a \text{ mod } p\). On note \(S\) cette valeur.
Calculer l'inverse \(I\) de \(S\).
Calculer \(M=464642165186863213175463\times S \text{ mod } p\).
Vérifier que \(M\times I = 464642165186863213175463 \text{ mod } p\).
###(Dés-)Active le code après la ligne # Tests (insensible à la casse) (Ctrl+I)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Tester votre fonction avec \(p = 733336898214308139427731599029\).
Il vaut mieux faire ce calcul en utilisant Thonny.
Le test de Miller-Rabin
Afin de pouvoir tester la primalité de très grand nombres, il faut utiliser une autre approche. Le test de Miller-Rabin est un test probabiliste très efficace. Il teste une propriété qui est fausse pour tous les nombres premiers. Par contre, pour les nombres composés il y a environ une chance sur quatre qu'elle soit fausse. En répétant le test \(k\) fois, on a une probabilité de se tromper d'environ \(\dfrac1{4^k}\). En prenant \(k=40\), on obtient une probabilité d'erreur de \(10^{-24}\).
Voici le code de ces fonctions :
###(Dés-)Active le code après la ligne # Tests (insensible à la casse) (Ctrl+I)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Évaluations restantes : ∞/∞
Afin d'accélérer l'exécution de cette fonction, on utilise la fonction Python pow telle que pow(a,b,n) correspond à \(\texttt{a}^\texttt{b} \text{ mod } \texttt{p}\). Cette fonction est bien plus rapide que celle que nous avons définie à l'exercice 12.
Exercice 17
Utiliser la fonction miller_rabin pour vérifier les résultats suivants et surtout vérifier le temps de calcul :
Quel est le plus petit entier, en base 10, qui s'écrit avec \(b\) bits dont le premier est \(1\).
Quel est le plus grand entier, en base 10, qui s'écrit avec \(b\) bits.
Solutions
Le plus petit entier est \(2^{\texttt{b}-1}\) et le plus grand est \(2^\texttt{b}-1\).
Exercice 19
Compléter le code de la fonction premier_taille qui prend en paramètre un entier b et qui renvoie un nombre premier choisi au hasard parmi tous ceux de b bits qui commencent par un 1.
Pour rappel random.randint(c, d) renvoie un entier tiré au hasard entre c et d inclus.
Puisque les nombres sont tirés au hasard, les résultats peuvent varier
>>> premier_taille(10)661>>> premier_taille(10)647>>> premier_taille(100)1264383536311359875787536761049>>> premier_taille(1024)# un peu plus long à calculer165737916444301193044460742780899652530354619391223623765834568675196139356175900709663498217845178532277343297986513424543708221594920253447061983381827932895931423676534928877952951269166580877381564589035794053286650862358642965817560049798738550370335180891383427376738817923530077262629789798946428015291
###(Dés-)Active le code après la ligne # Tests (insensible à la casse) (Ctrl+I)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Écrire le code de la fonction entier_binaire qui prend en paramètres un entier nb et un entier optionnel taille (qui vaut par défaut 8) et qui renvoie l'écriture binaire de nb sous forme de texte de longueur taille bits. On suppose que nb peut être écrit sur taille bits.
###(Dés-)Active le code après la ligne # Tests (insensible à la casse) (Ctrl+I)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Pour les exercices suivants, vous pourrez aussi utiliser la fonction entier_binaire_compl qui prend en paramètres un entier nb et un entier optionnel taille et qui renvoie l'écriture en binaire de nb avec le plus petit multiple de taille bits possible.
Vous pourrez utiliser cette fonction dans les exercices qui le nécessiteront.
Exercice 21
Écrire le code de la fonction binaire_entier qui prend un texte nb_b correspondant à un nombre binaire et qui renvoie l'entier correspondant en base 10.
On rappelle que int(t) permet d'obtenir l'entier correspondant au texte t. Ainsi int("15") vaut 15.
Pour pouvoir chiffrer un texte, il faut pouvoir transformer en binaire puis en nombre et réciproquement. Pour rappel pour obtenir le point de code associé à un symbole, il faut utiliser la fonction ord(symbole). Pour obtenir le symbole à partir du point de code, il faut faire chr(nb).
Exercice 22
Écrire le code de la fonction texte_binaire qui prend en paramètre une chaîne de caractères texte et qui renvoie un texte correspondant à la concaténation de tous les points de code des symboles de texte écrits en binaire.
On suppose que tous les symboles utilisés ont un point de code inférieur à 255 et doivent être représentés sur 8 bits. Cela correspond aux symboles de la table latin-1, qui inclue les accents utilisés en français.
###(Dés-)Active le code après la ligne # Tests (insensible à la casse) (Ctrl+I)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Évaluations restantes : 5/5
.1280132b=_(g"md/135h+Pw4k6urvx&:iSt)
f qp7;snyoal.ec010b0L0v0I0t0J0E0z0M0J0I0E0E05090v0t0B09000x010E0n0a0a0I0o0G000u0H0J0n0%0H0F010c0,0.0:0=0*0b0t0p0z0/0o0l0b0H0j0F0#0d090z0E0v0G0J0L0#1a080t0F0s0d0K0C0L0a0z0d1z1j0)0N170V0X0Z0#0g0t080g0J1N0g0v0(010Q041o1I0Y0!091M1O1Q1O0v1W1o1U0v0o001V0g0V0^0E0B0I1g09031j0W1!0#0y0S0L0F0I0a0L1U1@1_1Z1K09221o25270(020z0i0o0H0B0H0E0t0{0F0z0O1=0o0o0L0M2t0~2a0F1/0c0v0g2G1-1/2L1V0b2c1#1Q0F242q1U16181~2d2S2U2X1U0B2z1/2E2G2*0+1^2u2Z1#0F0H0o0/0J0(0d2D2.1F2E2Q0#2=2@0I2_00032|1_2~2.3109332^0(0e392F0*302:322?3g000k3j3b2b3n3e3p350(0f3t3l3c3w3f3z000m3t0~2'0L2G2X2K0b2M2P3w0M0H0O2W171/3M2)2}3K3V0O3$3v1J1#0l0(0O0y3t0z2-3*203e0y0(0v0L0q3|06041t0R2z3K3m3+0#0'0007463E483e3{3}3|4d3@2d4a0w0s3C0z4r3=473^0F0(2z0E3;3?2/4f0H0(054A4u2d0E1|000r0A0n0H0v0D4N4P4R4q4s4B3d3-000y2?4H4e4v0(0E0G0a040^0L4&4l1#1e0(1t4:4C4(003|3~4/103%4I1#4a4p513a0x4s5a4t4'2d4w000F044_3d4E004G572F5c4;32040(2?0b4k4`4m0(4c5o3)5y2;4)4+4-1o5x3d4n4W5b5q5E324x0L4z5C5P5k4F5j3F5S5U2*5W3w5l0h5Z4f5f240%0L0o41430t455C4Y3w4a5B2,535R5g5i5^5~095M5C594X644!2z0v0n0o0}5V5_5+5#3C0~3'3N3L2(0~3P0~0v3R6t1.6t0I1X6o0c3P0*6C3Z6E0O0Q0S0E00
###(Dés-)Active le code après la ligne # Tests (insensible à la casse) (Ctrl+I)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Afin de trouver un générateur de \(\mathbb{Z}/p\mathbb{Z}^*\), avec \(p\) premier, on utilise le fait que l'ordre d'un générateur d'un groupe divise l'ordre de ce groupe. Donc si \(g\) n'est pas un générateur de \(\mathbb{Z}/p\mathbb{Z}^*\), alors l'ordre de \(g\) doit diviser \(p-1\). Or, si on prend \(p>2\), alors \(p-1\) est pair. On peut donc tester si l'ordre de \(g\) n'est ni \(2\), ni \(\dfrac{n-1}2\). Cela ne garantit pas que \(g\) est un générateur, mais cela en enlève un certain nombres qui ne le sont pas.
Nous avons maintenant tout ce qu'il faut pour pouvoir chiffrer et déchiffrer avec une clef créée par le protocole de Diffie-Hellman, si la taille du message est inférieure à la taille de la clef.
# Tests
(insensible à la casse)(Ctrl+I)