<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Mathematics on kenji.blog</title><link>http://kenji.blog/fr/categories/mathematics/</link><description>Recent content in Mathematics on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>fr</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 22:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/fr/categories/mathematics/index.xml" rel="self" type="application/rss+xml"/><item><title>Fondements et implémentation de la cryptographie à l'aide du petit théorème de Fermat</title><link>http://kenji.blog/fr/p/fermats-little-theorem-cryptography-implementation/</link><pubDate>Fri, 11 Sep 2026 22:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/fermats-little-theorem-cryptography-implementation/</guid><description>&lt;img src="http://kenji.blog/p/fermats-little-theorem-cryptography-implementation/img/eyecatch.jpg" alt="Featured image of post Fondements et implémentation de la cryptographie à l'aide du petit théorème de Fermat" />&lt;h2 id="1-introduction--le-mystère-mathématique-qui-sous-tend-la-cryptographie-moderne">1. Introduction : Le mystère mathématique qui sous-tend la cryptographie moderne
&lt;/h2>&lt;p>Dans la société numérique d&amp;rsquo;aujourd&amp;rsquo;hui, et particulièrement dans les communications sur Internet, le &amp;ldquo;chiffrement&amp;rdquo; est devenu une technologie fondamentale indispensable. Le fait que nous puissions naviguer en toute sécurité sur des sites web via HTTPS dans nos navigateurs, effectuer des transactions financières par le biais des services bancaires en ligne, et avoir des échanges privés sur des applications de messagerie est dû aux protocoles cryptographiques basés sur des théories mathématiques avancées fonctionnant en arrière-plan. Parmi ceux-ci, la &amp;ldquo;cryptographie à clé publique&amp;rdquo; joue un rôle particulièrement important, dont le représentant le plus célèbre est le &lt;strong>chiffrement RSA&lt;/strong>.&lt;/p>
&lt;p>La sécurité et la validité de nombreux algorithmes cryptographiques, y compris RSA, dépendent fortement d&amp;rsquo;un théorème extrêmement beau et puissant découvert par le mathématicien français du 17e siècle, Pierre de Fermat. Il s&amp;rsquo;agit du &lt;strong>petit théorème de Fermat (Fermat&amp;rsquo;s Little Theorem)&lt;/strong>. De plus, le théorème de Leonhard Euler, qui généralise ce théorème, joue également un rôle décisif dans la théorie cryptographique.&lt;/p>
&lt;p>Cet article explique en détail, depuis les bases, comment la découverte mathématique pure qu&amp;rsquo;est le petit théorème de Fermat s&amp;rsquo;applique aux technologies cryptographiques pratiques modernes, en particulier aux &amp;ldquo;tests de primalité&amp;rdquo; et au &amp;ldquo;chiffrement RSA&amp;rdquo;. Il s&amp;rsquo;agit d&amp;rsquo;un guide technique très détaillé couvrant tout, des preuves mathématiques, aux mécanismes de chiffrement et de déchiffrement, jusqu&amp;rsquo;à l&amp;rsquo;implémentation concrète des algorithmes en C++ et Python.&lt;/p>
&lt;hr>
&lt;h2 id="2-bases-des-congruences-et-de-larithmétique-modulaire">2. Bases des congruences et de l&amp;rsquo;arithmétique modulaire
&lt;/h2>&lt;p>Pour comprendre le petit théorème de Fermat, vous devez d&amp;rsquo;abord vous familiariser avec le concept mathématique d&amp;rsquo;&amp;ldquo;arithmétique modulaire (congruences)&amp;rdquo;. L&amp;rsquo;arithmétique modulaire est un système de calcul qui se concentre sur le &amp;ldquo;reste&amp;rdquo; lorsqu&amp;rsquo;un nombre est divisé par un nombre fixe (appelé module). Comme il s&amp;rsquo;agit d&amp;rsquo;un calcul similaire à celui du cadran d&amp;rsquo;une horloge (qui fait un tour en 12 heures), on l&amp;rsquo;appelle aussi parfois &amp;ldquo;mathématiques de l&amp;rsquo;horloge&amp;rdquo;.&lt;/p>
&lt;p>Lorsque le reste de la division de deux entiers $a$ et $b$ par un entier positif $n$ est égal, on l&amp;rsquo;écrit mathématiquement comme suit :&lt;/p>
$$
a \equiv b \pmod n
$$
&lt;p>Cela se lit &amp;ldquo;$a$ et $b$ sont congrus modulo $n$&amp;rdquo;. Par exemple, le reste de 17 divisé par 5 est 2, et le reste de 12 divisé par 5 est également 2. Par conséquent, on peut écrire ce qui suit :&lt;/p>
$$
17 \equiv 12 \pmod 5 \equiv 2 \pmod 5
$$
&lt;p>En arithmétique modulaire, les quatre opérations arithmétiques habituelles (addition, soustraction, multiplication) s&amp;rsquo;appliquent telles quelles.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Addition&lt;/strong> : Si $a \equiv b \pmod n$ et $c \equiv d \pmod n$, alors $a + c \equiv b + d \pmod n$&lt;/li>
&lt;li>&lt;strong>Soustraction&lt;/strong> : Si $a \equiv b \pmod n$ et $c \equiv d \pmod n$, alors $a - c \equiv b - d \pmod n$&lt;/li>
&lt;li>&lt;strong>Multiplication&lt;/strong> : Si $a \equiv b \pmod n$ et $c \equiv d \pmod n$, alors $a \times c \equiv b \times d \pmod n$&lt;/li>
&lt;li>&lt;strong>Exponentiation&lt;/strong> : Si $a \equiv b \pmod n$, alors pour tout entier naturel $k$, $a^k \equiv b^k \pmod n$&lt;/li>
&lt;/ol>
&lt;p>Cependant, il faut faire attention à la &lt;strong>division&lt;/strong>. En général, même si $a \times c \equiv b \times c \pmod n$, vous ne pouvez pas diviser les deux côtés par $c$ pour obtenir $a \equiv b \pmod n$. Cela n&amp;rsquo;est vrai que si $c$ et $n$ sont premiers entre eux (leur plus grand commun diviseur est 1). Ce concept d&amp;rsquo;&amp;ldquo;inverse modulaire&amp;rdquo; devient extrêmement important dans la génération de clés pour le chiffrement RSA, que nous aborderons plus tard.&lt;/p>
&lt;hr>
&lt;h2 id="3-contexte-mathématique-et-preuve-du-petit-théorème-de-fermat">3. Contexte mathématique et preuve du petit théorème de Fermat
&lt;/h2>&lt;p>Maintenant que nous avons couvert les bases de l&amp;rsquo;arithmétique modulaire, examinons le sujet principal, le petit théorème de Fermat.&lt;/p>
&lt;h3 id="31-définition-du-théorème">3.1 Définition du théorème
&lt;/h3>&lt;p>Le petit théorème de Fermat est formulé comme suit :&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Petit théorème de Fermat (Fermat&amp;rsquo;s Little Theorem)&lt;/strong>
Soit $p$ un nombre premier et $a$ un entier quelconque qui n&amp;rsquo;est pas un multiple de $p$ (c&amp;rsquo;est-à-dire que $a$ et $p$ sont premiers entre eux). Alors, la congruence suivante est vraie :
&lt;/p>
$$ a^{p-1} \equiv 1 \pmod p $$
&lt;/blockquote>
&lt;p>Il est également courant d&amp;rsquo;exprimer ce théorème sous une forme valable pour tout entier $a$, en supprimant la condition &amp;ldquo;$a$ n&amp;rsquo;est pas un multiple de $p$&amp;rdquo;. Dans ce cas, on multiplie les deux côtés par $a$, ce qui donne :&lt;/p>
$$
a^p \equiv a \pmod p
$$
&lt;h3 id="32-vérification-par-des-exemples-concrets">3.2 Vérification par des exemples concrets
&lt;/h3>&lt;p>Vérifions si le théorème se vérifie vraiment en utilisant des nombres concrets.
Soit le nombre premier $p = 5$. Alors $p-1 = 4$. Nous choisissons un entier pour $a$ qui n&amp;rsquo;est pas un multiple de $p$.&lt;/p>
&lt;ul>
&lt;li>Pour $a = 2$ : $2^{5-1} = 2^4 = 16$. $16 \div 5 = 3$ avec un reste de $1$. Donc $16 \equiv 1 \pmod 5$. (Vérifié)&lt;/li>
&lt;li>Pour $a = 3$ : $3^{5-1} = 3^4 = 81$. $81 \div 5 = 16$ avec un reste de $1$. Donc $81 \equiv 1 \pmod 5$. (Vérifié)&lt;/li>
&lt;li>Pour $a = 4$ : $4^{5-1} = 4^4 = 256$. $256 \div 5 = 51$ avec un reste de $1$. Donc $256 \equiv 1 \pmod 5$. (Vérifié)&lt;/li>
&lt;/ul>
&lt;p>Ainsi, quel que soit le $a$ que vous choisissez (à condition qu&amp;rsquo;il ne soit pas un multiple de 5), le reste de sa 4ème puissance divisée par 5 sera toujours 1. Cela ressemble à de la magie, mais cela découle des magnifiques propriétés des nombres premiers.&lt;/p>
&lt;h3 id="33-preuve-mathématique-du-théorème">3.3 Preuve mathématique du théorème
&lt;/h3>&lt;p>Pourquoi cela est-il vrai ? Nous présentons ici une preuve élégante utilisant l&amp;rsquo;ensemble des classes de restes.&lt;/p>
&lt;p>Considérons l&amp;rsquo;ensemble $S = \{1, 2, 3, \dots, p-1\}$. Ce sont les représentants des entiers dont les restes de la division par $p$ vont de $1$ à $p-1$.
Considérons maintenant un nouvel ensemble $T$ obtenu en multipliant chaque élément par un entier $a$ qui est premier avec $p$.
&lt;/p>
$$ T = \{1a, 2a, 3a, \dots, (p-1)a\} $$
&lt;p>Considérons les restes de chaque élément de cet ensemble $T$ divisé par $p$. Étonnamment, ces restes, bien que leur ordre puisse changer, correspondent exactement à l&amp;rsquo;ensemble des éléments de l&amp;rsquo;ensemble d&amp;rsquo;origine $S$.
Pourquoi ?&lt;/p>
&lt;ol>
&lt;li>Les éléments de $T$ ne peuvent jamais être des multiples de $p$ (car ni $a$ ni les éléments d&amp;rsquo;origine ne sont des multiples de $p$).&lt;/li>
&lt;li>Il n&amp;rsquo;y a pas deux éléments distincts dans $T$ qui sont congrus modulo $p$. Si $ia \equiv ja \pmod p$ ($i \neq j$), puisque $a$ et $p$ sont premiers entre eux, nous pouvons diviser par $a$ pour obtenir $i \equiv j \pmod p$, ce qui est une contradiction.&lt;/li>
&lt;/ol>
&lt;p>Par conséquent, le produit de tous les éléments de $S$ et le produit de tous les éléments de $T$ sont congrus modulo $p$.&lt;/p>
$$
(1a) \times (2a) \times \dots \times ((p-1)a) \equiv 1 \times 2 \times \dots \times (p-1) \pmod p
$$
&lt;p>En réorganisant le côté gauche, puisqu&amp;rsquo;il y a $p-1$ termes de $a$,&lt;/p>
$$
a^{p-1} \cdot (p-1)! \equiv (p-1)! \pmod p
$$
&lt;p>Comme $(p-1)!$ est premier avec $p$, nous pouvons diviser les deux côtés par $(p-1)!$, ce qui conduit finalement au théorème suivant :&lt;/p>
$$
a^{p-1} \equiv 1 \pmod p
$$
&lt;p>Ceci est la preuve du petit théorème de Fermat.&lt;/p>
&lt;hr>
&lt;h2 id="4-la-fonction-indicatrice-deuler-et-le-théorème-deuler">4. La fonction indicatrice d&amp;rsquo;Euler et le théorème d&amp;rsquo;Euler
&lt;/h2>&lt;p>Le petit théorème de Fermat est un théorème concernant &amp;ldquo;un nombre premier $p$&amp;rdquo;, mais il a été généralisé à &amp;ldquo;tout entier positif $n$&amp;rdquo; par Leonhard Euler. Cette extension est essentielle pour comprendre le chiffrement RSA.&lt;/p>
&lt;h3 id="41-la-fonction-indicatrice-deuler-phin">4.1 La fonction indicatrice d&amp;rsquo;Euler $\phi(n)$
&lt;/h3>&lt;p>La fonction indicatrice d&amp;rsquo;Euler (ou fonction $\phi$ d&amp;rsquo;Euler) $\phi(n)$ est une fonction qui représente &amp;ldquo;le nombre d&amp;rsquo;entiers de $1$ à $n$ qui sont premiers avec $n$&amp;rdquo;.&lt;/p>
&lt;ul>
&lt;li>Dans le cas d&amp;rsquo;un nombre premier $p$, puisque tous les entiers de $1$ à $p-1$ sont premiers avec $p$, $\phi(p) = p - 1$.&lt;/li>
&lt;li>Pour le produit de deux nombres premiers distincts $p$ et $q$, c&amp;rsquo;est-à-dire $n = p \times q$, $\phi(n)$ peut être calculé avec une formule très simple :
$$ \phi(p \times q) = \phi(p) \times \phi(q) = (p - 1)(q - 1) $$&lt;/li>
&lt;/ul>
&lt;p>Cette propriété est la logique fondamentale derrière la génération de clés dans le chiffrement RSA.&lt;/p>
&lt;h3 id="42-le-théorème-deuler">4.2 Le théorème d&amp;rsquo;Euler
&lt;/h3>&lt;p>Euler a généralisé le petit théorème de Fermat comme suit :&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Théorème d&amp;rsquo;Euler (Euler&amp;rsquo;s Theorem)&lt;/strong>
Pour tout entier positif $n$ et tout entier $a$ qui lui est premier entre eux, ce qui suit est vrai :
&lt;/p>
$$ a^{\phi(n)} \equiv 1 \pmod n $$
&lt;/blockquote>
&lt;p>Si $n$ est un nombre premier $p$, alors $\phi(p) = p - 1$, donc cela devient exactement le petit théorème de Fermat ($a^{p-1} \equiv 1 \pmod p$). En d&amp;rsquo;autres termes, le petit théorème de Fermat n&amp;rsquo;est qu&amp;rsquo;un cas particulier du théorème d&amp;rsquo;Euler.&lt;/p>
&lt;hr>
&lt;h2 id="5-trouver-dénormes-nombres-premiers--le-test-de-primalité-de-fermat">5. Trouver d&amp;rsquo;énormes nombres premiers : Le test de primalité de Fermat
&lt;/h2>&lt;p>Dans les technologies cryptographiques (comme le chiffrement RSA et l&amp;rsquo;échange de clés Diffie-Hellman), il est nécessaire de trouver rapidement &amp;ldquo;d&amp;rsquo;énormes nombres premiers&amp;rdquo; s&amp;rsquo;étendant sur des centaines de chiffres. Cependant, utiliser la méthode de la &amp;ldquo;division par essais&amp;rdquo;, qui consiste à essayer de diviser par tous les nombres de $2$ à $\sqrt{N}$ pour déterminer si un grand nombre $N$ est premier, prendrait un temps équivalent à l&amp;rsquo;âge de l&amp;rsquo;univers.&lt;/p>
&lt;p>C&amp;rsquo;est là qu&amp;rsquo;intervient le &lt;strong>test de primalité de Fermat (Fermat Primality Test)&lt;/strong>, un &amp;ldquo;test de primalité probabiliste&amp;rdquo; qui utilise le petit théorème de Fermat à l&amp;rsquo;envers.&lt;/p>
&lt;h3 id="51-quest-ce-quun-test-de-primalité-probabiliste-">5.1 Qu&amp;rsquo;est-ce qu&amp;rsquo;un test de primalité probabiliste ?
&lt;/h3>&lt;p>Selon le petit théorème de Fermat, si $p$ est premier, alors $a^{p-1} \equiv 1 \pmod p$ est toujours vrai pour tout $a$ ($1 &lt; a &lt; p$).
La contraposée de cette affirmation est : &amp;ldquo;S&amp;rsquo;il existe un $a$ pour lequel $a^{p-1} \not\equiv 1 \pmod p$, alors $p$ &lt;strong>n&amp;rsquo;est absolument pas un nombre premier (c&amp;rsquo;est un nombre composé)&lt;/strong>&amp;rdquo;.&lt;/p>
&lt;p>Par conséquent, si vous voulez déterminer si $N$ est premier, vous choisissez quelques valeurs aléatoires de $a$, calculez $a^{N-1} \pmod N$ et vérifiez si le résultat est $1$. Si vous obtenez une réponse autre que $1$ ne serait-ce qu&amp;rsquo;une seule fois, il est certain que $N$ est un nombre composé. S&amp;rsquo;il vaut $1$ peu importe le nombre de fois que vous essayez, vous pouvez juger avec une forte probabilité que $N$ est &amp;ldquo;probablement premier&amp;rdquo;.&lt;/p>
&lt;h3 id="52-explication-de-lalgorithme-et-organigramme">5.2 Explication de l&amp;rsquo;algorithme et organigramme
&lt;/h3>&lt;p>L&amp;rsquo;algorithme du test de Fermat est le suivant :&lt;/p>
&lt;div class="mermaid">flowchart TD
Start["Début"] --> Input["Entrer le nombre à tester p et le nombre de tests k"]
Input --> LoopStart["Boucle de i = 0 à k-1"]
LoopStart --> Condition{"i &lt; k ?"}
Condition -- "Oui" --> RandomA["Choisir un entier aléatoire a dans la plage 1 &lt; a &lt; p-1"]
RandomA --> Calc["Calculer l'exponentiation modulaire a^(p-1) mod p"]
Calc --> CheckPrime{"Le résultat est-il 1 ?"}
CheckPrime -- "Non" --> ReturnComposite["p est un nombre composé (certain)"]
CheckPrime -- "Oui" --> Increment["Incrémenter i"]
Increment --> Condition
Condition -- "Non" --> ReturnPrime["p est probablement premier (probabiliste)"]
ReturnComposite --> End["Fin"]
ReturnPrime --> End&lt;/div>
&lt;h3 id="53-le-piège-des-nombres-de-carmichael-pseudo-premiers">5.3 Le piège des nombres de Carmichael (pseudo-premiers)
&lt;/h3>&lt;p>Bien que le test de Fermat soit extrêmement rapide, il présente un défaut majeur. Il existe des nombres diaboliques qui, bien qu&amp;rsquo;ils soient composés, satisfont $a^{N-1} \equiv 1 \pmod N$ pour tous les $a$. Ceux-ci sont appelés &lt;strong>nombres de Carmichael (Carmichael numbers)&lt;/strong>. Le plus petit nombre de Carmichael est $561$ ($3 \times 11 \times 17$).&lt;/p>
&lt;p>En raison de l&amp;rsquo;existence des nombres de Carmichael, un test de Fermat pur seul ne peut pas déterminer la primalité de manière absolue. C&amp;rsquo;est pourquoi, dans les systèmes cryptographiques réels (comme OpenSSL), le &lt;strong>test de primalité de Miller-Rabin (Miller-Rabin primality test)&lt;/strong>, qui est une version améliorée du test de Fermat, est utilisé en standard. Le test de Miller-Rabin peut détecter les nombres de Carmichael, réduisant ainsi la probabilité de fausse détection à presque zéro.&lt;/p>
&lt;h3 id="54-exponentiation-modulaire-rapide-méthode-dexponentiation-par-carrés">5.4 Exponentiation modulaire rapide (Méthode d&amp;rsquo;exponentiation par carrés)
&lt;/h3>&lt;p>Dans l&amp;rsquo;algorithme de test de primalité, il est nécessaire de calculer $a^{N-1} \pmod N$. Si $N$ est énorme, $a^{N-1}$ aura un nombre de chiffres astronomique et ne tiendra pas dans la mémoire d&amp;rsquo;un ordinateur.
La solution à ce problème est la &lt;strong>méthode d&amp;rsquo;exponentiation par carrés (Exponentiation by Squaring)&lt;/strong> ou exponentiation modulaire. En prenant le modulo (mod N) à chaque étape du calcul, la valeur est toujours maintenue plus petite que $N$, ce qui permet un calcul très rapide (complexité temporelle $O(\log N)$).&lt;/p>
&lt;hr>
&lt;h2 id="6-implémentation-du-test-de-primalité-et-de-lexponentiation-modulaire">6. Implémentation du test de primalité et de l&amp;rsquo;exponentiation modulaire
&lt;/h2>&lt;p>Maintenant, implémentons le test de primalité de Fermat et la méthode d&amp;rsquo;exponentiation par carrés en C++ et Python.&lt;/p>
&lt;h3 id="61-implémentation-en-c">6.1 Implémentation en C++
&lt;/h3>&lt;p>En C++, les types d&amp;rsquo;entiers standard ont tendance à déborder facilement, donc une bibliothèque d&amp;rsquo;entiers à précision multiple (comme GMP) est nécessaire pour manipuler des nombres géants. Cependant, pour comprendre l&amp;rsquo;algorithme, nous montrons ici une implémentation dans la limite des entiers 64 bits (&lt;code>unsigned long long&lt;/code>).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;random&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="k">namespace&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Exponentiation modulaire rapide (a^b mod m) - Exponentiation par carrés
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="nf">power_mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Si le bit de poids faible de b est 1, multiplier le résultat par a
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">__int128&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="n">result&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Extension en 128 bits pour éviter le débordement
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Élever a au carré
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">__int128&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="n">a&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Décaler b vers la droite (diviser par la moitié)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">/=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Test de primalité de Fermat
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">bool&lt;/span> &lt;span class="nf">fermat_is_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">iterations&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">random_device&lt;/span> &lt;span class="n">rd&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">mt19937_64&lt;/span> &lt;span class="n">gen&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">rd&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">uniform_int_distribution&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">dis&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">iterations&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dis&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">gen&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Si a^(p-1) mod p n&amp;#39;est pas 1, alors c&amp;#39;est un nombre composé
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">power_mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Probablement premier
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1000000007&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Nombre premier connu
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">fermat_is_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; is probably prime.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; is composite.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="62-implémentation-en-python">6.2 Implémentation en Python
&lt;/h3>&lt;p>En Python, le type entier standard prend en charge les entiers à précision multiple, il n&amp;rsquo;y a donc pas besoin de s&amp;rsquo;inquiéter du débordement. De plus, la fonction intégrée &lt;code>pow(a, b, m)&lt;/code> de Python utilise l&amp;rsquo;exponentiation par carrés en interne et est très rapide.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">random&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">fermat_is_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">iterations&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> Test de primalité probabiliste utilisant le test de Fermat
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">iterations&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Choisir un nombre aléatoire a entre 2 et p-2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Calculer a^(p-1) mod p. La fonction intégrée pow est rapide.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span> &lt;span class="c1"># Certitude que c&amp;#39;est un nombre composé&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">True&lt;/span> &lt;span class="c1"># Probablement premier&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Test&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">number_to_test&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">104729&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="n">fermat_is_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">number_to_test&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">number_to_test&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> est probablement premier.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">number_to_test&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> est un nombre composé.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="7-application-au-chiffrement-rsa--où-fermat-et-euler-se-rencontrent">7. Application au chiffrement RSA : Où Fermat et Euler se rencontrent
&lt;/h2>&lt;p>La plus grande application du petit théorème de Fermat (et du théorème d&amp;rsquo;Euler) est le &lt;strong>chiffrement RSA&lt;/strong>, développé en 1977 par Rivest, Shamir et Adleman.
Le chiffrement RSA est un système révolutionnaire de &amp;ldquo;cryptographie à clé publique&amp;rdquo;, qui réalise un mécanisme où la clé de chiffrement (clé publique) est rendue publique au monde entier, tandis que la clé de déchiffrement (clé privée) n&amp;rsquo;est connue que du destinataire.&lt;/p>
&lt;p>Cette asymétrie repose sur la sécurité computationnelle selon laquelle &amp;ldquo;la factorisation en nombres premiers de nombres composés géants est extrêmement difficile&amp;rdquo;.&lt;/p>
&lt;h3 id="71-fonctionnement-du-chiffrement-rsa-génération-de-clés-chiffrement-déchiffrement">7.1 Fonctionnement du chiffrement RSA (Génération de clés, Chiffrement, Déchiffrement)
&lt;/h3>&lt;p>Vérifions le flux de communication global du chiffrement RSA avec un diagramme de séquence Mermaid.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant Alice["Alice (Destinataire)"]
participant Bob["Bob (Expéditeur)"]
Alice->>Alice: "Générer d'énormes nombres premiers p, q"
Alice->>Alice: "Calculer N = p * q, φ(N) = (p-1)(q-1)"
Alice->>Alice: "Calculer la clé publique e et la clé privée d (e*d ≡ 1 mod φ(N))"
Alice->>Bob: "Envoyer la clé publique (N, e)"
Note over Bob: "Préparer le texte clair M (M &lt; N)"
Bob->>Bob: "Calculer le texte chiffré C = M^e mod N"
Bob->>Alice: "Envoyer le texte chiffré C"
Alice->>Alice: "Calculer le texte clair M = C^d mod N pour déchiffrer"&lt;/div>
&lt;p>Voici une explication des étapes mathématiques détaillées.&lt;/p>
&lt;h4 id="étape-1--génération-de-clés-travail-du-destinataire-alice">Étape 1 : Génération de clés (Travail du destinataire Alice)
&lt;/h4>&lt;ol>
&lt;li>Générer aléatoirement deux énormes nombres premiers $p$ et $q$ (c&amp;rsquo;est là que la méthode de test de primalité mentionnée ci-dessus est utilisée).&lt;/li>
&lt;li>Calculer leur produit $N = p \times q$. Ce $N$ est rendu public.&lt;/li>
&lt;li>En utilisant la fonction indicatrice d&amp;rsquo;Euler, calculer $\phi(N) = (p-1)(q-1)$.&lt;/li>
&lt;li>Choisir un entier $e$ (exposant public) qui est premier avec $\phi(N)$ (souvent $e = 65537$ est utilisé).&lt;/li>
&lt;li>Calculer l&amp;rsquo;inverse modulaire $d$ (exposant privé) de $e$. C&amp;rsquo;est-à-dire, trouver $d$ qui satisfait ce qui suit :
$$ e \cdot d \equiv 1 \pmod{\phi(N)} $$
&lt;strong>L&amp;rsquo;algorithme d&amp;rsquo;Euclide étendu&lt;/strong> est utilisé pour ce calcul.&lt;/li>
&lt;/ol>
&lt;p>La &lt;strong>clé publique est maintenant $(N, e)$&lt;/strong> et la &lt;strong>clé privée est $(N, d)$&lt;/strong>. ($p$, $q$, et $\phi(N)$ doivent être immédiatement détruits ou strictement dissimulés).&lt;/p>
&lt;h4 id="étape-2--chiffrement-travail-de-lexpéditeur-bob">Étape 2 : Chiffrement (Travail de l&amp;rsquo;expéditeur Bob)
&lt;/h4>&lt;p>Supposons que Bob veuille envoyer un message $M$ à Alice ($M$ est la version numérisée des caractères, avec $0 \le M &lt; N$).
Bob utilise la clé publique d&amp;rsquo;Alice $(N, e)$ pour effectuer le calcul suivant et créer le texte chiffré $C$.&lt;/p>
$$
C \equiv M^e \pmod N
$$
&lt;p>Ce $C$ est envoyé à Alice via le réseau.&lt;/p>
&lt;h4 id="étape-3--déchiffrement-travail-du-destinataire-alice">Étape 3 : Déchiffrement (Travail du destinataire Alice)
&lt;/h4>&lt;p>Alice, après avoir reçu le texte chiffré $C$, effectue le calcul suivant en utilisant sa clé privée $d$, qu&amp;rsquo;elle seule connaît.&lt;/p>
$$
M' \equiv C^d \pmod N
$$
&lt;p>Étonnamment, ce résultat de calcul $M'$ correspond parfaitement au message original $M$.&lt;/p>
&lt;h3 id="72-pourquoi-cela-peut-il-être-déchiffré--preuve-mathématique">7.2 Pourquoi cela peut-il être déchiffré ? (Preuve mathématique)
&lt;/h3>&lt;p>C&amp;rsquo;est ici que le petit théorème de Fermat (le théorème d&amp;rsquo;Euler) montre sa véritable valeur. Pourquoi $C^d \pmod N$ revient-il à $M$ ?&lt;/p>
&lt;p>Développons la formule de déchiffrement.
Puisque $C \equiv M^e \pmod N$,
&lt;/p>
$$ C^d \equiv (M^e)^d \equiv M^{ed} \pmod N $$
&lt;p>Lors de l&amp;rsquo;étape de génération de clés, nous avons choisi $d$ de sorte que $e \cdot d \equiv 1 \pmod{\phi(N)}$. Cela signifie qu&amp;rsquo;il existe un entier $k$ tel qu&amp;rsquo;il peut s&amp;rsquo;écrire comme suit :
&lt;/p>
$$ e \cdot d = 1 + k \cdot \phi(N) $$
&lt;p>En substituant cela dans la formule ci-dessus :
&lt;/p>
$$ M^{ed} = M^{1 + k \cdot \phi(N)} = M \cdot M^{k \cdot \phi(N)} = M \cdot (M^{\phi(N)})^k \pmod N $$
&lt;p>Ici, le &lt;strong>théorème d&amp;rsquo;Euler&lt;/strong> ($M^{\phi(N)} \equiv 1 \pmod N$) entre en jeu. (&lt;em>Strictement parlant, $M$ et $N$ doivent être premiers entre eux, mais dans RSA, la probabilité que $M$ et $N$ ne soient pas premiers entre eux est astronomiquement faible, et en utilisant le théorème des restes chinois, il peut être prouvé que cela est vrai même s&amp;rsquo;ils ne sont pas premiers entre eux&lt;/em>).&lt;/p>
&lt;p>En appliquant le théorème d&amp;rsquo;Euler, puisque $M^{\phi(N)} \equiv 1$,
&lt;/p>
$$ M \cdot (1)^k \equiv M \pmod N $$
&lt;p>$M$ est magnifiquement restauré ! Les propriétés des nombres que Fermat et Euler ont découvertes il y a des centaines d&amp;rsquo;années garantissent parfaitement la confidentialité des communications numériques modernes.&lt;/p>
&lt;hr>
&lt;h2 id="8-implémentation-jouet-du-chiffrement-rsa-python">8. Implémentation jouet du chiffrement RSA (Python)
&lt;/h2>&lt;p>Comme il est difficile de saisir cela uniquement en théorie, utilisons Python pour implémenter réellement le processus de génération de clés, de chiffrement et de déchiffrement RSA. Bien qu&amp;rsquo;il s&amp;rsquo;agisse d&amp;rsquo;une &amp;ldquo;implémentation jouet&amp;rdquo; à des fins éducatives, les mathématiques utilisées sont exactement les mêmes que les vraies.&lt;/p>
&lt;p>Nous inclurons également une implémentation de &amp;ldquo;l&amp;rsquo;algorithme d&amp;rsquo;Euclide étendu&amp;rdquo; pour trouver l&amp;rsquo;inverse modulaire $d$.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;span class="lnt">74
&lt;/span>&lt;span class="lnt">75
&lt;/span>&lt;span class="lnt">76
&lt;/span>&lt;span class="lnt">77
&lt;/span>&lt;span class="lnt">78
&lt;/span>&lt;span class="lnt">79
&lt;/span>&lt;span class="lnt">80
&lt;/span>&lt;span class="lnt">81
&lt;/span>&lt;span class="lnt">82
&lt;/span>&lt;span class="lnt">83
&lt;/span>&lt;span class="lnt">84
&lt;/span>&lt;span class="lnt">85
&lt;/span>&lt;span class="lnt">86
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">random&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Trouver le plus grand commun diviseur&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">b&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">a&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Algorithme d&amp;#39;Euclide étendu (trouver x, y pour ax + by = gcd(a,b))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Utilisé pour trouver d pour e*d ≡ 1 (mod φ(N))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">extended_gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">extended_gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">g&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">//&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">mod_inverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">extended_gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">g&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">Exception&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;L&amp;#39;inverse n&amp;#39;existe pas&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">phi&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Fonction de génération de nombres premiers (Version simplifiée : génère de petits nombres premiers)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">generate_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="kc">True&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">p&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">getrandbits&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Jugement simplifié au lieu du test de Fermat mentionné ci-dessus&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">p&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Génération de clés RSA&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">generate_keypair&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">16&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">p&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">generate_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">q&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">generate_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># S&amp;#39;assurer que p et q ne sont pas identiques&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">q&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">q&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">generate_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">q&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">phi&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">q&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># e est souvent un nombre premier comme 65537, mais ici il est choisi aléatoirement&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randrange&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">g&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randrange&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Calcul de la clé privée d&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">d&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod_inverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Clé publique (e, n), Clé privée (d, n)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">((&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">encrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pk&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">plaintext&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pk&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Calculer plaintext^e mod n&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cipher&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">ord&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">char&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">char&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">plaintext&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">cipher&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">decrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sk&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ciphertext&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sk&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Calculer cipher^d mod n et reconvertir en caractères&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">plain&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nb">chr&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">char&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">char&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">ciphertext&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">plain&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Exemple d&amp;#39;exécution&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;--- Implémentation jouet du chiffrement RSA ---&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">public_key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">private_key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">generate_keypair&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">12&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># Utilisation de nombres premiers de 12 bits&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Clé publique (e, n): &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">public_key&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Clé privée (d, n): &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">private_key&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Hello Math!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">Message d&amp;#39;origine : &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Chiffrement&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">encrypted_msg&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">encrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">public_key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Texte chiffré : &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">encrypted_msg&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Déchiffrement&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">decrypted_msg&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">decrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">private_key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">encrypted_msg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Message déchiffré : &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">decrypted_msg&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Lorsque vous exécutez ce code, vous pouvez voir le tableau de caractères être converti en un tableau de nombres peu familiers (texte chiffré), qui est ensuite magnifiquement restauré en la chaîne d&amp;rsquo;origine par la clé privée.&lt;/p>
&lt;hr>
&lt;h2 id="9-conclusion--lintersection-de-la-beauté-mathématique-et-de-la-praticité">9. Conclusion : L&amp;rsquo;intersection de la beauté mathématique et de la praticité
&lt;/h2>&lt;p>Au 17ème siècle, lorsque Pierre de Fermat a découvert ce &amp;ldquo;petit théorème&amp;rdquo;, personne ne pensait qu&amp;rsquo;il serait utile à quoi que ce soit. Fermat lui-même a mené des recherches en théorie des nombres par pure curiosité mathématique.&lt;/p>
&lt;p>Cependant, environ 300 ans plus tard, dans les années 1970, à l&amp;rsquo;aube des réseaux informatiques, le théorème de Fermat a fait un retour spectaculaire en tant que technologie cryptographique essentielle pour l&amp;rsquo;établissement de protocoles de communication sécurisés. La technologie de test de primalité basée sur le petit théorème de Fermat et le chiffrement RSA basé sur le théorème d&amp;rsquo;Euler soutiennent littéralement l&amp;rsquo;infrastructure Internet moderne.&lt;/p>
&lt;p>Les messages LINE que nous envoyons nonchalamment tous les jours, les achats sur Amazon, tout cela danse sur cette belle et simple formule $a^{p-1} \equiv 1 \pmod p$. Le petit théorème de Fermat nous enseigne que peu importe à quel point les mathématiques peuvent être abstraites, le moment viendra toujours où elles seront utiles à l&amp;rsquo;humanité.&lt;/p>
&lt;p>Dans l&amp;rsquo;apprentissage de la programmation et de la théorie cryptographique, comprendre les structures mathématiques à la base de celles-ci sera une arme puissante pour comprendre en profondeur le comportement des bibliothèques fournies sous forme de boîtes noires et pour concevoir des systèmes plus sécurisés.&lt;/p></description></item><item><title>L'intuition mathématique de la cryptographie basée sur les réseaux (Lattice-based cryptography)</title><link>http://kenji.blog/fr/p/lattice-based-cryptography-math-intuition/</link><pubDate>Fri, 11 Sep 2026 21:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/lattice-based-cryptography-math-intuition/</guid><description>&lt;img src="http://kenji.blog/p/lattice-based-cryptography-math-intuition/img/eyecatch.jpg" alt="Featured image of post L'intuition mathématique de la cryptographie basée sur les réseaux (Lattice-based cryptography)" />&lt;h1 id="1-introduction--laube-de-la-cryptographie-post-quantique-pqc-et-lessor-de-la-cryptographie-basée-sur-les-réseaux">1. Introduction : L&amp;rsquo;aube de la cryptographie post-quantique (PQC) et l&amp;rsquo;essor de la cryptographie basée sur les réseaux
&lt;/h1>&lt;p>L&amp;rsquo;infrastructure numérique de la société moderne repose sur des technologies de cryptographie à clé publique telles que le chiffrement RSA et la cryptographie sur les courbes elliptiques (ECC). Ces méthodes cryptographiques basent leur sécurité sur la difficulté mathématique de problèmes tels que le &amp;ldquo;problème de la factorisation en nombres premiers&amp;rdquo; ou le &amp;ldquo;problème du logarithme discret&amp;rdquo;, qui sont considérés comme impossibles à résoudre efficacement (nécessitant un temps exponentiel) par les ordinateurs classiques conventionnels.&lt;/p>
&lt;p>Cependant, en 1994, l&amp;rsquo;algorithme de Shor, publié par Peter Shor, a provoqué une onde de choc dans le monde de la cryptographie. Cet algorithme a prouvé mathématiquement qu&amp;rsquo;une fois qu&amp;rsquo;un ordinateur quantique à grande échelle sera réalisé, il pourra résoudre les problèmes de factorisation en nombres premiers et de logarithme discret en un temps polynomial. Cela signifie que la cryptographie à clé publique largement utilisée aujourd&amp;rsquo;hui deviendra complètement décryptable à l&amp;rsquo;avenir.&lt;/p>
&lt;p>Pour contrer cette &amp;ldquo;menace quantique (Quantum Threat)&amp;rdquo;, il est devenu urgent de rechercher de nouvelles méthodes cryptographiques difficiles à décrypter, même avec un ordinateur quantique. C&amp;rsquo;est le domaine appelé &amp;ldquo;Cryptographie Post-Quantique (Post-Quantum Cryptography : PQC)&amp;rdquo; ou &amp;ldquo;Cryptographie résistante aux ordinateurs quantiques&amp;rdquo;.&lt;/p>
&lt;p>Il existe plusieurs candidats prometteurs pour la PQC, tels que la cryptographie basée sur les fonctions de hachage, sur les codes, sur des polynômes multivariés et sur les isogénies. Parmi eux, celle qui attire actuellement le plus l&amp;rsquo;attention et qui est au cœur du processus de standardisation PQC par le NIST (Institut national des normes et de la technologie des États-Unis) est la &amp;ldquo;cryptographie basée sur les réseaux (Lattice-based cryptography)&amp;rdquo;. Comparée à d&amp;rsquo;autres méthodes, la cryptographie basée sur les réseaux se distingue par une vitesse de traitement très élevée pour le chiffrement et le déchiffrement. De plus, elle possède une caractéristique remarquable en théorie cryptographique : une preuve de sécurité extrêmement solide basée sur la réduction de la &amp;ldquo;complexité dans le pire des cas (Worst-case complexity)&amp;rdquo; à la &amp;ldquo;complexité en moyenne (Average-case complexity)&amp;rdquo;.&lt;/p>
&lt;p>Dans cet article, nous partirons de la définition mathématique du &amp;ldquo;réseau (Lattice)&amp;rdquo; qui est à la base de cette cryptographie, pour expliquer en profondeur les problèmes difficiles sur les réseaux tels que le SVP (Problème du vecteur le plus court) et le CVP (Problème du vecteur le plus proche), ainsi que le problème LWE (Learning With Errors) qui est le cœur de la cryptographie moderne sur les réseaux. Nous utiliserons des formules mathématiques, des intuitions géométriques et des exemples numériques concrets.&lt;/p>
&lt;h1 id="2-définition-mathématique-et-intuition-géométrique-du-réseau-lattice">2. Définition mathématique et intuition géométrique du réseau (Lattice)
&lt;/h1>&lt;h2 id="21-espace-vectoriel-et-réseau">2.1 Espace vectoriel et réseau
&lt;/h2>&lt;p>En mathématiques, un &amp;ldquo;réseau (Lattice)&amp;rdquo; est un ensemble de points discrets disposés de manière régulière dans un espace vectoriel réel à $n$ dimensions $\mathbb{R}^n$. Il ressemble à un espace vectoriel (Vector Space) étudié en algèbre linéaire, mais il présente une différence cruciale. Alors qu&amp;rsquo;un espace vectoriel est un espace continu représenté par des combinaisons linéaires de vecteurs de base avec des &amp;ldquo;coefficients réels&amp;rdquo;, un réseau est un espace discret représenté par des combinaisons linéaires de vecteurs de base avec des &amp;ldquo;coefficients entiers&amp;rdquo;.&lt;/p>
&lt;p>Donnons une définition mathématique rigoureuse. Considérons $n$ vecteurs linéairement indépendants ($n \le m$) $\mathbf{b}_1, \mathbf{b}_2, \dots, \mathbf{b}_n$ dans un espace vectoriel réel à $m$ dimensions $\mathbb{R}^m$. La matrice dont les colonnes sont ces vecteurs est notée $B = [\mathbf{b}_1, \mathbf{b}_2, \dots, \mathbf{b}_n] \in \mathbb{R}^{m \times n}$. On appelle $B$ la &amp;ldquo;base (Basis)&amp;rdquo; du réseau.&lt;/p>
&lt;p>Le réseau $\mathcal{L}(B)$ généré par cette base $B$ est défini comme suit :&lt;/p>
$$
\mathcal{L}(B) = \left\{ \sum_{i=1}^{n} x_i \mathbf{b}_i \mathrel{\bigg|} x_i \in \mathbb{Z} \right\} = \{ B \mathbf{x} \mid \mathbf{x} \in \mathbb{Z}^n \}
$$
&lt;p>Ce qui est important ici, c&amp;rsquo;est que les coefficients $x_i$ sont restreints aux entiers $\mathbb{Z}$ et non aux nombres réels $\mathbb{R}$. Par conséquent, au lieu de former un nombre infini de points continus dans l&amp;rsquo;espace, cela forme un &amp;ldquo;ensemble de points discrets&amp;rdquo; semblables à des intersections espacées uniformément.&lt;/p>
&lt;h2 id="22-image-géométrique">2.2 Image géométrique
&lt;/h2>&lt;p>Considérons l&amp;rsquo;exemple du plan bidimensionnel $\mathbb{R}^2$. Si nous choisissons les vecteurs de base $\mathbf{b}_1 = \begin{pmatrix} 1 \\ 0 \end{pmatrix}$ et $\mathbf{b}_2 = \begin{pmatrix} 0 \\ 1 \end{pmatrix}$, le réseau généré par ceux-ci est l&amp;rsquo;ensemble de toutes les coordonnées entières $(x, y) \in \mathbb{Z}^2$ sur le plan cartésien. C&amp;rsquo;est le &amp;ldquo;réseau carré&amp;rdquo; le plus simple.&lt;/p>
&lt;p>Cependant, les réseaux ne sont pas toujours orthogonaux. Par exemple, si nous considérons la base $\mathbf{b}_1 = \begin{pmatrix} 2 \\ 1 \end{pmatrix}$ et $\mathbf{b}_2 = \begin{pmatrix} 1 \\ 3 \end{pmatrix}$, les points générés ressembleront aux intersections d&amp;rsquo;une maille déformée en biais.&lt;/p>
&lt;h2 id="23-non-unicité-de-la-base-et-transformation-unimodulaire">2.3 Non-unicité de la base et transformation unimodulaire
&lt;/h2>&lt;p>Il existe une propriété importante liée au fondement de la sécurité de la cryptographie sur les réseaux : &amp;ldquo;Il existe une infinité de bases qui génèrent le même réseau&amp;rdquo;.&lt;/p>
&lt;p>Par exemple, la base $\mathbf{b}_1 = (1, 0)^T, \mathbf{b}_2 = (0, 1)^T$ qui génère le réseau $\mathbb{Z}^2$, génère exactement le même réseau $\mathbb{Z}^2$ si nous utilisons la base $\mathbf{b}'_1 = (1, 1)^T, \mathbf{b}'_2 = (2, 3)^T$.&lt;/p>
&lt;p>Une condition nécessaire et suffisante pour qu&amp;rsquo;une base $B$ et une autre base $B'$ génèrent le même réseau est l&amp;rsquo;existence d&amp;rsquo;une matrice à coefficients entiers $U \in \mathbb{Z}^{n \times n}$ avec un déterminant $\det(U) = \pm 1$, telle que
&lt;/p>
$$ B' = B U $$
&lt;p>
Une telle matrice $U$ est appelée &amp;ldquo;matrice unimodulaire (Unimodular matrix)&amp;rdquo;.&lt;/p>
&lt;p>L&amp;rsquo;idée fondamentale dans son application à la cryptographie est d&amp;rsquo;utiliser une &amp;ldquo;bonne base (une base proche de l&amp;rsquo;orthogonalité, composée de vecteurs courts)&amp;rdquo; comme clé privée, et une &amp;ldquo;mauvaise base (une base avec des vecteurs extrêmement obliques les uns par rapport aux autres et très longs)&amp;rdquo; comme clé publique. Calculer une bonne base à partir d&amp;rsquo;une mauvaise base devient extrêmement difficile à mesure que la dimension augmente. C&amp;rsquo;est l&amp;rsquo;intuition fondamentale de la cryptographie basée sur les réseaux.&lt;/p>
&lt;h1 id="3-problèmes-mathématiquement-difficiles-dans-les-réseaux">3. Problèmes mathématiquement difficiles dans les réseaux
&lt;/h1>&lt;p>La sécurité de la cryptographie basée sur les réseaux repose sur la difficulté de résoudre certains problèmes mathématiques sur les réseaux. Nous présentons ici les deux problèmes les plus fondamentaux et célèbres.&lt;/p>
&lt;h2 id="31-problème-du-vecteur-le-plus-court-shortest-vector-problem-svp">3.1 Problème du vecteur le plus court (Shortest Vector Problem: SVP)
&lt;/h2>&lt;p>Le SVP est le problème le plus classique et célèbre de la théorie des réseaux.&lt;/p>
&lt;p>&lt;strong>Définition (SVP) :&lt;/strong>
Étant donné une base de réseau arbitraire $B$, trouver le vecteur $\mathbf{v}$ non nul appartenant à ce réseau $\mathcal{L}(B)$ qui a la norme euclidienne (longueur) minimale.&lt;/p>
&lt;p>Mathématiquement, c&amp;rsquo;est le problème de trouver $\mathbf{v}$ tel que $\min_{\mathbf{v} \in \mathcal{L}(B) \setminus \{\mathbf{0}\}} \| \mathbf{v} \|$. Cette longueur minimale est notée $\lambda_1(\mathcal{L})$ et est appelée le &amp;ldquo;premier minimum successif (First successive minimum) du réseau&amp;rdquo;.&lt;/p>
&lt;p>En basse dimension, comme en 2 ou 3 dimensions, vous pouvez trouver le vecteur le plus court à l&amp;rsquo;œil nu en dessinant un graphique, ou bien le résoudre efficacement en utilisant l&amp;rsquo;algorithme de réduction de base de Gauss. Cependant, lorsque la dimension $n$ atteint des centaines ou des milliers de dimensions, il est connu que résoudre strictement le SVP est un problème NP-difficile.&lt;/p>
&lt;p>Dans les systèmes cryptographiques réels, on utilise le SVP approché ($\gamma$-SVP), qui consiste à trouver un &amp;ldquo;vecteur approximativement court&amp;rdquo; au lieu du vecteur strictement le plus court. Lorsque le facteur d&amp;rsquo;approximation $\gamma$ est de taille polynomiale, ce problème est toujours considéré comme extrêmement difficile.&lt;/p>
&lt;h2 id="32-problème-du-vecteur-le-plus-proche-closest-vector-problem-cvp">3.2 Problème du vecteur le plus proche (Closest Vector Problem: CVP)
&lt;/h2>&lt;p>Le CVP est également un problème extrêmement important dans la cryptographie sur les réseaux.&lt;/p>
&lt;p>&lt;strong>Définition (CVP) :&lt;/strong>
Étant donné une base de réseau arbitraire $B$ et un vecteur cible arbitraire $\mathbf{t} \in \mathbb{R}^m$ dans l&amp;rsquo;espace (qui n&amp;rsquo;est pas nécessairement un point du réseau), trouver le point du réseau $\mathbf{v} \in \mathcal{L}(B)$ qui est le plus proche de $\mathbf{t}$.&lt;/p>
&lt;p>Mathématiquement, c&amp;rsquo;est le problème de trouver un point du réseau $\mathbf{v}$ tel que $\min_{\mathbf{v} \in \mathcal{L}(B)} \| \mathbf{v} - \mathbf{t} \|$.&lt;/p>
&lt;p>Le CVP, tout comme le SVP, est NP-difficile en haute dimension. Du point de vue des applications cryptographiques, le problème LWE décrit ci-dessous est étroitement lié à une variante spéciale de ce CVP (Bounded Distance Decoding: BDD).&lt;/p>
&lt;h2 id="33-pourquoi-est-il-impossible-de-les-résoudre-en-haute-dimension--limites-de-lll-et-bkz">3.3 Pourquoi est-il impossible de les résoudre en haute dimension ? (Limites de LLL et BKZ)
&lt;/h2>&lt;p>L&amp;rsquo;algorithme LLL (algorithme de Lenstra-Lenstra-Lovász) est un algorithme célèbre pour résoudre les problèmes de réseau en haute dimension. L&amp;rsquo;algorithme LLL fonctionne en temps polynomial et peut réduire (Reduction) la base du réseau en une &amp;ldquo;bonne base&amp;rdquo; dans une certaine mesure. Cependant, le vecteur le plus court que l&amp;rsquo;algorithme LLL peut trouver a un facteur d&amp;rsquo;approximation exponentiel ($2^{\mathcal{O}(n)}$) par rapport à la longueur du vrai vecteur le plus court, ce qui ne suffit pas pour briser la sécurité de la cryptographie.&lt;/p>
&lt;p>En utilisant des algorithmes de réduction de base plus puissants comme l&amp;rsquo;algorithme BKZ (Block Korkine-Zolotarev), qui est une amélioration de LLL, il est possible de trouver des vecteurs plus courts, mais la complexité de calcul augmente de manière exponentielle par rapport à la taille du bloc. Dans la cryptographie sur les réseaux, des paramètres de sécurité (comme la taille de la dimension $n$) sont déterminés en estimant le temps d&amp;rsquo;exécution de cet algorithme BKZ. Avec les paramètres standard actuels de la PQC, la dimension $n$ est choisie avec des valeurs de 500 à plus de 1000, et on estime qu&amp;rsquo;il faudrait un temps supérieur à l&amp;rsquo;âge de l&amp;rsquo;univers pour la déchiffrer, même avec des superordinateurs ou de futurs ordinateurs quantiques.&lt;/p>
&lt;h1 id="4-formulation-mathématique-du-problème-lwe-learning-with-errors">4. Formulation mathématique du problème LWE (Learning With Errors)
&lt;/h1>&lt;p>La majeure partie de la cryptographie moderne sur les réseaux est basée sur le &amp;ldquo;problème LWE (Learning With Errors)&amp;rdquo; proposé par Oded Regev en 2005. La beauté du problème LWE réside dans la simplicité de sa formulation et dans sa solide preuve mathématique basée sur &amp;ldquo;la réduction de la complexité dans le pire des cas à la complexité en moyenne&amp;rdquo;.&lt;/p>
&lt;h2 id="41-système-déquations-linéaires-sans-bruit">4.1 Système d&amp;rsquo;équations linéaires sans bruit
&lt;/h2>&lt;p>Pour comprendre le problème LWE, considérons d&amp;rsquo;abord un simple système d&amp;rsquo;équations linéaires sans bruit.
Supposons qu&amp;rsquo;il existe un vecteur secret inconnu $\mathbf{s} \in \mathbb{Z}_q^n$ (chaque composante est un entier de $0$ à $q-1$). Ici, $q$ est un nombre premier.&lt;/p>
&lt;p>Nous choisissons des vecteurs de coefficients aléatoires $\mathbf{a}_1, \mathbf{a}_2, \dots \in \mathbb{Z}_q^n$ et calculons le produit scalaire avec le vecteur secret $\mathbf{s}$ modulo $q$.
$b_1 = \langle \mathbf{a}_1, \mathbf{s} \rangle \pmod q$
$b_2 = \langle \mathbf{a}_2, \mathbf{s} \rangle \pmod q$
$\vdots$&lt;/p>
&lt;p>Si l&amp;rsquo;on nous donne un nombre suffisant (plus de $n$) de paires $(\mathbf{a}_i, b_i)$, nous pouvons facilement restaurer le vecteur secret $\mathbf{s}$ en utilisant l&amp;rsquo;&amp;ldquo;élimination de Gauss (Gaussian elimination)&amp;rdquo; en algèbre linéaire. C&amp;rsquo;est un problème qui peut être facilement résolu en temps polynomial.&lt;/p>
&lt;h2 id="42-définition-du-problème-lwe--ajout-de-bruit">4.2 Définition du problème LWE : Ajout de bruit
&lt;/h2>&lt;p>Alors, que se passe-t-il si nous ajoutons un léger &amp;ldquo;bruit (erreur)&amp;rdquo; à ce problème ?
C&amp;rsquo;est là l&amp;rsquo;essence du problème LWE.&lt;/p>
&lt;p>Pour un vecteur secret inconnu $\mathbf{s} \in \mathbb{Z}_q^n$, nous ajoutons une petite erreur $e_i \in \mathbb{Z}_q$ au résultat de chaque équation.
$b_i = \langle \mathbf{a}_i, \mathbf{s} \rangle + e_i \pmod q$&lt;/p>
&lt;p>Ici, $e_i$ est une petite valeur entière dont la moyenne est 0 et l&amp;rsquo;écart-type est relativement faible (par exemple, choisie à partir d&amp;rsquo;une distribution gaussienne discrète, similaire à une distribution normale).
L&amp;rsquo;information fournie est une liste de paires de vecteurs aléatoires $\mathbf{a}_i$ et de $b_i$ calculés en ajoutant l&amp;rsquo;erreur.
$( \mathbf{a}_1, b_1 ), ( \mathbf{a}_2, b_2 ), \dots, ( \mathbf{a}_m, b_m )$&lt;/p>
&lt;p>C&amp;rsquo;est beaucoup plus clair lorsqu&amp;rsquo;on l&amp;rsquo;exprime sous forme de matrice.
En utilisant une matrice aléatoire $A \in \mathbb{Z}_q^{m \times n}$, un vecteur secret $\mathbf{s} \in \mathbb{Z}_q^n$, et un vecteur d&amp;rsquo;erreur $\mathbf{e} \in \mathbb{Z}_q^m$, on peut écrire :
&lt;/p>
$$ \mathbf{b} = A \mathbf{s} + \mathbf{e} \pmod q $$
&lt;p>
Seuls $A$ et $\mathbf{b}$ sont fournis. Le &amp;ldquo;problème de recherche LWE (Search LWE problem)&amp;rdquo; consiste à trouver $\mathbf{s}$ à partir de cela.&lt;/p>
&lt;p>Puisque l&amp;rsquo;erreur $e_i$ est introduite, si l&amp;rsquo;on essaie d&amp;rsquo;utiliser l&amp;rsquo;élimination de Gauss, l&amp;rsquo;erreur s&amp;rsquo;amplifiera de manière exponentielle lors de l&amp;rsquo;addition et de la soustraction d&amp;rsquo;équations, et il deviendra impossible d&amp;rsquo;arriver à la bonne réponse. À première vue, cela ressemble à un simple système d&amp;rsquo;équations linéaires, mais l&amp;rsquo;ajout de ce petit bruit fait bondir le niveau de difficulté au stade NP-difficile.&lt;/p>
&lt;h2 id="43-problème-de-décision-lwe-decision-lwe">4.3 Problème de décision LWE (Decision LWE)
&lt;/h2>&lt;p>Une variante du problème de recherche LWE, appelée &amp;ldquo;problème de décision LWE (Decision LWE problem)&amp;rdquo;, est fréquemment utilisée dans les preuves en théorie cryptographique.&lt;/p>
&lt;p>Le problème de décision LWE est le problème de déterminer, étant donné une liste d&amp;rsquo;échantillons obtenus à partir des deux distributions suivantes, de quelle distribution elle provient.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Distribution LWE&lt;/strong> : $(A, \mathbf{b} = A\mathbf{s} + \mathbf{e} \pmod q)$ calculé intentionnellement.&lt;/li>
&lt;li>&lt;strong>Distribution aléatoire uniforme&lt;/strong> : $(A, \mathbf{u})$ constitué d&amp;rsquo;une matrice $A$ et d&amp;rsquo;un vecteur $\mathbf{u}$ choisis de manière totalement aléatoire.&lt;/li>
&lt;/ol>
&lt;p>Étonnamment, si les paramètres du problème LWE sont choisis de manière appropriée, les paires obtenues à partir de la distribution LWE deviennent &amp;ldquo;informatiquement indiscernables (Computationally Indistinguishable)&amp;rdquo; des paires de données totalement aléatoires. Cette propriété est la raison pour laquelle la cryptographie basée sur LWE peut générer &amp;ldquo;un texte chiffré indiscernable de nombres aléatoires&amp;rdquo;.&lt;/p>
&lt;h2 id="44-réduction-de-la-complexité-du-pire-des-cas-à-la-complexité-en-moyenne-théorème-de-regev">4.4 Réduction de la complexité du pire des cas à la complexité en moyenne (Théorème de Regev)
&lt;/h2>&lt;p>La plus grande réalisation d&amp;rsquo;Oded Regev a été de lier mathématiquement la difficulté de ce problème LWE à la difficulté des problèmes de réseaux susmentionnés (SVP et CVP).&lt;/p>
&lt;p>En utilisant la réduction quantique (Quantum reduction), il a prouvé que &amp;ldquo;s&amp;rsquo;il existe un algorithme en temps polynomial capable de résoudre le problème LWE en moyenne (pour des $A$ et $\mathbf{e}$ choisis aléatoirement), alors il existe un algorithme quantique en temps polynomial capable de résoudre le Gap-SVP pour le pire des cas (le cas le plus difficile) de n&amp;rsquo;importe quel réseau.&amp;rdquo; (Plus tard, une réduction classique a également été démontrée par Peikert et al.).&lt;/p>
&lt;p>C&amp;rsquo;est une propriété de rêve en théorie cryptographique. En effet, elle dissipe la crainte que &amp;ldquo;la cryptographie puisse être brisée parce que nous avons peut-être choisi par hasard une clé faible (une partie du cas moyen)&amp;rdquo;, et fournit la puissante garantie que &amp;ldquo;si le LWE moyen peut être résolu, alors tous les problèmes difficiles des réseaux peuvent être résolus (donc LWE est absolument difficile)&amp;rdquo;.&lt;/p>
&lt;div class="mermaid">graph TD
A["Problèmes de réseau dans le pire des cas (Gap-SVP, SIVP)"] -->|Réduction quantique/classique| B["Problème LWE en moyenne"]
B -->|Construction cryptographique| C["Systèmes cryptographiques basés sur LWE (PKE, KEM, FHE)"]
style A fill:#ffcccc,stroke:#ff0000,stroke-width:2px,color:#000
style B fill:#ccffcc,stroke:#00aa00,stroke-width:2px,color:#000
style C fill:#ccccff,stroke:#0000ff,stroke-width:2px,color:#000&lt;/div>
&lt;h1 id="5-construction-du-cryptosystème-à-clé-publique-basé-sur-lwe-cryptosystème-de-regev">5. Construction du cryptosystème à clé publique basé sur LWE (Cryptosystème de Regev)
&lt;/h1>&lt;p>Maintenant que nous avons compris la difficulté du problème LWE, examinons le cryptosystème à clé publique de base proposé par Oded Regev pour voir comment il est utilisé pour le chiffrement et le déchiffrement. Nous expliquerons ici le mécanisme le plus fondamental de chiffrement d&amp;rsquo;un message d&amp;rsquo;un bit $M \in \{0, 1\}$.&lt;/p>
&lt;h2 id="51-génération-de-clé-key-generation">5.1 Génération de clé (Key Generation)
&lt;/h2>&lt;ol>
&lt;li>En tant que paramètres du système, déterminez le module premier $q$, la dimension $n$, et le nombre d&amp;rsquo;équations $m$ ($m > n \log q$).&lt;/li>
&lt;li>En tant que clé privée, choisissez aléatoirement un vecteur $\mathbf{s} \in \mathbb{Z}_q^n$.&lt;/li>
&lt;li>Générez une matrice aléatoire $A \in \mathbb{Z}_q^{m \times n}$.&lt;/li>
&lt;li>Choisissez un petit vecteur d&amp;rsquo;erreur $\mathbf{e} \in \mathbb{Z}_q^m$ à partir d&amp;rsquo;une distribution d&amp;rsquo;erreur telle que la distribution gaussienne discrète.&lt;/li>
&lt;li>Calculez le vecteur $\mathbf{b} = A \mathbf{s} + \mathbf{e} \pmod q$.&lt;/li>
&lt;li>La clé publique (Public Key) sera $(A, \mathbf{b})$.&lt;/li>
&lt;li>La clé secrète (Secret Key) sera $\mathbf{s}$.&lt;/li>
&lt;/ol>
&lt;p>La clé publique est littéralement une &amp;ldquo;instance du problème LWE&amp;rdquo;. Puisque trouver la clé secrète $\mathbf{s}$ à partir de la clé publique $(A, \mathbf{b})$ équivaut à résoudre le problème de recherche LWE, la sécurité est garantie.&lt;/p>
&lt;h2 id="52-chiffrement-encryption">5.2 Chiffrement (Encryption)
&lt;/h2>&lt;p>Alice utilise la clé publique de Bob $(A, \mathbf{b})$ pour chiffrer un message d&amp;rsquo;un bit $M \in \{0, 1\}$.&lt;/p>
&lt;ol>
&lt;li>Choisissez un vecteur binaire aléatoire (dont les composantes sont 0 ou 1) $\mathbf{r} \in \{0, 1\}^m$.&lt;/li>
&lt;li>Comme première partie du texte chiffré, calculez le vecteur $\mathbf{u} = A^T \mathbf{r} \pmod q$. ($A^T$ est la matrice transposée de $A$. C&amp;rsquo;est-à-dire que nous additionnons les lignes de $A$ dont la composante correspondante de $\mathbf{r}$ est 1).&lt;/li>
&lt;li>Comme deuxième partie du texte chiffré, calculez le scalaire $v = \mathbf{b}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor \pmod q$.
(Si le message $M$ est 0, n&amp;rsquo;ajoutez rien ; s&amp;rsquo;il est $1$, ajoutez exactement la moitié de $q$, soit $\lfloor \frac{q}{2} \rfloor$).&lt;/li>
&lt;li>Le texte chiffré (Ciphertext) sera $(\mathbf{u}, v)$.&lt;/li>
&lt;/ol>
&lt;p>L&amp;rsquo;intuition derrière le chiffrement est de prendre la &amp;ldquo;somme d&amp;rsquo;un sous-ensemble aléatoire&amp;rdquo; par rapport à la matrice $A$ et au vecteur $\mathbf{b}$ de la clé publique. En raison de la difficulté du problème de décision LWE, ce texte chiffré $(\mathbf{u}, v)$ semble indiscernable de vecteurs totalement aléatoires et de nombres uniformément aléatoires (Sécurité sémantique : Semantic Security).&lt;/p>
&lt;div class="mermaid">flowchart LR
M["Message M dans {0,1}"] --> Enc
PK["Clé publique (A, b)"] --> Enc
r["Vecteur binaire aléatoire r"] --> Enc
subgraph Enc ["Processus de chiffrement"]
direction TB
u_calc["u = A^T * r mod q"]
v_calc["v = b^T * r + M * floor(q/2) mod q"]
end
Enc --> CT["Texte chiffré (u, v)"]&lt;/div>
&lt;h2 id="53-déchiffrement-decryption">5.3 Déchiffrement (Decryption)
&lt;/h2>&lt;p>Bob déchiffre le texte chiffré $(\mathbf{u}, v)$ en utilisant sa clé secrète $\mathbf{s}$.&lt;/p>
&lt;ol>
&lt;li>Calculez la valeur suivante : $D = v - \mathbf{s}^T \mathbf{u} \pmod q$&lt;/li>
&lt;li>Si le résultat calculé est proche de $0$, le message est de $M=0$, s&amp;rsquo;il est proche de $\lfloor \frac{q}{2} \rfloor$, le message est de $M=1$.&lt;/li>
&lt;/ol>
&lt;p>Montrons mathématiquement pourquoi cela permet le déchiffrement.
Rappelez-vous que $\mathbf{b} = A \mathbf{s} + \mathbf{e}$.&lt;/p>
$$
\begin{aligned}
v - \mathbf{s}^T \mathbf{u} &amp;= (\mathbf{b}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor) - \mathbf{s}^T (A^T \mathbf{r}) \\
&amp;= ((A \mathbf{s} + \mathbf{e})^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor) - \mathbf{s}^T A^T \mathbf{r} \\
&amp;= (\mathbf{s}^T A^T \mathbf{r} + \mathbf{e}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor) - \mathbf{s}^T A^T \mathbf{r} \\
&amp;= \mathbf{e}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor \pmod q
\end{aligned}
$$
&lt;p>Ici, le terme $\mathbf{s}^T A^T \mathbf{r}$ s&amp;rsquo;est parfaitement annulé et a disparu de l&amp;rsquo;équation !
Ce qui reste, c&amp;rsquo;est $\mathbf{e}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor$.&lt;/p>
&lt;p>$\mathbf{e}$ est un vecteur de bruit dont les composantes sont très petites, et $\mathbf{r}$ est un vecteur binaire dont les composantes sont 0 ou 1. Par conséquent, leur produit scalaire $\mathbf{e}^T \mathbf{r}$ restera également une valeur relativement faible (si les paramètres sont choisis de manière appropriée).&lt;/p>
&lt;ul>
&lt;li>Si $M=0$, le résultat sera $\mathbf{e}^T \mathbf{r}$, qui est une petite valeur proche de $0$.&lt;/li>
&lt;li>Si $M=1$, le résultat sera $\mathbf{e}^T \mathbf{r} + \lfloor \frac{q}{2} \rfloor$, qui sera situé autour de la moitié de $q$, soit $\lfloor \frac{q}{2} \rfloor$.&lt;/li>
&lt;/ul>
&lt;p>Si les paramètres sont conçus de sorte que la valeur absolue de l&amp;rsquo;erreur $\mathbf{e}^T \mathbf{r}$ soit inférieure à $\frac{q}{4}$, Bob peut déterminer (déchiffrer) avec précision le message $M$ en regardant simplement si le résultat du calcul est plus proche de $0$ ou de $\lfloor \frac{q}{2} \rfloor$. C&amp;rsquo;est le mécanisme élégant par lequel la cryptographie basée sur LWE fonctionne.&lt;/p>
&lt;div class="mermaid">flowchart LR
CT["Texte chiffré (u, v)"] --> Dec
SK["Clé secrète s"] --> Dec
subgraph Dec ["Processus de déchiffrement"]
direction TB
calc["Calculer D = v - s^T * u mod q"]
check["Vérifier si D est plus proche de 0 ou de q/2"]
end
calc --> check
Dec --> M_out["Message récupéré M"]&lt;/div>
&lt;h1 id="6-exemple-jouet-toy-example-de-chiffrement-lwe-avec-des-valeurs-numériques-spécifiques">6. Exemple jouet (Toy Example) de chiffrement LWE avec des valeurs numériques spécifiques
&lt;/h1>&lt;p>Il est difficile de comprendre seulement avec une liste de formules mathématiques, alors établissons des paramètres numériques très petits et suivons les calculs du chiffrement au déchiffrement.
(* Dans un système cryptographique réel, pour assurer la sécurité, $n$ est de 500 ou plus et $q$ est de plusieurs milliers).&lt;/p>
&lt;p>&lt;strong>【Paramétrage】&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Module $q = 17$ (Un nombre premier. Les valeurs seront donc de $0$ à $16$).&lt;/li>
&lt;li>Dimension $n = 2$&lt;/li>
&lt;li>Nombre d&amp;rsquo;équations $m = 4$&lt;/li>
&lt;li>Supposons que nous chiffrons le message $M = 1$.&lt;/li>
&lt;li>Montant du décalage du message : $\lfloor \frac{q}{2} \rfloor = \lfloor \frac{17}{2} \rfloor = 8$&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>【1. Phase de génération de clé】&lt;/strong>
Bob choisit aléatoirement une clé secrète $\mathbf{s}$, une matrice $A$, et un vecteur d&amp;rsquo;erreur $\mathbf{e}$.
&lt;/p>
$$ \mathbf{s} = \begin{pmatrix} 3 \\ 4 \end{pmatrix} \in \mathbb{Z}_{17}^2 $$
$$ A = \begin{pmatrix} 2 &amp; 15 \\ 1 &amp; 8 \\ 14 &amp; 5 \\ 9 &amp; 10 \end{pmatrix} \in \mathbb{Z}_{17}^{4 \times 2} $$
$$ \mathbf{e} = \begin{pmatrix} 1 \\ -1 \\ 0 \\ 2 \end{pmatrix} \equiv \begin{pmatrix} 1 \\ 16 \\ 0 \\ 2 \end{pmatrix} \pmod{17} $$
&lt;p>Ensuite, calculez la clé publique $\mathbf{b}$.
&lt;/p>
$$ A \mathbf{s} = \begin{pmatrix} 2 &amp; 15 \\ 1 &amp; 8 \\ 14 &amp; 5 \\ 9 &amp; 10 \end{pmatrix} \begin{pmatrix} 3 \\ 4 \end{pmatrix} = \begin{pmatrix} 2\times 3 + 15\times 4 \\ 1\times 3 + 8\times 4 \\ 14\times 3 + 5\times 4 \\ 9\times 3 + 10\times 4 \end{pmatrix} = \begin{pmatrix} 6 + 60 \\ 3 + 32 \\ 42 + 20 \\ 27 + 40 \end{pmatrix} = \begin{pmatrix} 66 \\ 35 \\ 62 \\ 67 \end{pmatrix} $$
&lt;p>
Nous calculons cela modulo 17. (par exemple, $66 = 17 \times 3 + 15$)
&lt;/p>
$$ A \mathbf{s} \pmod{17} = \begin{pmatrix} 15 \\ 1 \\ 11 \\ 16 \end{pmatrix} $$
&lt;p>
Ajoutez le vecteur d&amp;rsquo;erreur $\mathbf{e}$.
&lt;/p>
$$ \mathbf{b} = A \mathbf{s} + \mathbf{e} = \begin{pmatrix} 15 \\ 1 \\ 11 \\ 16 \end{pmatrix} + \begin{pmatrix} 1 \\ 16 \\ 0 \\ 2 \end{pmatrix} = \begin{pmatrix} 16 \\ 17 \\ 11 \\ 18 \end{pmatrix} \equiv \begin{pmatrix} 16 \\ 0 \\ 11 \\ 1 \end{pmatrix} \pmod{17} $$
&lt;p>La clé publique est $A$ et $\mathbf{b} = (16, 0, 11, 1)^T$.&lt;/p>
&lt;p>&lt;strong>【2. Phase de chiffrement】&lt;/strong>
Alice chiffre le message $M = 1$.
Choisissez un vecteur aléatoire $\mathbf{r}$. Ici, supposons $\mathbf{r} = (1, 0, 1, 0)^T$.&lt;/p>
&lt;p>Calculez $\mathbf{u}$.
&lt;/p>
$$ \mathbf{u} = A^T \mathbf{r} = \begin{pmatrix} 2 &amp; 1 &amp; 14 &amp; 9 \\ 15 &amp; 8 &amp; 5 &amp; 10 \end{pmatrix} \begin{pmatrix} 1 \\ 0 \\ 1 \\ 0 \end{pmatrix} = \begin{pmatrix} 2 \times 1 + 14 \times 1 \\ 15 \times 1 + 5 \times 1 \end{pmatrix} = \begin{pmatrix} 16 \\ 20 \end{pmatrix} \equiv \begin{pmatrix} 16 \\ 3 \end{pmatrix} \pmod{17} $$
&lt;p>Calculez $v$.
&lt;/p>
$$ \mathbf{b}^T \mathbf{r} = (16, 0, 11, 1) \begin{pmatrix} 1 \\ 0 \\ 1 \\ 0 \end{pmatrix} = 16 \times 1 + 11 \times 1 = 27 \equiv 10 \pmod{17} $$
&lt;p>
Ajoutez la valeur $\lfloor 17/2 \rfloor = 8$ correspondant au message $M=1$.
&lt;/p>
$$ v = \mathbf{b}^T \mathbf{r} + M \cdot 8 = 10 + 1 \times 8 = 18 \equiv 1 \pmod{17} $$
&lt;p>Alice envoie le texte chiffré $(\mathbf{u}, v) = \left( \begin{pmatrix} 16 \\ 3 \end{pmatrix}, 1 \right)$ à Bob.&lt;/p>
&lt;p>&lt;strong>【3. Phase de déchiffrement】&lt;/strong>
Après avoir reçu le texte chiffré, Bob le déchiffre en utilisant la clé secrète $\mathbf{s} = (3, 4)^T$.
Formule de déchiffrement : calculez $D = v - \mathbf{s}^T \mathbf{u} \pmod{17}$.&lt;/p>
$$ \mathbf{s}^T \mathbf{u} = (3, 4) \begin{pmatrix} 16 \\ 3 \end{pmatrix} = 3 \times 16 + 4 \times 3 = 48 + 12 = 60 \equiv 9 \pmod{17} $$
$$ D = v - \mathbf{s}^T \mathbf{u} = 1 - 9 = -8 \pmod{17} $$
&lt;p>Ici, dans le monde modulo 17, $-8$ est égal à $9$ ($-8 + 17 = 9$).
Déterminez si la valeur obtenue $D = 9$ est plus proche de $0$ ou de $8$ ($\lfloor 17/2 \rfloor$).
Étant donné que $9$ est clairement plus proche de $8$ que de $0$, Bob a pu restaurer correctement $M = 1$ !&lt;/p>
&lt;p>Pourquoi est-ce devenu $9$ ? Rappelons la preuve précédente.
La partie d&amp;rsquo;erreur est $\mathbf{e}^T \mathbf{r} = (1, -1, 0, 2) (1, 0, 1, 0)^T = 1 \times 1 + 0 \times 1 = 1$.
Par conséquent, le résultat du calcul est $\mathbf{e}^T \mathbf{r} + M \cdot 8 = 1 + 8 = 9$, et il est confirmé que la valeur théorique a été calculée.&lt;/p>
&lt;h1 id="7-évolution-vers-une-application-pratique--ring-lwe-et-module-lwe">7. Évolution vers une application pratique : Ring-LWE et Module-LWE
&lt;/h1>&lt;p>Le problème LWE standard (Standard LWE) expliqué jusqu&amp;rsquo;à présent possède une preuve de sécurité très solide, mais présente un défaut fatal dans la pratique. C&amp;rsquo;est &amp;ldquo;la taille énorme de la clé&amp;rdquo; et le &amp;ldquo;coût de calcul élevé&amp;rdquo;.&lt;/p>
&lt;p>Dans le Standard LWE, la clé publique contient une énorme matrice $A \in \mathbb{Z}_q^{m \times n}$. Lorsque le paramètre $n$ atteint des centaines ou des milliers, la taille de cette matrice atteint plusieurs mégaoctets, ce qui est trop lourd pour être envoyé et reçu à chaque fois dans les protocoles de communication Internet (tels que TLS). De plus, la multiplication d&amp;rsquo;une matrice et d&amp;rsquo;un vecteur nécessite une complexité de calcul de $\mathcal{O}(n^2)$.&lt;/p>
&lt;p>Pour résoudre ce problème, on a introduit &amp;ldquo;Ring-LWE (RLWE)&amp;rdquo; et &amp;ldquo;Module-LWE (MLWE)&amp;rdquo;, qui intègrent une structure algébrique appelée anneaux de polynômes (Polynomial rings) dans le réseau.&lt;/p>
&lt;h2 id="71-intuition-de-ring-lwe">7.1 Intuition de Ring-LWE
&lt;/h2>&lt;p>Dans Ring-LWE, les vecteurs et les matrices sont remplacés par des éléments (polynômes) sur l&amp;rsquo;anneau de polynômes $\mathcal{R}_q = \mathbb{Z}_q[X]/(X^n + 1)$. (Ici, $n$ est choisi comme une puissance de 2).&lt;/p>
&lt;p>Alors que la clé publique de Standard LWE était la matrice $A$, Ring-LWE utilise un seul polynôme $a(x)$. La clé secrète $s(x)$ et l&amp;rsquo;erreur $e(x)$ deviennent également des polynômes.
L&amp;rsquo;équation est la suivante :
&lt;/p>
$$ b(x) = a(x) \cdot s(x) + e(x) \pmod q $$
&lt;p>Comme il s&amp;rsquo;agit d&amp;rsquo;une multiplication de polynômes, la complexité de calcul peut être considérablement réduite à $\mathcal{O}(n \log n)$ en utilisant la &amp;ldquo;Transformation Numérique Théorique (Number Theoretic Transform: NTT)&amp;rdquo;, qui est similaire à la Transformation de Fourier Rapide (FFT). De plus, puisque la taille de la clé publique est également réduite d&amp;rsquo;une matrice à un seul polynôme, la taille des données est réduite à $\mathcal{O}(n)$. Cela apporte un avantage écrasant en termes de bande passante de communication.&lt;/p>
&lt;p>D&amp;rsquo;un point de vue mathématique, Ring-LWE ne repose pas sur un réseau général, mais se réduit à un problème sur un réseau doté d&amp;rsquo;une symétrie spéciale appelé &amp;ldquo;réseau idéal (Ideal Lattice)&amp;rdquo;.&lt;/p>
&lt;h2 id="72-module-lwe-et-normalisation-du-nist-kyber--ml-kem">7.2 Module-LWE et normalisation du NIST (Kyber / ML-KEM)
&lt;/h2>&lt;p>Ring-LWE est efficace, mais il y avait quelques inquiétudes quant au fait que la structure algébrique spéciale du réseau idéal puisse devenir un indice pour de futures attaques. Ainsi, le &amp;ldquo;Module-LWE (MLWE)&amp;rdquo; a été créé en prenant le meilleur des deux mondes : la sécurité conservatrice de Standard LWE et l&amp;rsquo;efficacité de Ring-LWE.&lt;/p>
&lt;p>Dans Module-LWE, nous considérons de petites matrices et des vecteurs dont les éléments sont des polynômes. En d&amp;rsquo;autres termes, nous traitons des modules sur l&amp;rsquo;anneau.
Actuellement, &amp;ldquo;CRYSTALS-Kyber&amp;rdquo; (nom standardisé : ML-KEM), qui a été sélectionné par le NIST comme norme pour l&amp;rsquo;algorithme d&amp;rsquo;échange de clés PQC (KEM), est construit précisément sur la difficulté de ce problème Module-LWE.&lt;/p>
&lt;h1 id="8-pourquoi-est-ce-sûr-face-aux-ordinateurs-quantiques-">8. Pourquoi est-ce sûr face aux ordinateurs quantiques ?
&lt;/h1>&lt;p>Enfin, abordons le point essentiel : &amp;ldquo;Pourquoi considère-t-on que la cryptographie basée sur les réseaux ne sera pas brisée même avec des ordinateurs quantiques ?&amp;rdquo;&lt;/p>
&lt;p>L&amp;rsquo;algorithme de Shor, grâce auquel les ordinateurs quantiques brisent le chiffrement RSA et la cryptographie sur les courbes elliptiques, est essentiellement un algorithme qui résout le &amp;ldquo;problème du sous-groupe caché (Hidden Subgroup Problem: HSP)&amp;rdquo;. La structure mathématique derrière RSA et ECC (groupes abéliens finis) présente une périodicité, et en utilisant une opération spécifique à l&amp;rsquo;algorithme quantique appelée Transformée de Fourier Quantique (QFT), cette période (le sous-groupe caché) peut être extraite en une seule fois.&lt;/p>
&lt;p>Cependant, les problèmes de réseaux sont fondamentalement différents. Bien que les réseaux aient également une périodicité, ce qui est requis dans SVP et CVP sont des propriétés géométriques non linéaires telles que &amp;ldquo;la distance la plus courte&amp;rdquo; ou &amp;ldquo;la suppression du bruit&amp;rdquo;. Même si nous appliquons la &amp;ldquo;Transformée de Fourier quantique sur un groupe abélien&amp;rdquo; comme l&amp;rsquo;algorithme de Shor tel quel, nous ne pouvons pas extraire efficacement les informations utiles qui seraient la solution au problème du réseau. Jusqu&amp;rsquo;à présent, aucun algorithme quantique capable de résoudre SVP ou LWE en temps polynomial n&amp;rsquo;a été découvert, et on croit largement que même avec la capacité de calcul parallèle des ordinateurs quantiques, seuls des moyens de résolution proches d&amp;rsquo;une recherche par force brute (une accélération de l&amp;rsquo;ordre de la racine carrée grâce à l&amp;rsquo;algorithme de Grover) sont valables.&lt;/p>
&lt;h1 id="9-conclusion">9. Conclusion
&lt;/h1>&lt;p>Dans cet article, nous avons expliqué en détail l&amp;rsquo;intuition mathématique de la cryptographie sur les réseaux, en commençant par la définition géométrique du réseau, la formulation du problème LWE, et jusqu&amp;rsquo;à la construction d&amp;rsquo;une cryptographie à clé publique.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Le réseau (Lattice)&lt;/strong> est un espace discret représenté par des combinaisons linéaires à coefficients entiers de vecteurs de base, et il devient difficile de trouver une &amp;ldquo;bonne base&amp;rdquo; proche de l&amp;rsquo;orthogonalité dans les dimensions élevées (SVP).&lt;/li>
&lt;li>&lt;strong>Le problème LWE (Learning With Errors)&lt;/strong> est le problème de la résolution d&amp;rsquo;équations linéaires simultanées avec du bruit, ce qui est lié à la difficulté du problème du pire cas du réseau, fournissant ainsi une base solide de sécurité.&lt;/li>
&lt;li>En utilisant le problème LWE, le chiffrement et le déchiffrement (&lt;strong>Cryptosystème de Regev&lt;/strong>) sont réalisés grâce à un mécanisme ingénieux d&amp;rsquo;ajout et de suppression intentionnelle de bruit.&lt;/li>
&lt;li>Dans les protocoles réels, &lt;strong>Ring-LWE&lt;/strong> et &lt;strong>Module-LWE&lt;/strong> utilisant des anneaux de polynômes sont adoptés pour améliorer l&amp;rsquo;efficacité de la communication et la vitesse de calcul, et servent de base au &lt;strong>ML-KEM&lt;/strong> standard du NIST.&lt;/li>
&lt;/ol>
&lt;p>À l&amp;rsquo;approche du changement de paradigme informatique sans précédent que représentent les ordinateurs quantiques, il est très romantique de penser que la &amp;ldquo;cryptographie sur les réseaux&amp;rdquo;, née des profondeurs de l&amp;rsquo;algèbre linéaire classique et de la théorie des nombres, soutiendra la fondation de la sécurité Internet de demain. Les mathématiques qui sous-tendent la cryptographie sur les réseaux ne sont en aucun cas trop complexes, et avec des connaissances de base en algèbre linéaire et en probabilités, vous pouvez parfaitement comprendre sa belle structure. Nous espérons que cet article vous aidera à comprendre la cryptographie basée sur les réseaux, qui est au cœur de la PQC.&lt;/p></description></item><item><title>Hypothèse de Riemann et distribution des nombres premiers : une relation profonde avec la cryptographie moderne</title><link>http://kenji.blog/fr/p/riemann-hypothesis-prime-distribution-cryptography/</link><pubDate>Fri, 11 Sep 2026 16:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/riemann-hypothesis-prime-distribution-cryptography/</guid><description>&lt;img src="http://kenji.blog/p/riemann-hypothesis-prime-distribution-cryptography/img/eyecatch.jpg" alt="Featured image of post Hypothèse de Riemann et distribution des nombres premiers : une relation profonde avec la cryptographie moderne" />&lt;h1 id="1-introduction--le-mystère-cosmique-des-nombres-premiers-et-lhypothèse-de-riemann">1. Introduction : Le mystère cosmique des nombres premiers et l&amp;rsquo;hypothèse de Riemann
&lt;/h1>&lt;p>Les « nombres premiers » (Prime Numbers) sont des entiers naturels qui ne sont divisibles que par 1 et par eux-mêmes, et sont souvent appelés les « atomes » du monde mathématique. La suite 2, 3, 5, 7, 11, 13&amp;hellip; semble à première vue désordonnée et aléatoire. Depuis que le mathématicien grec antique Euclide a prouvé qu&amp;rsquo;« il existe une infinité de nombres premiers », d&amp;rsquo;innombrables mathématiciens ont tenté de percer les régularités cachées dans cette suite de nombres premiers.&lt;/p>
&lt;p>Celle qui s&amp;rsquo;est le plus rapprochée du mystère des nombres premiers est l&amp;rsquo;&lt;strong>« Hypothèse de Riemann » (Riemann Hypothesis)&lt;/strong>, proposée en 1859 par le mathématicien allemand Bernhard Riemann. L&amp;rsquo;hypothèse de Riemann est l&amp;rsquo;un des problèmes les plus importants et non résolus des mathématiques modernes, et elle fait partie des Problèmes du prix du millénaire définis par l&amp;rsquo;Institut de mathématiques Clay, avec une récompense d&amp;rsquo;un million de dollars.&lt;/p>
&lt;p>À première vue, un problème difficile de mathématiques pures concernant la distribution des nombres premiers peut sembler sans rapport avec notre vie quotidienne. Cependant, la sécurité de l&amp;rsquo;infrastructure d&amp;rsquo;Internet qui soutient la société moderne, en particulier &lt;strong>les technologies de cryptographie moderne telles que le chiffrement RSA et la cryptographie sur les courbes elliptiques (ECC)&lt;/strong>, dépend profondément des propriétés des nombres premiers géants.&lt;/p>
&lt;p>Dans cet article, nous entreprendrons un voyage mathématique allant de la distribution des nombres premiers au théorème des nombres premiers, à la fonction zêta de Riemann, pour atteindre le cœur de l&amp;rsquo;hypothèse de Riemann. Nous explorerons en profondeur comment elle est liée à la cryptographie moderne et ce qu&amp;rsquo;il adviendrait du monde si l&amp;rsquo;hypothèse de Riemann venait à être prouvée.&lt;/p>
&lt;hr>
&lt;h1 id="2-le-théorème-des-nombres-premiers-et-la-distribution-des-nombres-premiers--la-découverte-de-gauss">2. Le théorème des nombres premiers et la distribution des nombres premiers : La découverte de Gauss
&lt;/h1>&lt;p>Afin de comprendre comment les nombres premiers sont distribués, les mathématiciens ont considéré la &lt;strong>fonction de compte des nombres premiers (Prime-counting function)&lt;/strong> $\pi(x)$, qui représente « combien de nombres premiers existent inférieurs ou égaux à un certain nombre $x$ ».&lt;/p>
&lt;p>Par exemple :&lt;/p>
&lt;ul>
&lt;li>$\pi(10) = 4$ (2, 3, 5, 7)&lt;/li>
&lt;li>$\pi(100) = 25$&lt;/li>
&lt;li>$\pi(1000) = 168$&lt;/li>
&lt;/ul>
&lt;p>Carl Friedrich Gauss, mathématicien de génie de 15 ans, a calculé d&amp;rsquo;énormes tables de nombres premiers et a découvert que la fréquence d&amp;rsquo;apparition des nombres premiers diminue de manière inversement proportionnelle au logarithme népérien $\ln x$. En d&amp;rsquo;autres termes, il a conjecturé que la probabilité de trouver un nombre premier autour d&amp;rsquo;un certain nombre $x$ est d&amp;rsquo;environ $\frac{1}{\ln x}$.&lt;/p>
&lt;p>L&amp;rsquo;expression de cela à l&amp;rsquo;aide d&amp;rsquo;une intégrale est le &lt;strong>logarithme intégral (Logarithmic integral)&lt;/strong> $\text{Li}(x)$.&lt;/p>
$$ \text{Li}(x) = \int_{2}^{x} \frac{dt}{\ln t} $$
&lt;p>La conjecture de Gauss a ensuite été prouvée indépendamment en 1896 par Jacques Hadamard et Charles-Jean de La Vallée Poussin, et a été établie en tant que &lt;strong>théorème des nombres premiers (Prime Number Theorem, PNT)&lt;/strong>.&lt;/p>
$$ \lim_{x \to \infty} \frac{\pi(x)}{\text{Li}(x)} = 1 $$
&lt;p>Ou de manière approximative, il s&amp;rsquo;exprime comme suit :&lt;/p>
$$ \pi(x) \sim \frac{x}{\ln x} $$
&lt;p>Grâce à ce théorème, nous savons que les nombres premiers ont une distribution très lisse et prévisible d&amp;rsquo;un point de vue macroscopique. Cependant, d&amp;rsquo;un point de vue microscopique, il existe toujours une « erreur » ou une « fluctuation » entre $\pi(x)$ et $\text{Li}(x)$. La véritable nature de cette fluctuation est le plus grand mystère que l&amp;rsquo;hypothèse de Riemann tente de résoudre.&lt;/p>
&lt;hr>
&lt;h1 id="3-la-fonction-zêta-de-riemann-et-le-produit-eulerien">3. La fonction zêta de Riemann et le produit eulerien
&lt;/h1>&lt;p>L&amp;rsquo;arme la plus puissante pour analyser la distribution des nombres premiers est la &lt;strong>fonction zêta de Riemann (Riemann Zeta Function)&lt;/strong>. À l&amp;rsquo;origine, il s&amp;rsquo;agissait d&amp;rsquo;une série infinie définie par Leonhard Euler pour les nombres réels $s > 1$.&lt;/p>
$$ \zeta(s) = \sum_{n=1}^\infty \frac{1}{n^s} = 1 + \frac{1}{2^s} + \frac{1}{3^s} + \frac{1}{4^s} + \dots $$
&lt;p>L&amp;rsquo;une des plus grandes réalisations d&amp;rsquo;Euler a été de prouver que cette série infinie peut être exprimée comme un produit infini sur tous les nombres premiers $p$. C&amp;rsquo;est le &lt;strong>produit eulerien (Euler Product Formula)&lt;/strong>.&lt;/p>
$$ \zeta(s) = \prod_{p \text{ prime}} \frac{1}{1 - p^{-s}} = \left( \frac{1}{1 - 2^{-s}} \right) \left( \frac{1}{1 - 3^{-s}} \right) \left( \frac{1}{1 - 5^{-s}} \right) \dots $$
&lt;p>La compréhension intuitive de la preuve est que si vous développez chaque terme du côté droit comme une série géométrique et que vous les multipliez, le théorème fondamental de l&amp;rsquo;arithmétique (tout entier naturel est exprimé de manière unique comme un produit de nombres premiers) reconstruira parfaitement la somme des inverses des entiers naturels du côté gauche.&lt;/p>
&lt;p>&lt;strong>Cette seule équation est devenue un pont reliant l&amp;rsquo;analyse (séries infinies / fonctions continues) et la théorie des nombres (nombres premiers / nombres discrets).&lt;/strong> Étudier la fonction zêta est synonyme d&amp;rsquo;étudier la distribution des nombres premiers.&lt;/p>
&lt;hr>
&lt;h1 id="4-prolongement-analytique-et-extension-au-plan-complexe">4. Prolongement analytique et extension au plan complexe
&lt;/h1>&lt;p>Le génie de Riemann réside dans l&amp;rsquo;extension de la variable $s$ de $\zeta(s)$, qu&amp;rsquo;Euler ne considérait que pour les nombres réels, à des &lt;strong>nombres complexes $s = \sigma + it$ ($\sigma$ est la partie réelle, $t$ est la partie imaginaire)&lt;/strong>.&lt;/p>
&lt;p>La série infinie originale ne converge que pour $\sigma > 1$, mais Riemann a utilisé une méthode appelée « prolongement analytique (Analytic Continuation) » pour étendre la définition de sorte que $\zeta(s)$ ait un sens sur l&amp;rsquo;ensemble du plan complexe, à l&amp;rsquo;exception du pôle en $s = 1$.&lt;/p>
&lt;p>Il a en outre dérivé une magnifique équation fonctionnelle (Functional equation) satisfaite par la fonction zêta.&lt;/p>
$$ \zeta(s) = 2^s \pi^{s-1} \sin\left(\frac{\pi s}{2}\right) \Gamma(1-s) \zeta(1-s) $$
&lt;p>Où $\Gamma(x)$ est la fonction gamma. Cette équation nous permet de connaître les propriétés du demi-plan gauche à partir des propriétés du demi-plan droit.&lt;/p>
&lt;h3 id="zéros-zeros-of-the-zeta-function">Zéros (Zeros of the Zeta Function)
&lt;/h3>&lt;p>Les nombres complexes $s$ où la valeur de la fonction zêta devient 0 sont appelés « zéros ».
D&amp;rsquo;après l&amp;rsquo;équation fonctionnelle, lorsque $s$ est un nombre pair négatif ($-2, -4, -6, \dots$), $\sin(\pi s / 2)$ devient 0, donc $\zeta(s) = 0$. Ceux-ci sont appelés les &lt;strong>zéros triviaux (Trivial zeros)&lt;/strong>.&lt;/p>
&lt;p>Cependant, ce qui est important dans la distribution des nombres premiers, ce sont les autres zéros, à savoir les &lt;strong>zéros non triviaux (Non-trivial zeros)&lt;/strong> qui existent dans la « bande critique (Critical strip) » où $0 \le \sigma \le 1$.&lt;/p>
&lt;hr>
&lt;h1 id="5-le-cœur-de-lhypothèse-de-riemann-et-la-formule-explicite">5. Le cœur de l&amp;rsquo;hypothèse de Riemann et la formule explicite
&lt;/h1>&lt;p>Riemann a calculé un petit nombre de zéros et a formulé une conjecture étonnante. C&amp;rsquo;est l&amp;rsquo;&lt;strong>hypothèse de Riemann&lt;/strong>.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Hypothèse de Riemann (Riemann Hypothesis)&lt;/strong>
Tous les zéros non triviaux de la fonction zêta de Riemann $\zeta(s)$ ont une partie réelle égale à $1/2$ (c&amp;rsquo;est-à-dire $\text{Re}(s) = 1/2$).&lt;/p>
&lt;/blockquote>
&lt;p>Cette droite où la partie réelle est de 1/2 est appelée la « droite critique (Critical line) ».&lt;/p>
&lt;div class="mermaid">graph TD
A["Fonction zêta de Riemann ζ(s)"] --> B["Extension au plan complexe par prolongement analytique"]
B --> C["Zéros triviaux (s = -2, -4, -6 ...)"]
B --> D["Zéros non triviaux (0 &lt;= Re(s) &lt;= 1)"]
D --> E["Hypothèse de Riemann"]
E --> F["Tous les zéros non triviaux sont sur Re(s) = 1/2"]
F --> G["Vers la preuve de la limite du terme d'erreur de la distribution des nombres premiers"]&lt;/div>
&lt;p>Pourquoi l&amp;rsquo;hypothèse de Riemann est-elle si importante ? C&amp;rsquo;est parce que les zéros de la fonction zêta déterminent &lt;strong>complètement&lt;/strong> la distribution des nombres premiers.&lt;/p>
&lt;p>Riemann, et plus tard le mathématicien von Mangoldt, ont dérivé une « formule explicite (Explicit formula) » qui décrit avec précision la distribution des nombres premiers. En utilisant la fonction de Tchebychev $\psi(x)$, elle s&amp;rsquo;exprime comme suit :&lt;/p>
$$ \psi(x) = x - \sum_{\rho} \frac{x^\rho}{\rho} - \ln(2\pi) - \frac{1}{2}\ln(1 - x^{-2}) $$
&lt;p>Où $\rho$ est la somme sur tous les zéros non triviaux de la fonction zêta.
Le terme principal est $x$ (qui correspond au théorème des nombres premiers), et en ajoutant et en soustrayant des termes ondulatoires dépendant des zéros $\rho$, la distribution en escalier exacte des nombres premiers est restaurée. On peut dire que les zéros non triviaux représentent les « fréquences (ondes) » de la distribution des nombres premiers.&lt;/p>
&lt;p>Si l&amp;rsquo;hypothèse de Riemann est vraie, et que la partie réelle de tous les zéros non triviaux $\rho$ est exactement de $1/2$, alors le terme d&amp;rsquo;erreur du théorème des nombres premiers se situera dans la plus petite plage théoriquement concevable.&lt;/p>
$$ |\pi(x) - \text{Li}(x)| \le \frac{1}{8\pi} \sqrt{x} \ln x \quad \text{for} \quad x \ge 2657 $$
&lt;p>En d&amp;rsquo;autres termes, &lt;strong>si l&amp;rsquo;hypothèse de Riemann est vraie, il sera prouvé que les nombres premiers sont distribués de la manière la plus « régulière et belle » que nous puissions imaginer&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h1 id="6-la-cryptographie-moderne-et-sa-relation-indissociable-avec-les-nombres-premiers">6. La cryptographie moderne et sa relation indissociable avec les nombres premiers
&lt;/h1>&lt;p>Jusqu&amp;rsquo;ici, nous étions dans le monde profond des mathématiques pures, mais ces propriétés des nombres premiers soutiennent fondamentalement la société numérique moderne. Le représentant de cela est la cryptographie à clé publique telle que le &lt;strong>chiffrement RSA&lt;/strong>.&lt;/p>
&lt;p>La sécurité de toutes les communications, y compris les paiements par carte de crédit sur Internet, la transmission de mots de passe et les signatures numériques de la blockchain, dépend des « nombres premiers ».&lt;/p>
&lt;h3 id="fonctionnement-du-chiffrement-rsa">Fonctionnement du chiffrement RSA
&lt;/h3>&lt;p>La sécurité du chiffrement RSA est basée sur le fait mathématique (problème de la factorisation) qu&amp;rsquo;« il est très difficile de factoriser un nombre composé avec un grand nombre de chiffres ».&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Génération de clés&lt;/strong>:
Choisissez au hasard de très grands nombres premiers $p$ et $q$ (par exemple, 2048 bits chacun).
Multipliez-les pour calculer $N = p \times q$. Ce $N$ fera partie de la clé publique.
En utilisant l&amp;rsquo;indicatrice d&amp;rsquo;Euler $\phi(N) = (p-1)(q-1)$, générez la clé privée $d$.&lt;/p>
$$ e \times d \equiv 1 \pmod{\phi(N)} $$
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Chiffrement et déchiffrement&lt;/strong>:
Le texte en clair $M$ est converti en texte chiffré $C$ à l&amp;rsquo;aide de la clé publique $e, N$.
&lt;/p>
$$ C \equiv M^e \pmod{N} $$
&lt;p>
Seul celui qui possède la clé privée $d$ peut le déchiffrer.
&lt;/p>
$$ M \equiv C^d \pmod{N} $$
&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph LR
A["Texte en clair (Plaintext)"] --> B["Chiffrer avec la clé publique (e, N)"]
B --> C["Texte chiffré (Ciphertext)"]
C --> D["Déchiffrer avec la clé privée (d)"]
D --> E["Texte en clair original"]
F["Attaquant (Attacker)"] -- "Tente de factoriser N" --> C
F -.-> G["Impossible de calculer d sans connaître p et q"]&lt;/div>
&lt;p>Pour casser le chiffrement RSA, il faut trouver (factoriser) les nombres premiers originaux $p$ et $q$ à partir du gigantesque $N$. Même en utilisant les algorithmes les plus courants (Crible algébrique : GNFS, etc.), la factorisation d&amp;rsquo;un nombre de centaines de chiffres prendrait un temps dépassant de loin l&amp;rsquo;âge de l&amp;rsquo;univers, même avec des superordinateurs.&lt;/p>
&lt;hr>
&lt;h1 id="7-limpact-de-lhypothèse-de-riemann-sur-la-cryptographie">7. L&amp;rsquo;impact de l&amp;rsquo;hypothèse de Riemann sur la cryptographie
&lt;/h1>&lt;p>Alors, comment « l&amp;rsquo;hypothèse de Riemann » au sommet des mathématiques pures et la « cryptographie » se croisent-elles ?&lt;/p>
&lt;h3 id="71-algorithmes-de-génération-de-nombres-premiers-test-de-primalité-et-lhypothèse-de-riemann-généralisée-grh">7.1. Algorithmes de génération de nombres premiers (test de primalité) et l&amp;rsquo;hypothèse de Riemann généralisée (GRH)
&lt;/h3>&lt;p>Pour utiliser le chiffrement RSA, il faut d&amp;rsquo;abord générer des nombres premiers géants $p$ et $q$. Cependant, déterminer de manière fiable et rapide si « un certain nombre est premier » n&amp;rsquo;est pas facile.&lt;/p>
&lt;p>Actuellement, l&amp;rsquo;algorithme pratique utilisé est le &lt;strong>test de primalité de Miller-Rabin (Miller-Rabin primality test)&lt;/strong>, qui est un algorithme probabiliste. Cet algorithme est rapide, mais il existe un risque de « pseudo-premiers » où un nombre composé est identifié à tort comme premier avec une probabilité extrêmement faible.&lt;/p>
&lt;p>Cependant, si l&amp;rsquo;&lt;strong>« Hypothèse de Riemann généralisée (Generalized Riemann Hypothesis, GRH) »&lt;/strong>, qui étend l&amp;rsquo;hypothèse de Riemann aux fonctions L de Dirichlet, est supposée vraie, la situation change radicalement.
Si la GRH est vraie, la limite supérieure du nombre de tests dans le test de Miller-Rabin est mathématiquement garantie, et elle passe d&amp;rsquo;un algorithme probabiliste à un &lt;strong>« algorithme déterministe en temps polynomial »&lt;/strong> (C&amp;rsquo;était un fait majeur connu avant même la découverte du test de primalité AKS).&lt;/p>
&lt;p>En d&amp;rsquo;autres termes, l&amp;rsquo;hypothèse de Riemann (et son extension) joue un rôle dans l&amp;rsquo;approbation directe de la génération de base de la cryptographie : « Pouvons-nous générer des nombres premiers géants rapidement et avec une confiance absolue ? ».&lt;/p>
&lt;h3 id="72-relation-avec-les-algorithmes-de-factorisation">7.2. Relation avec les algorithmes de factorisation
&lt;/h3>&lt;p>Lors de l&amp;rsquo;évaluation de la complexité des algorithmes pour le décryptage (comme le crible algébrique), la connaissance de la distribution des nombres premiers est indispensable. De nombreux algorithmes de factorisation dépendent de la distribution des « nombres friables (Smooth numbers : nombres qui n&amp;rsquo;ont que de petits facteurs premiers) ».&lt;/p>
&lt;p>Pour évaluer rigoureusement la fréquence d&amp;rsquo;apparition des nombres friables, une compréhension profonde de la distribution des nombres premiers est requise, et ici aussi, des techniques de théorie analytique des nombres directement liées à la fonction zêta et à l&amp;rsquo;hypothèse de Riemann sont pleinement utilisées. Si l&amp;rsquo;hypothèse de Riemann est prouvée et que l&amp;rsquo;erreur de la distribution des nombres premiers est complètement déterminée, il sera possible d&amp;rsquo;évaluer plus précisément les limites de performance des algorithmes de factorisation.&lt;/p>
&lt;hr>
&lt;h1 id="8-si-lhypothèse-de-riemann-est-prouvée-la-cryptographie-sera-t-elle-cassée-">8. Si l&amp;rsquo;hypothèse de Riemann est prouvée, la cryptographie sera-t-elle cassée ?
&lt;/h1>&lt;p>On dit parfois comme une légende urbaine que « si l&amp;rsquo;hypothèse de Riemann est résolue, le chiffrement RSA s&amp;rsquo;effondrera en un instant », mais &lt;strong>c&amp;rsquo;est mathématiquement inexact&lt;/strong>.&lt;/p>
&lt;p>La preuve de l&amp;rsquo;hypothèse de Riemann elle-même ne créera pas immédiatement un algorithme magique qui accélère considérablement la factorisation. L&amp;rsquo;hypothèse de Riemann n&amp;rsquo;est qu&amp;rsquo;un théorème sur la « régularité de la distribution macroscopique » des nombres premiers, et elle ne nous dit pas directement par quels nombres premiers un nombre individuel $N$ est divisible (propriété locale).&lt;/p>
&lt;p>Cependant, l&amp;rsquo;impact n&amp;rsquo;est pas nul.
Il est extrêmement probable que de &lt;strong>« nouveaux outils mathématiques » et des « méthodes analytiques inconnues » soient découverts&lt;/strong> au cours du processus de démonstration de l&amp;rsquo;hypothèse de Riemann. L&amp;rsquo;histoire montre que lorsque le dernier théorème de Fermat et la conjecture de Poincaré ont été prouvés, les nouvelles théories développées au cours du processus ont fait progresser les mathématiques dans leur ensemble.&lt;/p>
&lt;p>Si des méthodes géométriques algébriques inconnues ou des méthodes géométriques non commutatives permettant de manipuler complètement les propriétés des zéros de la fonction zêta de Riemann sont établies, il n&amp;rsquo;est pas exclu que cela conduise à la découverte d&amp;rsquo;un algorithme révolutionnaire de factorisation (par exemple, un algorithme classique qui réduit la complexité au temps polynomial). En ce sens, les cryptographes ne peuvent jamais quitter des yeux les développements de l&amp;rsquo;hypothèse de Riemann.&lt;/p>
&lt;h3 id="ordinateurs-quantiques-et-algorithme-de-shor">Ordinateurs quantiques et algorithme de Shor
&lt;/h3>&lt;p>Une menace plus directe et réaliste pour la cryptographie n&amp;rsquo;est pas la preuve de l&amp;rsquo;hypothèse de Riemann, mais les &lt;strong>ordinateurs quantiques&lt;/strong>. « L&amp;rsquo;algorithme de Shor » publié par Peter Shor en 1994 a prouvé qu&amp;rsquo;avec un ordinateur quantique suffisamment performant, la factorisation peut être résolue en temps polynomial. Cela casserait fondamentalement le chiffrement RSA et la cryptographie sur les courbes elliptiques.&lt;/p>
&lt;p>Actuellement, une transition vers la « cryptographie post-quantique (Post-Quantum Cryptography, PQC) » (comme la cryptographie fondée sur les réseaux) qui ne peut pas être déchiffrée même par des ordinateurs quantiques progresse dans le monde entier. Les technologies de cryptographie basées sur les nombres premiers peuvent en un sens atteindre la fin de leur âge d&amp;rsquo;or, mais la valeur mathématique des nombres premiers eux-mêmes ne sera jamais perdue.&lt;/p>
&lt;hr>
&lt;h1 id="9-conclusion--lintersection-de-labstraction-mathématique-et-de-la-société-réelle">9. Conclusion : L&amp;rsquo;intersection de l&amp;rsquo;abstraction mathématique et de la société réelle
&lt;/h1>&lt;div class="mermaid">graph TD
A["Exploration des mathématiques pures"] --> B["Élucidation de l'hypothèse de Riemann"]
B --> C["Compréhension complète de la distribution des nombres premiers"]
C --> D["Développement spectaculaire de la théorie des nombres et de la géométrie algébrique"]
D -.-> E["Possibilité de nouveaux algorithmes de factorisation"]
E -.-> F["Mise à jour de l'évaluation de la sécurité cryptographique"]
A --> G["Mathématiques appliquées et informatique"]
G --> H["Efficacité des tests de primalité et de la génération cryptographique"]
H --> F&lt;/div>
&lt;p>La quête insatiable des nombres premiers, qui se poursuit depuis la Grèce antique, a été sublimée par le génie de Riemann en une magnifique symphonie sur le plan complexe (les zéros de la fonction zêta). Et étonnamment, ce cristal pur et immaculé des mathématiques est appliqué des siècles plus tard comme le bouclier le plus puissant garantissant la sécurité de la société de l&amp;rsquo;information.&lt;/p>
&lt;p>L&amp;rsquo;hypothèse de Riemann est une entité qui symbolise à la fois la « beauté abstraite » des mathématiques et sa « stupéfiante applicabilité au monde physique et à la société réelle ».&lt;/p>
&lt;p>Lorsqu&amp;rsquo;un jour cette immense montagne mathématique, dont personne n&amp;rsquo;a encore atteint le sommet, sera conquise, nous comprendrons parfaitement la vérité cosmique des nombres premiers et acquerrons une nouvelle perspective sur les fondements de la société de l&amp;rsquo;information. L&amp;rsquo;étude de la cryptographie est aussi un voyage à travers l&amp;rsquo;histoire de la sagesse humaine.&lt;/p></description></item><item><title>Algorithmes de test de primalité rapides implémentés en C++ (méthode de Miller-Rabin, etc.)</title><link>http://kenji.blog/fr/p/cpp-fast-prime-testing-miller-rabin/</link><pubDate>Fri, 11 Sep 2026 14:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/cpp-fast-prime-testing-miller-rabin/</guid><description>&lt;img src="http://kenji.blog/p/cpp-fast-prime-testing-miller-rabin/img/eyecatch.jpg" alt="Featured image of post Algorithmes de test de primalité rapides implémentés en C++ (méthode de Miller-Rabin, etc.)" />&lt;h1 id="introduction--pourquoi-avons-nous-besoin-de-tests-de-primalité-rapides-">Introduction : Pourquoi avons-nous besoin de tests de primalité rapides ?
&lt;/h1>&lt;p>Dans le monde de l&amp;rsquo;informatique, de la théorie de la cryptographie ou de la programmation compétitive, déterminer rapidement et précisément &amp;ldquo;si un certain nombre est premier ou non&amp;rdquo; est un défi fondamental et extrêmement important. Par exemple, la cryptographie à clé publique telle que RSA, qui soutient la sécurité de la société Internet moderne, base sa sécurité sur la génération d&amp;rsquo;énormes nombres premiers et sur la difficulté de les multiplier (la difficulté de la factorisation en nombres premiers). Par conséquent, il n&amp;rsquo;est pas exagéré de dire que la technologie capable d&amp;rsquo;identifier instantanément si un nombre énorme est premier est la technologie qui soutient le fondement de la société numérique.&lt;/p>
&lt;p>De plus, en programmation compétitive (comme AtCoder et Codeforces), les tests de primalité sont un thème récurrent. Dans des situations où des dizaines de milliers de tests de primalité doivent être effectués en moins d&amp;rsquo;une seconde pour des entrées énormes avec des contraintes telles que $N \le 10^{18}$, les algorithmes traditionnels et naïfs ne peuvent absolument pas respecter la limite de temps de calcul (Time Limit Exceeded : TLE).&lt;/p>
&lt;p>Dans cet article, nous expliquerons en profondeur, de la base mathématique jusqu&amp;rsquo;aux implémentations hautement optimisées en C++, en commençant par des algorithmes naïfs de test de primalité, puis le &amp;ldquo;test de Fermat&amp;rdquo;, qui est un test de primalité probabiliste, et enfin l&amp;rsquo;algorithme rapide de niveau pratique le plus puissant qui surmonte ses faiblesses : le &amp;ldquo;test de primalité de Miller-Rabin&amp;rdquo;. En particulier, pour les entiers de 64 bits ($N &lt; 2^{64}$), nous expliquerons en détail la méthode qui ne se limite pas à un test probabiliste mais &amp;ldquo;peut tester la primalité avec 100% de certitude (test déterministe)&amp;rdquo;, et fournirons un code source en C++ prêt à être utilisé en pratique.&lt;/p>
&lt;hr>
&lt;h1 id="1-les-bases-du-test-de-primalité-et-la-méthode-des-divisions-successives-trial-division">1. Les bases du test de primalité et la méthode des divisions successives (Trial Division)
&lt;/h1>&lt;p>Un nombre premier (Prime number) est un entier naturel supérieur ou égal à 2 qui n&amp;rsquo;a de diviseurs positifs que 1 et lui-même. En suivant fidèlement la définition d&amp;rsquo;un nombre premier, pour déterminer si un certain entier $N$ est premier, nous pouvons essayer de diviser $N$ par tous les entiers de $2$ à $N-1$ ; s&amp;rsquo;il n&amp;rsquo;est jamais divisible, il est premier, et s&amp;rsquo;il est divisible au moins une fois, il est considéré comme un nombre composé (pas un nombre premier).&lt;/p>
&lt;p>Cependant, la complexité temporelle de cette méthode est de $O(N)$, et lorsque $N$ est un nombre énorme comme $10^{18}$, même les ordinateurs modernes prendront énormément de temps pour le calcul.&lt;/p>
&lt;h2 id="optimisation-de-la-méthode-des-divisions-successives--recherche-jusquà-sqrtn">Optimisation de la méthode des divisions successives : recherche jusqu&amp;rsquo;à $\sqrt{N}$
&lt;/h2>&lt;p>Lorsqu&amp;rsquo;un nombre composé $N$ est exprimé comme $a \times b = N$ ($a \le b$), il est certain que $a \le \sqrt{N}$. Par conséquent, il n&amp;rsquo;est pas nécessaire d&amp;rsquo;exécuter la boucle du test de primalité jusqu&amp;rsquo;à $N-1$ ; il suffit de vérifier jusqu&amp;rsquo;à $\sqrt{N}$.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Test de primalité par la méthode des divisions successives (O(sqrt(N)))
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">bool&lt;/span> &lt;span class="nf">is_prime_trial_division&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Vérifier uniquement les nombres impairs supérieurs ou égaux à 3
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>La complexité de cet algorithme est de $O(\sqrt{N})$. Si $N \le 10^{12}$, il peut être calculé en un instant, mais dans le cas de $N \approx 10^{18}$, le nombre de boucles devient d&amp;rsquo;environ $10^9$ fois, ce qui prend de quelques centaines de millisecondes à quelques secondes même avec un environnement C++, et n&amp;rsquo;est donc pas adapté pour de multiples évaluations.&lt;/p>
&lt;hr>
&lt;h1 id="2-le-test-de-fermat--laube-du-test-de-primalité-probabiliste">2. Le test de Fermat : L&amp;rsquo;aube du test de primalité probabiliste
&lt;/h1>&lt;p>Ce qui a été conçu pour surmonter les limites de la méthode des divisions successives est l&amp;rsquo;&amp;ldquo;algorithme probabiliste (Probabilistic Algorithm)&amp;rdquo; qui utilise des théorèmes de la théorie des nombres. L&amp;rsquo;exemple typique en est le &amp;ldquo;test de primalité de Fermat&amp;rdquo; utilisant le petit théorème de Fermat.&lt;/p>
&lt;h2 id="le-petit-théorème-de-fermat-fermats-little-theorem">Le petit théorème de Fermat (Fermat&amp;rsquo;s Little Theorem)
&lt;/h2>&lt;p>Ce théorème, découvert par Pierre de Fermat, affirme ce qui suit :&lt;/p>
&lt;blockquote>
&lt;p>Pour tout nombre premier $p$ et tout entier $a$ qui lui est premier (non multiple de $p$), la congruence suivante est vraie :
&lt;/p>
$$ a^{p-1} \equiv 1 \pmod p $$
&lt;/blockquote>
&lt;p>En prenant la contraposée de ce théorème, on peut dire que &amp;ldquo;pour un certain entier $N$ et un entier $a$ premier avec $N$, si $a^{N-1} \not\equiv 1 \pmod N$, alors $N$ est définitivement un nombre composé&amp;rdquo;. En utilisant cette propriété, le test de Fermat consiste à choisir une base (base) aléatoire $a$ pour le nombre cible $N$, à calculer $a^{N-1} \pmod N$ et à vérifier s&amp;rsquo;il devient $1$.&lt;/p>
&lt;h2 id="exponentiation-modulaire-rapide-méthode-dexponentiation-binaire">Exponentiation modulaire rapide (Méthode d&amp;rsquo;exponentiation binaire)
&lt;/h2>&lt;p>Pour effectuer le test de Fermat, il est nécessaire de calculer rapidement d&amp;rsquo;énormes puissances telles que $a^{N-1} \pmod N$. Pour cela, nous utilisons la &amp;ldquo;méthode d&amp;rsquo;exponentiation binaire (Modular Exponentiation / Binary Exponentiation)&amp;rdquo;. La complexité est de $O(\log N)$, ce qui est extrêmement rapide.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Calcul de a^b mod m en utilisant la méthode d&amp;#39;exponentiation binaire
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="nf">mod_pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span> &lt;span class="o">%=&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">__int128_t&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="n">res&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">__int128_t&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="n">a&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">b&lt;/span> &lt;span class="o">&amp;gt;&amp;gt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">res&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ul>
&lt;li>Ici, pour éviter les dépassements de capacité, l&amp;rsquo;extension GCC/Clang &lt;code>__int128_t&lt;/code> (entier de 128 bits) est utilisée pour conserver les produits intermédiaires.&lt;/li>
&lt;/ul>
&lt;h2 id="nombres-pseudo-premiers-et-nombres-de-carmichael-carmichael-numbers">Nombres pseudo-premiers et nombres de Carmichael (Carmichael Numbers)
&lt;/h2>&lt;p>Le test de Fermat est très puissant, mais il a une faiblesse fatale. Il existe des nombres tels que bien que $N$ soit un nombre composé, $a^{N-1} \equiv 1 \pmod N$ reste vrai pour tous les $a$ ($a$ premiers avec $N$).&lt;/p>
&lt;p>De tels nombres sont appelés &amp;ldquo;nombres pseudo-premiers absolus&amp;rdquo; ou &amp;ldquo;nombres de Carmichael&amp;rdquo;. Le plus petit nombre de Carmichael est $561 = 3 \times 11 \times 17$.
En raison de la présence de nombres de Carmichael, il n&amp;rsquo;est pas possible d&amp;rsquo;effectuer un test déterministe avec une &amp;ldquo;probabilité de 100%&amp;rdquo; en utilisant uniquement le test de Fermat. Peu importe le nombre de bases différentes $a$ que vous essayez, un nombre comme $561$ fera toujours semblant d&amp;rsquo;être premier (une tromperie).&lt;/p>
&lt;hr>
&lt;h1 id="3-test-de-primalité-de-miller-rabin-miller-rabin-primality-test">3. Test de primalité de Miller-Rabin (Miller-Rabin Primality Test)
&lt;/h1>&lt;p>Le &amp;ldquo;test de primalité de Miller-Rabin&amp;rdquo;, conçu par Miller (Gary L. Miller) et Rabin (Michael O. Rabin), a brillamment surmonté la faiblesse du test de Fermat (l&amp;rsquo;existence des nombres de Carmichael).
Aujourd&amp;rsquo;hui, il est le plus largement utilisé dans la génération de clés des systèmes cryptographiques et des bibliothèques internes de divers langages de programmation en tant algorithme de test de primalité rapide et pratique.&lt;/p>
&lt;h2 id="principes-mathématiques">Principes mathématiques
&lt;/h2>&lt;p>En plus du petit théorème de Fermat, l&amp;rsquo;algorithme de Miller-Rabin utilise la propriété selon laquelle &amp;ldquo;dans un corps fini modulo un nombre premier ($\mathbb{Z}/p\mathbb{Z}$), les seules solutions à $x^2 \equiv 1 \pmod p$ sont $x \equiv 1$ ou $x \equiv -1$&amp;rdquo; (dans le cas modulo un nombre composé, d&amp;rsquo;autres racines carrées non triviales peuvent exister).&lt;/p>
&lt;p>Si l&amp;rsquo;on soustrait $1$ au nombre impair $N$ que nous voulons tester, $N-1$ sera toujours un nombre pair. Par conséquent, nous divisons $N-1$ par $2$ autant de fois que possible, et l&amp;rsquo;exprimons sous la forme suivante :
&lt;/p>
$$ N-1 = d \cdot 2^s $$
&lt;p>
(Ici, $d$ est un nombre impair, $s \ge 1$)&lt;/p>
&lt;p>Pour toute base arbitraire $a$ ($1 &lt; a &lt; N-1$), nous vérifions si $a^{N-1} \equiv 1 \pmod N$ selon le petit théorème de Fermat, mais nous effectuons ce calcul par étapes.
Plus précisément, nous répétons la mise au carré dans l&amp;rsquo;ordre : $a^d, a^{d \cdot 2}, a^{d \cdot 4}, \ldots, a^{d \cdot 2^s}$.&lt;/p>
&lt;p>La condition pour que le test de Miller-Rabin détermine que $N$ est &amp;ldquo;premier (ou probablement premier avec une forte probabilité)&amp;rdquo; est que l&amp;rsquo;une des conditions &lt;strong>suivantes&lt;/strong> soit remplie.&lt;/p>
&lt;ol>
&lt;li>$a^d \equiv 1 \pmod N$&lt;/li>
&lt;li>Il existe un certain $r$ ($0 \le r &lt; s$) tel que $a^{d \cdot 2^r} \equiv -1 \pmod N$ soit vrai.
&lt;ul>
&lt;li>En arithmétique modulaire en C++, $-1 \pmod N$ devient $N-1$.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>Si $N$ est premier, cette condition sera toujours remplie pour n&amp;rsquo;importe quel $a$. Inversement, si $N$ est un nombre composé, lorsqu&amp;rsquo;un $a$ aléatoire est choisi, il est prouvé mathématiquement que la probabilité de remplir cette condition (la probabilité d&amp;rsquo;être trompé) est inférieure ou égale à $\frac{1}{4}$.
En effectuant $k$ tests indépendants, la probabilité d&amp;rsquo;une fausse identification devient inférieure ou égale à $\left(\frac{1}{4}\right)^k$, ce qui peut être considéré comme pratiquement nul. Il n&amp;rsquo;existe pas de nombres qui puissent &amp;ldquo;tromper de manière absolue&amp;rdquo; comme les nombres de Carmichael.&lt;/p>
&lt;h2 id="flux-de-lalgorithme-de-la-méthode-de-miller-rabin-organigramme-mermaid">Flux de l&amp;rsquo;algorithme de la méthode de Miller-Rabin (Organigramme Mermaid)
&lt;/h2>&lt;p>Le diagramme ci-dessous illustre le flux logique d&amp;rsquo;un seul test (un test pour une base $a$) de la méthode de test de primalité de Miller-Rabin.&lt;/p>
&lt;div class="mermaid">graph TD
Start["Début du test (Entrée : N, a)"] --> CalcDS["Calculer d (impair) et s tels que N-1 = d * 2^s"]
CalcDS --> CalcX["Calculer x = a^d mod N"]
CalcX --> CheckX1{"x == 1 ou x == N-1 ?"}
CheckX1 -- "Oui" --> ReturnTrue["Peut-être premier (Probably Prime)"]
CheckX1 -- "Non" --> LoopStart["Début de la boucle de r = 1 à s-1"]
LoopStart --> LoopCondition{"r &lt; s ?"}
LoopCondition -- "Non" --> ReturnFalse["Certainement composé (Composite)"]
LoopCondition -- "Oui" --> SquareX["Calculer x = (x * x) mod N"]
SquareX --> CheckXMinus1{"x == N - 1 ?"}
CheckXMinus1 -- "Oui" --> ReturnTrue
CheckXMinus1 -- "Non" --> CheckXOne{"x == 1 ?"}
CheckXOne -- "Oui" --> ReturnFalse
CheckXOne -- "Non" --> LoopNext["Incrémenter r de 1 et continuer"]
LoopNext --> LoopCondition&lt;/div>
&lt;hr>
&lt;h1 id="4-test-déterministe-pour-les-entiers-de-64-bits">4. Test déterministe pour les entiers de 64 bits
&lt;/h1>&lt;p>Bien que le test de primalité de Miller-Rabin soit fondamentalement un algorithme &amp;ldquo;probabiliste&amp;rdquo;, lorsque la limite supérieure de $N$ est fixe, on peut tester la primalité avec &amp;ldquo;100% de certitude&amp;rdquo; en essayant toutes les bases spécifiques $a$ (bases).
Ceci est appelé le &lt;strong>test de Miller-Rabin déterministe (Deterministic Miller-Rabin Test)&lt;/strong>.&lt;/p>
&lt;p>Grâce aux recherches de Jim Sinclair et d&amp;rsquo;autres, il a été révélé que pour tous les entiers $N &lt; 2^{64}$ (environ $1.8 \times 10^{19}$), un test complètement déterministe et suffisant est possible en choisissant les $7$ nombres premiers suivants comme base $a$.&lt;/p>
&lt;p>&lt;strong>Liste des bases $a$ à tester :&lt;/strong>
&lt;code>{2, 325, 9375, 28178, 450775, 9780504, 1795265022}&lt;/code>&lt;/p>
&lt;p>Alternativement, en utilisant un autre ensemble bien connu des $12$ nombres premiers suivants, une détermination parfaite peut également être effectuée en dessous de $N &lt; 2^{64}$.
&lt;code>{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}&lt;/code>&lt;/p>
&lt;p>Cette fois, pour améliorer la simplicité et la fiabilité de l&amp;rsquo;algorithme, nous adopterons la méthode utilisant ces derniers $12$ nombres premiers comme bases (ou les $7$ bases plus optimisées). Dans l&amp;rsquo;implémentation C++, en divisant la plage avec un branchement conditionnel, nous optimiserons pour minimiser le nombre de tests.&lt;/p>
&lt;hr>
&lt;h1 id="5-implémentation-avancée-en-c-highly-optimized-c-implementation">5. Implémentation avancée en C++ (Highly Optimized C++ Implementation)
&lt;/h1>&lt;p>Maintenant, en résumant les théories mathématiques et la conception des algorithmes discutées jusqu&amp;rsquo;à présent, nous présenterons le code d&amp;rsquo;implémentation de la fonction de test de primalité de Miller-Rabin au niveau le plus fort dans le C++ moderne.&lt;/p>
&lt;h2 id="points-clés-de-limplémentation">Points clés de l&amp;rsquo;implémentation
&lt;/h2>&lt;ol>
&lt;li>
&lt;p>&lt;strong>Éviter le dépassement de capacité de la multiplication des entiers de 64 bits :&lt;/strong>
Dans le cas de $N \approx 10^{18}$, $x \times x$ dans la multiplication modulaire sera au maximum de $10^{36}$, ce qui dépassera facilement la valeur maximale de $1.8 \times 10^{19}$ d&amp;rsquo;un entier normal de 64 bits (&lt;code>uint64_t&lt;/code> ou &lt;code>long long&lt;/code>).
Pour résoudre ce problème, le type d&amp;rsquo;extension GCC ou Clang &lt;code>__int128_t&lt;/code> (ou &lt;code>unsigned __int128&lt;/code>) est utilisé, et le calcul est effectué avec une précision de 128 bits avant de prendre le modulo. Cela permet une multiplication modulaire à grande vitesse sans l&amp;rsquo;utilisation d&amp;rsquo;algorithmes complexes.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Choix de la base déterministe :&lt;/strong>
Si la valeur de $N$ est petite, elle est optimisée de manière à ce qu&amp;rsquo;un plus petit nombre de bases n&amp;rsquo;aient besoin d&amp;rsquo;être testées.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h2 id="code-source-c-complet">Code source C++ complet
&lt;/h2>&lt;p>Voici le code source complet prêt à être utilisé en pratique. Ce code peut être copié et utilisé tel quel dans des environnements tels que la programmation compétitive.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;span class="lnt">74
&lt;/span>&lt;span class="lnt">75
&lt;/span>&lt;span class="lnt">76
&lt;/span>&lt;span class="lnt">77
&lt;/span>&lt;span class="lnt">78
&lt;/span>&lt;span class="lnt">79
&lt;/span>&lt;span class="lnt">80
&lt;/span>&lt;span class="lnt">81
&lt;/span>&lt;span class="lnt">82
&lt;/span>&lt;span class="lnt">83
&lt;/span>&lt;span class="lnt">84
&lt;/span>&lt;span class="lnt">85
&lt;/span>&lt;span class="lnt">86
&lt;/span>&lt;span class="lnt">87
&lt;/span>&lt;span class="lnt">88
&lt;/span>&lt;span class="lnt">89
&lt;/span>&lt;span class="lnt">90
&lt;/span>&lt;span class="lnt">91
&lt;/span>&lt;span class="lnt">92
&lt;/span>&lt;span class="lnt">93
&lt;/span>&lt;span class="lnt">94
&lt;/span>&lt;span class="lnt">95
&lt;/span>&lt;span class="lnt">96
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;cstdint&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;initializer_list&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="k">namespace&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// (a * b) mod m rapide avec des entiers de 128 bits
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">inline&lt;/span> &lt;span class="kt">uint64_t&lt;/span> &lt;span class="nf">mod_mul&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint64_t&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint64_t&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint64_t&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">uint64_t&lt;/span>&lt;span class="p">)((&lt;/span>&lt;span class="kt">unsigned&lt;/span> &lt;span class="n">__int128&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="n">a&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Calcul de (base^exp) mod m par la méthode d&amp;#39;exponentiation binaire
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">uint64_t&lt;/span> &lt;span class="nf">mod_pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint64_t&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint64_t&lt;/span> &lt;span class="n">exp&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint64_t&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint64_t&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">base&lt;/span> &lt;span class="o">%=&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">exp&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">exp&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod_mul&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">res&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">base&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod_mul&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exp&lt;/span> &lt;span class="o">&amp;gt;&amp;gt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">res&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Test déterministe pour les entiers 64 bits par la méthode de Miller-Rabin
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">bool&lt;/span> &lt;span class="nf">is_prime_miller_rabin&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint64_t&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Valeurs limites et évaluation préalable des petits nombres premiers
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">3&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">5&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">7&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">3&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">5&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">7&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Décomposer sous la forme n-1 = d * 2^s
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">uint64_t&lt;/span> &lt;span class="n">d&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">s&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">((&lt;/span>&lt;span class="n">d&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">d&lt;/span> &lt;span class="o">&amp;gt;&amp;gt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">s&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Liste des bases utilisées pour le test
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// Optimisation pour minimiser le nombre de bases testées selon la taille de N
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">uint64_t&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">bases&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">4759123141ULL&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bases&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">7&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">61&lt;/span>&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">1122004669633ULL&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bases&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">13&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">23&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1662803&lt;/span>&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 7 bases qui sont déterministes pour tous les nombres N &amp;lt; 2^64
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">bases&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">325&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">9375&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">28178&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">450775&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">9780504&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1795265022&lt;/span>&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Exécuter le test pour chaque base
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">uint64_t&lt;/span> &lt;span class="nl">a&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">bases&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span> &lt;span class="o">%=&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">continue&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Si a est un multiple de n, cela ne peut pas être testé, mais ce n&amp;#39;est pas premier
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint64_t&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod_pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">continue&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Première condition remplie, passer à la base suivante
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="n">composite&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Boucle de s-1 itérations (x = x^2 mod n)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">s&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">r&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod_mul&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">composite&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Seconde condition remplie, peut-être premier
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">break&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Si aucune condition n&amp;#39;est remplie, il est certainement composé
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">composite&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Si la condition est remplie pour toutes les bases, il est certainement premier
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Échantillons pour les tests
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">uint64_t&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">test_cases&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="mi">1000000007&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1">// Nombre premier célèbre
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="mi">998244353&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1">// Nombre premier célèbre
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="mi">1000000000000000003&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1">// Nombre premier autour de 10^18
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="mi">1000000000000000007&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1">// Nombre composé (10^18 + 7)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="mi">561&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1">// Nombre de Carmichael (Composé)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="mi">18446744073709551557ULL&lt;/span> &lt;span class="c1">// Un des plus grands nombres premiers près de 2^64
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">uint64_t&lt;/span> &lt;span class="nl">n&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">test_cases&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; is &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">is_prime_miller_rabin&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="s">&amp;#34;Prime&amp;#34;&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="s">&amp;#34;Composite&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h1 id="6-évaluation-de-la-complexité-et-des-performances-de-lalgorithme">6. Évaluation de la complexité et des performances de l&amp;rsquo;algorithme
&lt;/h1>&lt;p>Examinons les performances de l&amp;rsquo;algorithme implémenté.&lt;/p>
&lt;h2 id="complexité-temporelle-time-complexity">Complexité temporelle (Time Complexity)
&lt;/h2>&lt;ul>
&lt;li>&lt;strong>Méthode des divisions successives :&lt;/strong> $O(\sqrt{N})$&lt;/li>
&lt;li>&lt;strong>Test de Fermat :&lt;/strong> Calcul d&amp;rsquo;exponentiation $O(\log N) \times k$ ($k$ étant le nombre d&amp;rsquo;essais)&lt;/li>
&lt;li>&lt;strong>Méthode de Miller-Rabin :&lt;/strong> Calcul d&amp;rsquo;exponentiation et boucle $O(\log N) \times k$&lt;/li>
&lt;/ul>
&lt;p>Dans un environnement 64 bits ($N \le 2^{64}$), la méthode déterministe de Miller-Rabin ci-dessus vérifie au maximum $7$ bases. Par conséquent, $k$ peut être considéré comme une constante $k \le 7$, et la complexité temporelle globale devient strictement $O(\log N)$.
Même dans le pire des cas ($N \approx 10^{19}$), le nombre d&amp;rsquo;étapes d&amp;rsquo;exécution tient dans un maximum de $7 \times 64 = 448$ opérations de base, et le temps d&amp;rsquo;exécution est inférieur à quelques microsecondes ($10^{-6}$ secondes). Par rapport au $O(\sqrt{N})$ de la méthode des divisions successives (environ $4 \times 10^9$ boucles), une &lt;strong>accélération de plusieurs millions de fois&lt;/strong> est atteinte.&lt;/p>
&lt;h2 id="optimisation-supplémentaire--multiplication-de-montgomery-montgomery-multiplication">Optimisation supplémentaire : Multiplication de Montgomery (Montgomery Multiplication)
&lt;/h2>&lt;p>Dans l&amp;rsquo;implémentation de cet article, le type étendu entier de 128 bits &lt;code>__int128_t&lt;/code> est utilisé pour la division (opération modulo &lt;code>%&lt;/code>). Même sur les processeurs modernes, la division entière (instruction DIV) est une instruction coûteuse qui nécessite des dizaines de cycles par rapport à l&amp;rsquo;addition ou la multiplication.&lt;/p>
&lt;p>Les créateurs de bibliothèques et les programmeurs compétitifs cherchant à atteindre les limites de l&amp;rsquo;optimisation adoptent parfois une méthode appelée &lt;strong>multiplication de Montgomery (Montgomery Multiplication)&lt;/strong>. La multiplication de Montgomery est un algorithme remarquable qui remplace les opérations modulo coûteuses (division) par &amp;ldquo;seulement des décalages de bits et des multiplications&amp;rdquo; en mappant les nombres dans un &amp;ldquo;espace de Montgomery&amp;rdquo; spécial.
En intégrant cela dans la multiplication modulaire du test de Miller-Rabin, la vitesse d&amp;rsquo;exécution peut encore être augmentée d&amp;rsquo;environ 2 à 3 fois. Comme c&amp;rsquo;est un sujet très profond, nous l&amp;rsquo;expliquerons en détail dans un autre article.&lt;/p>
&lt;hr>
&lt;h1 id="7-conclusion">7. Conclusion
&lt;/h1>&lt;p>Dans cet article, nous avons expliqué d&amp;rsquo;un coup de nombreux concepts, des bases aux sujets avancés du test de primalité.
Récapitulons les points clés.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>La méthode des divisions successives&lt;/strong> est certaine, mais manque d&amp;rsquo;utilité pratique lorsque $N$ dépasse $10^{12}$ en raison de sa complexité de $O(\sqrt{N})$.&lt;/li>
&lt;li>&lt;strong>Le test de Fermat&lt;/strong> est extrêmement rapide avec $O(\log N)$, mais a une faiblesse fatale en étant trompé par des nombres pseudo-premiers absolus tels que les nombres de Carmichael.&lt;/li>
&lt;li>&lt;strong>Le test de primalité de Miller-Rabin&lt;/strong> est l&amp;rsquo;algorithme le plus puissant et pratique qui résout les faiblesses du test de Fermat.&lt;/li>
&lt;li>Dans l&amp;rsquo;implémentation C++, le dépassement de capacité de multiplication d&amp;rsquo;entiers 64 bits peut être géré en toute sécurité en utilisant &lt;code>__int128_t&lt;/code>.&lt;/li>
&lt;li>Dans la plage des entiers de 64 bits ($N &lt; 2^{64}$), en choisissant $7$ ou $12$ nombres premiers spécifiques comme base, un &lt;strong>test de primalité déterministe (100% précis)&lt;/strong> plutôt que probabiliste est possible.&lt;/li>
&lt;/ol>
&lt;p>Le test de primalité rapide est une technologie incontournable dans les calculs manipulant de grands nombres. Le code source en C++ de Miller-Rabin fourni dans cet article est robuste et peut être utilisé en pratique tel quel. N&amp;rsquo;hésitez pas à l&amp;rsquo;utiliser dans vos propres projets ou compétitions d&amp;rsquo;algorithmes.&lt;/p>
&lt;div class="mermaid">graph LR
TrialDivision["Méthode des divisions successives (O(√N))"] --> Fermat["Test de Fermat (O(log N), avec faiblesses)"]
Fermat --> MillerRabin["Méthode de Miller-Rabin (O(log N), rendable déterministe)"]
MillerRabin --> Montgomery["+ Multiplication de Montgomery (Accélération constante)"]
style MillerRabin fill:#f9f,stroke:#333,stroke-width:2px&lt;/div>
&lt;p>Le monde des algorithmes, où se croisent la programmation et les mathématiques, est extrêmement beau et profond. J&amp;rsquo;espère que cela vous sera utile dans votre apprentissage futur.&lt;/p>
&lt;hr>
&lt;p>&lt;em>Reference:&lt;/em>&lt;/p>
&lt;ul>
&lt;li>&lt;em>Pomerance, C., Selfridge, J. L., &amp;amp; Wagstaff, S. S. (1980). The pseudoprimes to 25.10^9. Mathematics of Computation.&lt;/em>&lt;/li>
&lt;li>&lt;em>Sinclair, J. (2011). Deterministic Miller-Rabin primality testing.&lt;/em>&lt;/li>
&lt;/ul></description></item><item><title>【Explication mathématique】Le fonctionnement de la cryptographie RSA expliqué aux lycéens</title><link>http://kenji.blog/fr/p/rsa-encryption-math-explained-for-beginners/</link><pubDate>Fri, 11 Sep 2026 13:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/rsa-encryption-math-explained-for-beginners/</guid><description>&lt;img src="http://kenji.blog/p/rsa-encryption-math-explained-for-beginners/img/eyecatch.jpg" alt="Featured image of post 【Explication mathématique】Le fonctionnement de la cryptographie RSA expliqué aux lycéens" />&lt;p>L&amp;rsquo;une des technologies qui soutient fondamentalement la sécurité de la société Internet est la « cryptographie RSA ». La plupart des communications que nous utilisons négligemment chaque jour, telles que les paiements par carte de crédit lors des achats en ligne, les échanges sur les réseaux sociaux avec des amis, ou l&amp;rsquo;envoi et la réception d&amp;rsquo;informations confidentielles d&amp;rsquo;entreprise, sont protégées par cette cryptographie RSA ou par ses technologies successives.&lt;/p>
&lt;p>Cependant, lorsque l&amp;rsquo;on entend le mot « cryptographie », on peut imaginer des machines de chiffrement complexes comme celles des films d&amp;rsquo;espionnage, ou des mathématiques super avancées que seuls quelques génies peuvent comprendre. S&amp;rsquo;il est vrai que la théorie cryptographique moderne repose sur des mathématiques avancées, &lt;strong>le mécanisme fondamental de la cryptographie RSA peut être pleinement compris avec des connaissances mathématiques acquises au lycée (propriétés des entiers, nombres premiers, congruences, etc.)&lt;/strong>.&lt;/p>
&lt;p>Dans cet article, en partant des connaissances mathématiques du lycée, nous expliquerons étape par étape et de manière exhaustive les principes mathématiques sur lesquels repose la cryptographie RSA et pourquoi son décryptage est si difficile. Nous l&amp;rsquo;expliquerons soigneusement avec des exemples concrets pour que même ceux qui ne sont pas très à l&amp;rsquo;aise avec les mathématiques puissent comprendre.&lt;/p>
&lt;hr>
&lt;h2 id="1-cryptographie-à-clé-symétrique-et-cryptographie-à-clé-publique">1. Cryptographie à clé symétrique et cryptographie à clé publique
&lt;/h2>&lt;p>Avant d&amp;rsquo;aborder le mécanisme mathématique de la cryptographie RSA, passons d&amp;rsquo;abord en revue les concepts de base de la cryptographie. Les méthodes de chiffrement sont généralement divisées en deux types : la « cryptographie à clé symétrique » (ou clé secrète) et la « cryptographie à clé publique ».&lt;/p>
&lt;h3 id="11-les-limites-de-la-cryptographie-à-clé-symétrique">1.1 Les limites de la cryptographie à clé symétrique
&lt;/h3>&lt;p>La plupart des cryptographies utilisées depuis l&amp;rsquo;Antiquité sont appelées « cryptographie à clé symétrique ». C&amp;rsquo;est une méthode où &lt;strong>la même clé est utilisée pour le « chiffrement (conversion du message en un texte chiffré secret) » et le « déchiffrement (restauration du texte chiffré en son message d&amp;rsquo;origine) »&lt;/strong>.&lt;/p>
&lt;p>Par exemple, supposons qu&amp;rsquo;Alice veuille envoyer une lettre secrète à Bob. Alice met la lettre dans une boîte et la verrouille à l&amp;rsquo;aide d&amp;rsquo;un cadenas (clé symétrique). Pour que Bob puisse ouvrir cette boîte, il doit posséder la même clé que celle utilisée par Alice.&lt;/p>
&lt;p>Cette méthode pose un problème majeur : le « problème de distribution des clés ». Lorsque Alice et Bob, éloignés l&amp;rsquo;un de l&amp;rsquo;autre, communiquent pour la première fois, comment peuvent-ils partager la clé sans être sur écoute ? Si la clé est volée par un tiers pendant son envoi par la poste, toutes les communications chiffrées ultérieures seront complètement compromises.&lt;/p>
&lt;h3 id="12-linvention-révolutionnaire--la--cryptographie-à-clé-publique-">1.2 L&amp;rsquo;invention révolutionnaire : la « Cryptographie à clé publique »
&lt;/h3>&lt;p>La « cryptographie à clé publique » a été inventée pour résoudre ce problème de distribution des clés. La cryptographie RSA en est un type.&lt;/p>
&lt;p>Dans la cryptographie à clé publique, &lt;strong>deux clés différentes sont utilisées : une « clé pour chiffrer (clé publique) » et une « clé pour déchiffrer (clé privée) »&lt;/strong>.&lt;/p>
&lt;ol>
&lt;li>Le destinataire, Bob, crée une paire composée d&amp;rsquo;une « clé publique » et d&amp;rsquo;une « clé privée ».&lt;/li>
&lt;li>Bob publie la « clé publique » dans le monde entier (peu importe qui l&amp;rsquo;obtient).&lt;/li>
&lt;li>L&amp;rsquo;expéditrice, Alice, utilise la « clé publique » de Bob pour chiffrer son message et l&amp;rsquo;envoie.&lt;/li>
&lt;li>Le message chiffré ne peut être déchiffré qu&amp;rsquo;avec la « clé privée », que seul Bob possède.&lt;/li>
&lt;/ol>
&lt;p>Si l&amp;rsquo;on compare cela à un cadenas, Bob fabrique de nombreux « cadenas ouverts (clés publiques) » et les disperse à travers le monde. Alice place un message destiné à Bob dans une boîte et la verrouille avec un cadenas de Bob qu&amp;rsquo;elle a trouvé. Une fois fermé, le cadenas ne peut être ouvert qu&amp;rsquo;avec la « clé passe-partout (clé privée) » détenue par Bob. Même si quelqu&amp;rsquo;un vole la boîte en cours de route, il ne peut pas l&amp;rsquo;ouvrir sans la clé passe-partout.&lt;/p>
&lt;div class="mermaid">graph TD
A["Alice (Expéditrice)"] --> B["Texte clair (Message)"]
B --> C["Processus de chiffrement"]
D["Clé publique de Bob (Accessible à tous)"] --> C
C --> E["Transmission via Internet : Texte chiffré"]
E --> F["Processus de déchiffrement"]
G["Clé privée de Bob (Détenue uniquement par Bob)"] --> F
F --> H["Texte clair restauré (Message)"]
H --> I["Bob (Destinataire)"]&lt;/div>
&lt;p>Pour réaliser ce système révolutionnaire, une sorte de &lt;strong>« fonction à sens unique (un puzzle mathématique à sens unique) »&lt;/strong> est nécessaire : « un chiffrement facile avec la clé publique, mais un déchiffrement absolument impossible sans la clé privée ». C&amp;rsquo;est là que les « nombres premiers » que nous connaissons bien ont été choisis comme pièces de ce puzzle.&lt;/p>
&lt;hr>
&lt;h2 id="2-base-mathématique-de-la-cryptographie-rsa-1--nombres-premiers-et-décomposition-en-facteurs-premiers">2. Base mathématique de la cryptographie RSA 1 : Nombres premiers et décomposition en facteurs premiers
&lt;/h2>&lt;p>La sécurité de la cryptographie RSA repose sur le fait mathématique que &lt;strong>« la décomposition en facteurs premiers de nombres gigantesques est extrêmement difficile »&lt;/strong>.&lt;/p>
&lt;h3 id="21-quest-ce-quun-nombre-premier-">2.1 Qu&amp;rsquo;est-ce qu&amp;rsquo;un nombre premier ?
&lt;/h3>&lt;p>Un nombre premier est « un entier naturel supérieur à 1 qui ne peut être divisé de manière exacte que par 1 et par lui-même ».
Exemples : $2, 3, 5, 7, 11, 13, 17, 19, 23...$&lt;/p>
&lt;p>Les nombres premiers sont comme les « atomes » de tous les nombres entiers. Tout entier naturel peut être décomposé sous la forme d&amp;rsquo;une multiplication de nombres premiers. C&amp;rsquo;est ce qu&amp;rsquo;on appelle la &lt;strong>décomposition en facteurs premiers&lt;/strong>. Par exemple, $60 = 2^2 \times 3 \times 5$. Le fait que l&amp;rsquo;on puisse décomposer un nombre en facteurs premiers d&amp;rsquo;une seule et unique manière (si l&amp;rsquo;on ignore l&amp;rsquo;ordre) est connu sous le nom de « Théorème fondamental de l&amp;rsquo;arithmétique ».&lt;/p>
&lt;h3 id="22-la-difficulté-de-la-décomposition-en-facteurs-premiers-fonction-à-sens-unique">2.2 La difficulté de la décomposition en facteurs premiers (Fonction à sens unique)
&lt;/h3>&lt;p>Ce qui est important ici, c&amp;rsquo;est l&amp;rsquo;asymétrie selon laquelle &lt;strong>« la multiplication est facile, mais la décomposition en facteurs premiers est difficile »&lt;/strong>.&lt;/p>
&lt;p>Par exemple, essayez de calculer mentalement la multiplication des deux nombres premiers suivants.
$11 \times 13 = ?$
C&amp;rsquo;est facile. La réponse est $143$.&lt;/p>
&lt;p>Alors, qu&amp;rsquo;en est-il du nombre suivant ?
Décomposez $323$ en facteurs premiers.
Qu&amp;rsquo;en pensez-vous ? Cela devrait prendre un peu plus de temps. (La réponse est $17 \times 19$).&lt;/p>
&lt;p>Si les nombres sont petits, les humains peuvent s&amp;rsquo;en sortir d&amp;rsquo;une manière ou d&amp;rsquo;une autre, mais lorsque les nombres deviennent grands, les calculs deviennent explosivement difficiles, même avec des ordinateurs. Dans la cryptographie RSA principalement utilisée aujourd&amp;rsquo;hui, on utilise un nombre $N = p \times q$, qui est le produit de deux nombres premiers immenses, $p$ et $q$, de 2048 bits (environ 600 chiffres en base 10).&lt;/p>
&lt;p>Lorsqu&amp;rsquo;on donne deux immenses nombres premiers $p$ et $q$, un ordinateur peut calculer $N$ en un instant (moins d&amp;rsquo;une milliseconde). Cependant, à l&amp;rsquo;inverse, si l&amp;rsquo;on ne donne que $N$, trouver les $p$ et $q$ originaux prendrait tellement de temps que même les superordinateurs les plus rapides actuels ne pourraient pas le résoudre en le calculant pendant des milliers de milliards d&amp;rsquo;années.&lt;/p>
&lt;p>Cette &lt;strong>« asymétrie de calcul (l&amp;rsquo;aller est facile, le retour est difficile) »&lt;/strong> devient le fondement qui crée la relation entre la clé publique et la clé privée.&lt;/p>
&lt;hr>
&lt;h2 id="3-base-mathématique-de-la-cryptographie-rsa-2--congruence-arithmétique-modulaire">3. Base mathématique de la cryptographie RSA 2 : Congruence (Arithmétique modulaire)
&lt;/h2>&lt;p>Les calculs de la cryptographie RSA ne se font pas dans le monde des additions et multiplications où les nombres deviennent infiniment grands comme nous en avons l&amp;rsquo;habitude, mais dans le monde des « restes » après division par un certain nombre. C&amp;rsquo;est ce qu&amp;rsquo;on appelle la &lt;strong>congruence (ou arithmétique modulaire)&lt;/strong>.&lt;/p>
&lt;h3 id="31-les-mathématiques-de-lhorloge">3.1 Les mathématiques de l&amp;rsquo;horloge
&lt;/h3>&lt;p>L&amp;rsquo;arithmétique modulaire est souvent comparée aux « mathématiques de l&amp;rsquo;horloge ». S&amp;rsquo;il est 10 heures actuellement, quelle heure sera-t-il dans 5 heures ? $10 + 5 = 15$ heures, mais sur une horloge classique de 12 heures, on répond « 3 heures ». C&amp;rsquo;est parce que le reste de la division de 15 par 12 est 3.&lt;/p>
&lt;p>Dans le monde mathématique, on écrit cela comme suit :
&lt;/p>
$$ 15 \equiv 3 \pmod{12} $$
&lt;p>
Cela se lit « 15 est congru à 3 modulo 12 (le reste de la division par 12 est égal) ».&lt;/p>
&lt;h3 id="32-propriétés-fondamentales-des-congruences">3.2 Propriétés fondamentales des congruences
&lt;/h3>&lt;p>Les congruences ont des propriétés très pratiques qui ressemblent beaucoup à celles des équations ($=$). Soit $N$ le module (le diviseur).
Lorsque $a \equiv b \pmod N$ et $c \equiv d \pmod N$, ce qui suit est vrai :&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Addition :&lt;/strong> $a + c \equiv b + d \pmod N$&lt;/li>
&lt;li>&lt;strong>Soustraction :&lt;/strong> $a - c \equiv b - d \pmod N$&lt;/li>
&lt;li>&lt;strong>Multiplication :&lt;/strong> $a \times c \equiv b \times d \pmod N$&lt;/li>
&lt;li>&lt;strong>Exponentiation (puissance) :&lt;/strong> $a^k \equiv b^k \pmod N$ ($k$ est un entier naturel)&lt;/li>
&lt;/ol>
&lt;p>La propriété d&amp;rsquo;« exponentiation » est particulièrement importante. Elle signifie que &lt;strong>« le reste d&amp;rsquo;une puissance est égal à la puissance du reste »&lt;/strong>.
Par exemple, supposons que nous voulions trouver le reste de la division de $7^{100}$ par $5$. Il serait fastidieux de multiplier sérieusement $7$ cent fois avant de diviser par $5$, mais en utilisant la propriété des congruences, puisque $7 \equiv 2 \pmod 5$, on a $7^{100} \equiv 2^{100} \pmod 5$, ce qui permet de simplifier considérablement le calcul. Dans le monde de la cryptographie, on manipule des puissances de très grands nombres, cette propriété est donc indispensable.&lt;/p>
&lt;hr>
&lt;h2 id="4-base-mathématique-de-la-cryptographie-rsa-3--la-fonction-deuler-et-le-théorème-deuler">4. Base mathématique de la cryptographie RSA 3 : La fonction d&amp;rsquo;Euler et le théorème d&amp;rsquo;Euler
&lt;/h2>&lt;p>Voici la mathématique magique qui est au cœur de la cryptographie RSA. Le « théorème d&amp;rsquo;Euler », qui est une généralisation du « petit théorème de Fermat », fait son apparition.&lt;/p>
&lt;h3 id="41-lindicatrice-deuler-phin">4.1 L&amp;rsquo;indicatrice d&amp;rsquo;Euler $\phi(N)$
&lt;/h3>&lt;p>La fonction indicatrice d&amp;rsquo;Euler (fonction $\phi$) est une fonction qui, pour un entier naturel $N$ donné, renvoie le &lt;strong>« nombre d&amp;rsquo;entiers naturels compris entre 1 et $N$ qui sont premiers avec $N$ (dont le plus grand commun diviseur est 1) »&lt;/strong>.&lt;/p>
&lt;p>Regardons quelques exemples.&lt;/p>
&lt;ul>
&lt;li>$\phi(5)$ : Parmi 1, 2, 3, 4, 5, les nombres premiers avec 5 sont 1, 2, 3, 4, soit 4 nombres. Donc, $\phi(5) = 4$.&lt;/li>
&lt;li>$\phi(6)$ : Parmi 1, 2, 3, 4, 5, 6, les nombres premiers avec 6 sont 1, 5, soit 2 nombres. Donc, $\phi(6) = 2$.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>【Propriété spéciale dans le cas d&amp;rsquo;un nombre premier】&lt;/strong>
Si $p$ est un nombre premier, tous les nombres de 1 à $p-1$ sont premiers avec $p$. Par conséquent,
&lt;/p>
$$ \phi(p) = p - 1 $$
&lt;p>&lt;strong>【Propriété spéciale dans le cas du produit de deux nombres premiers】&lt;/strong>
Pour deux nombres premiers distincts $p$ et $q$, si on pose $N = p \times q$, $\phi(N)$ peut être facilement calculée avec la formule suivante.
&lt;/p>
$$ \phi(N) = \phi(p) \times \phi(q) = (p - 1)(q - 1) $$
&lt;p>
Cette propriété agit comme la « porte dérobée secrète (trapdoor) » de la cryptographie RSA. La personne qui connaît $p$ et $q$ (le créateur de la clé) peut calculer $\phi(N)$ en un instant, mais une tierce personne qui ne connaît que $N$ ne peut pas trouver $\phi(N)$ sans factoriser $N$.&lt;/p>
&lt;h3 id="42-le-théorème-deuler">4.2 Le théorème d&amp;rsquo;Euler
&lt;/h3>&lt;p>Leonhard Euler a prouvé le magnifique théorème suivant en utilisant cette $\phi(N)$.&lt;/p>
&lt;p>&lt;strong>Théorème d&amp;rsquo;Euler :&lt;/strong>
Si les entiers $a$ et $N$ sont premiers entre eux, la congruence suivante est vraie :
&lt;/p>
$$ a^{\phi(N)} \equiv 1 \pmod N $$
&lt;p>C&amp;rsquo;est une propriété surprenante selon laquelle « si l&amp;rsquo;on multiplie un certain nombre $a$ par lui-même $\phi(N)$ fois et qu&amp;rsquo;on le divise par $N$, le reste sera toujours $1$ ». (Si $N$ est un nombre premier $p$, cela devient $a^{p-1} \equiv 1 \pmod p$, ce qui est appelé le petit théorème de Fermat).&lt;/p>
&lt;p>Transformons ce théorème d&amp;rsquo;Euler. Multiplions les deux côtés par $a$ une fois de plus.
&lt;/p>
$$ a^{\phi(N) + 1} \equiv a \pmod N $$
&lt;p>De plus, pour tout entier $k$, comme $a^{k \cdot \phi(N)}$ sera également égal à $1^k = 1$, l&amp;rsquo;équation suivante est vraie :
&lt;/p>
$$ a^{k \cdot \phi(N) + 1} \equiv a \pmod N $$
&lt;p>Cette équation est le principe fondamental qui permet à la magie de la cryptographie RSA de fonctionner : &lt;strong>« chiffrer puis déchiffrer permet de revenir à l&amp;rsquo;original »&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h2 id="5-algorithme-de-la-cryptographie-rsa--étapes-de-génération-de-clé-de-chiffrement-et-de-déchiffrement">5. Algorithme de la cryptographie RSA : Étapes de génération de clé, de chiffrement et de déchiffrement
&lt;/h2>&lt;p>Maintenant que nous avons les connaissances de base, examinons les étapes spécifiques de la cryptographie RSA. La cryptographie RSA est globalement divisée en trois phases : « 1. Génération de la clé », « 2. Chiffrement » et « 3. Déchiffrement ».&lt;/p>
&lt;div class="mermaid">flowchart TD
A1["1. Choisir les nombres premiers p, q"] --> A2["Calculer N = p × q"]
A1 --> A3["Calculer φ(N) = (p-1)(q-1)"]
A3 --> A4["Choisir e premier avec φ(N)"]
A3 --> A5["Calculer d tel que e × d ≡ 1 (mod φ(N))"]
A2 --> A6["Clé publique (N, e)"]
A4 --> A6
A5 --> A7["Clé privée d"]
B1["2. Message en texte clair M"] --> B2["Calculer C ≡ M^e (mod N)"]
A6 -.-> B2
B2 --> B3["Envoyer le texte chiffré C"]
B3 --> C1["3. Texte chiffré reçu C"]
C1 --> C2["Calculer M ≡ C^d (mod N)"]
A7 -.-> C2
C2 --> C3["Obtenir le message en texte clair d'origine M"]&lt;/div>
&lt;h3 id="51-génération-de-clé-key-generation">5.1 Génération de clé (Key Generation)
&lt;/h3>&lt;p>Bob, qui est le destinataire, génère sa « clé publique » et sa « clé privée ».&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Sélection des nombres premiers :&lt;/strong> Il choisit aléatoirement deux grands nombres premiers $p$ et $q$.&lt;/li>
&lt;li>&lt;strong>Calcul du module $N$ :&lt;/strong> Il calcule $N = p \times q$. Ce $N$ est rendu public.&lt;/li>
&lt;li>&lt;strong>Calcul de $\phi(N)$ :&lt;/strong> Il calcule la fonction d&amp;rsquo;Euler $\phi(N) = (p - 1)(q - 1)$. C&amp;rsquo;est le nombre secret de Bob uniquement.&lt;/li>
&lt;li>&lt;strong>Sélection de la clé publique $e$ :&lt;/strong> Il choisit un entier $e$ tel que $1 &lt; e &lt; \phi(N)$ et qui est premier avec $\phi(N)$.&lt;/li>
&lt;li>&lt;strong>Calcul de la clé privée $d$ :&lt;/strong> Il trouve un entier $d$ qui satisfait la condition suivante.
$$ e \times d \equiv 1 \pmod{\phi(N)} $$
En d&amp;rsquo;autres termes, c&amp;rsquo;est « un nombre $d$ tel que le reste de $e \times d$ divisé par $\phi(N)$ est égal à $1$ ».&lt;/li>
&lt;/ol>
&lt;p>La préparation de la clé est maintenant terminée.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Clé publique :&lt;/strong> La paire $(N, e)$. Elle est publiée dans le monde entier.&lt;/li>
&lt;li>&lt;strong>Clé privée :&lt;/strong> $d$. Il ne le dit absolument à personne.&lt;/li>
&lt;/ul>
&lt;h3 id="52-chiffrement-encryption">5.2 Chiffrement (Encryption)
&lt;/h3>&lt;p>Supposons qu&amp;rsquo;Alice veuille envoyer un message secret $M$ à Bob. (On suppose que $M$ est un nombre représentant des caractères et $0 \le M &lt; N$). Alice utilise la clé publique de Bob $(N, e)$ et calcule comme suit :&lt;/p>
$$ C \equiv M^e \pmod N $$
&lt;p>Elle calcule « le reste $C$ de la division de la puissance $e$ du message $M$ par $N$ ». Ce $C$ est le texte chiffré.&lt;/p>
&lt;h3 id="53-déchiffrement-decryption">5.3 Déchiffrement (Decryption)
&lt;/h3>&lt;p>Bob reçoit le texte chiffré $C$. Bob utilise sa clé privée $d$ et calcule comme suit :&lt;/p>
$$ M \equiv C^d \pmod N $$
&lt;p>En calculant « le reste de la division de la puissance $d$ du texte chiffré $C$ par $N$ », étonnamment, le message d&amp;rsquo;origine $M$ est restauré !&lt;/p>
&lt;hr>
&lt;h2 id="6-pourquoi-le-déchiffrement-permet-il-de-revenir-à-loriginal--preuve-mathématique">6. Pourquoi le déchiffrement permet-il de revenir à l&amp;rsquo;original ? (Preuve mathématique)
&lt;/h2>&lt;p>Vous vous demandez peut-être : « Comment se fait-il que le simple fait d&amp;rsquo;élever $C$ à la puissance $d$ nous ramène au $M$ d&amp;rsquo;origine ? ». C&amp;rsquo;est ici que le « théorème d&amp;rsquo;Euler » que nous avons vu plus tôt entre en jeu.&lt;/p>
&lt;p>Substituons la formule de chiffrement $C = M^e$ dans la formule de déchiffrement $C^d \pmod N$.
&lt;/p>
$$ C^d \equiv (M^e)^d \equiv M^{ed} \pmod N $$
&lt;p>Rappelez-vous ici de l&amp;rsquo;étape 5 de la génération de clé. Lors de la création de $d$, Bob l&amp;rsquo;a choisi de sorte que $e \times d \equiv 1 \pmod{\phi(N)}$. Cela signifie que « $ed$ est un multiple de $\phi(N)$ plus $1$ ». En utilisant un entier $k$, on peut l&amp;rsquo;écrire comme suit :
&lt;/p>
$$ ed = k \cdot \phi(N) + 1 $$
&lt;p>Substituons cela dans l&amp;rsquo;exposant et décomposons-le en utilisant les lois des exposants.
&lt;/p>
$$ M^{ed} = M^{k \cdot \phi(N) + 1} = M^{k \cdot \phi(N)} \times M^1 = (M^{\phi(N)})^k \times M $$
&lt;p>Ici, en supposant que le message $M$ et $N$ sont premiers entre eux, d&amp;rsquo;après le &lt;strong>théorème d&amp;rsquo;Euler&lt;/strong>, on a $M^{\phi(N)} \equiv 1 \pmod N$.
&lt;/p>
$$ (M^{\phi(N)})^k \times M \equiv 1^k \times M \equiv M \pmod N $$
&lt;p>Par conséquent, la formule suivante est magnifiquement vérifiée.
&lt;/p>
$$ C^d \equiv M \pmod N $$
&lt;p>Alice ne connaît pas $d$, et les personnes sur écoute ne connaissent pas $d$ non plus, donc seul Bob, qui possède $d$, peut extraire $M$ de $C$.&lt;/p>
&lt;hr>
&lt;h2 id="7-exemple-concret--faisons-lexpérience-de-rsa-par-un-calcul-manuel-avec-de-petits-nombres-premiers">7. Exemple concret : Faisons l&amp;rsquo;expérience de RSA par un calcul manuel avec de petits nombres premiers
&lt;/h2>&lt;p>Faisons une communication chiffrée d&amp;rsquo;Alice à Bob en utilisant de petits nombres (nombres premiers) en pratique.&lt;/p>
&lt;p>&lt;strong>【Phase de génération de la clé de Bob】&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>Choisir deux nombres premiers $p=11$, $q=13$.&lt;/li>
&lt;li>Calculer $N = 11 \times 13 = 143$.&lt;/li>
&lt;li>Calculer $\phi(N) = (11 - 1) \times (13 - 1) = 10 \times 12 = 120$.&lt;/li>
&lt;li>Choisir une clé publique $e$ première avec $\phi(N)=120$. Prenons ici $e=7$.&lt;/li>
&lt;li>Trouver la clé privée $d$. Chercher $d$ tel que $7 \times d \equiv 1 \pmod{120}$.
Dans l&amp;rsquo;équation $7d = 120k + 1$, pour $k=6$, on obtient $721$, et $721 \div 7 = 103$.
Donc, $d = 103$.&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>Clé publique : $(N=143, e=7)$&lt;/li>
&lt;li>Clé privée : $d=103$&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>【Phase de chiffrement d&amp;rsquo;Alice】&lt;/strong>
Supposons que nous voulions envoyer le message $M = 9$.
Formule : $C \equiv 9^7 \pmod{143}$
$9^7 = 4,782,969$. Divisé par 143, cela donne $33447$ avec un reste de $48$.
Le texte chiffré est devenu $C = 48$.&lt;/p>
&lt;p>&lt;strong>【Phase de déchiffrement de Bob】&lt;/strong>
Bob reçoit le texte chiffré $C = 48$ et le déchiffre à l&amp;rsquo;aide de sa clé privée $d = 103$.
Formule : $M \equiv 48^{103} \pmod{143}$
Si vous exécutez &lt;code>(48 ** 103) % 143&lt;/code> sur une calculatrice, le résultat est magnifiquement « &lt;strong>9&lt;/strong> » ! Il a pu recevoir avec succès le message d&amp;rsquo;origine.&lt;/p>
&lt;hr>
&lt;h2 id="8-comment-trouver-la-clé-privée-d--lalgorithme-deuclide-étendu">8. Comment trouver la clé privée $d$ : L&amp;rsquo;algorithme d&amp;rsquo;Euclide étendu
&lt;/h2>&lt;p>Dans l&amp;rsquo;exemple de calcul manuel, nous avons trouvé $k$ par intuition pour découvrir $d=103$, mais cette méthode est impossible lorsque les nombres atteignent des centaines de chiffres. Dans les programmes réels, nous utilisons un algorithme appelé &lt;strong>« algorithme d&amp;rsquo;Euclide étendu »&lt;/strong>.&lt;/p>
&lt;p>Résoudre $7d \equiv 1 \pmod{120}$ équivaut à trouver des entiers $d, y$ qui satisfont $7d + 120y = 1$. En calculant à l&amp;rsquo;envers avec l&amp;rsquo;algorithme d&amp;rsquo;Euclide, nous pouvons le trouver mécaniquement.&lt;/p>
&lt;ol>
&lt;li>$120 \div 7 = 17$ reste $1$&lt;/li>
&lt;li>En transformant cela, $1 = 120 - 17 \times 7$&lt;/li>
&lt;li>En d&amp;rsquo;autres termes, $-17 \times 7 \equiv 1 \pmod{120}$&lt;/li>
&lt;/ol>
&lt;p>$-17$ signifie la même chose que $120 - 17 = 103$ dans le monde du modulo $120$. Par conséquent, on trouve $d = 103$ en un instant. Cette méthode permet de calculer très rapidement même pour des nombres extrêmement grands.&lt;/p>
&lt;hr>
&lt;h2 id="9-lautre-visage-de-la-cryptographie-rsa--les-signatures-numériques">9. L&amp;rsquo;autre visage de la cryptographie RSA : Les signatures numériques
&lt;/h2>&lt;p>Ce qui est merveilleux avec la cryptographie RSA, c&amp;rsquo;est qu&amp;rsquo;en inversant les rôles de la clé publique et de la clé privée, on peut aussi l&amp;rsquo;utiliser comme &lt;strong>« signature numérique »&lt;/strong>.&lt;/p>
&lt;p>Pour le chiffrement, c&amp;rsquo;était « chiffrement avec la clé publique $\Rightarrow$ déchiffrement avec la clé privée », mais
pour la signature numérique, on suit les étapes : « chiffrement avec la clé privée $\Rightarrow$ déchiffrement avec la clé publique ».&lt;/p>
&lt;div class="mermaid">flowchart TD
A1["1. Alice crée une signature avec sa clé privée"] --> A2["S ≡ M^d (mod N)"]
A2 --> A3["Envoyer le message M et la signature S"]
A3 --> B1["2. Bob vérifie la signature avec la clé publique"]
B1 --> B2["Calculer M' ≡ S^e (mod N)"]
B2 --> B3["Vérifier si M' et M correspondent"]&lt;/div>
&lt;p>Alice convertit le message en utilisant sa propre clé privée $d$ (c&amp;rsquo;est la signature $S$) et l&amp;rsquo;envoie à Bob. Bob effectue le calcul de vérification en utilisant la clé publique $e$ d&amp;rsquo;Alice. Si le résultat du calcul correspond au message d&amp;rsquo;origine, cela prouve simultanément que « ce sont des données qui ne peuvent être créées qu&amp;rsquo;avec la clé privée d&amp;rsquo;Alice » et que « le message n&amp;rsquo;a pas été falsifié en cours de route ».&lt;/p>
&lt;hr>
&lt;h2 id="10-expérimenter-la-cryptographie-rsa-avec-la-programmation">10. Expérimenter la cryptographie RSA avec la programmation
&lt;/h2>&lt;p>Même les calculs de puissance qui sont difficiles à faire à la main peuvent être très facilement implémentés avec Python. Voici un code Python qui vous permet d&amp;rsquo;expérimenter la logique de base de la cryptographie RSA.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Trouver le plus grand commun diviseur&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">b&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">a&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">mod_inverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Trouver la clé privée d (utilisation de la fonction intégrée à partir de Python 3.8)&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. Génération de clé&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">p&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">q&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">11&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">13&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">N&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">q&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">phi&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">q&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">e&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">7&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">d&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod_inverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Clé publique : (N=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">N&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">, e=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">), Clé privée : d=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">d&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. Chiffrement&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">9&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">ciphertext&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Texte chiffré : &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">ciphertext&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. Déchiffrement&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">decrypted_message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ciphertext&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Message déchiffré : &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">decrypted_message&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>La fonction &lt;code>pow(base, exp, mod)&lt;/code> de Python utilise un algorithme rapide appelé « exponentiation rapide (par carrés successifs) » en interne, de sorte que même pour des nombres de centaines de chiffres, le calcul se termine en un clin d&amp;rsquo;œil.&lt;/p>
&lt;hr>
&lt;h2 id="11-résumé-et-avenir-des-technologies-cryptographiques">11. Résumé et avenir des technologies cryptographiques
&lt;/h2>&lt;p>Nous avons percé les secrets du mécanisme de la cryptographie RSA, en nous basant sur les connaissances mathématiques du lycée.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>La difficulté de la décomposition en facteurs premiers :&lt;/strong> Il est facile de calculer $p \times q = N$, mais il est très difficile de trouver $p, q$ à partir de $N$.&lt;/li>
&lt;li>&lt;strong>Congruence et théorème d&amp;rsquo;Euler :&lt;/strong> Grâce à la règle $a^{\phi(N)} \equiv 1 \pmod N$, la porte dérobée magique « revenir à l&amp;rsquo;original lorsqu&amp;rsquo;on élève à une certaine puissance » est achevée.&lt;/li>
&lt;li>&lt;strong>Clé publique et clé privée :&lt;/strong> N&amp;rsquo;importe qui peut chiffrer, mais seul le destinataire légitime peut déchiffrer.&lt;/li>
&lt;/ol>
&lt;p>Le $N$ de la cryptographie RSA actuellement utilisé comporte plus de 600 chiffres, et même si on mobilisait tous les superordinateurs du monde, la décomposition en facteurs premiers prendrait plus de temps que l&amp;rsquo;âge de l&amp;rsquo;univers. Cependant, si les « ordinateurs quantiques » dont la recherche a progressé ces dernières années deviennent un jour utilisables en pratique, cette décomposition pourrait être résolue en un instant grâce à l&amp;rsquo;« algorithme de Shor ». Pour cette raison, le développement d&amp;rsquo;une « cryptographie post-quantique », qui ne pourrait pas être cassée même par des ordinateurs quantiques, avance rapidement partout dans le monde.&lt;/p>
&lt;p>Les mathématiques avancées, souvent perçues comme « inutiles », protègent en réalité fondamentalement notre vie quotidienne. La cryptographie RSA est le meilleur matériel pédagogique qui nous enseigne la profondeur et la beauté de telles mathématiques. J&amp;rsquo;espère qu&amp;rsquo;à travers cet article, vous avez pu ressentir, ne serait-ce qu&amp;rsquo;un peu, l&amp;rsquo;intérêt de la cryptographie et des mathématiques.&lt;/p></description></item><item><title>Qu'est-ce que le chiffrement homomorphe complet (FHE) ? Explication de la clé de la sécurité de nouvelle génération</title><link>http://kenji.blog/fr/p/fully-homomorphic-encryption-fhe-explained/</link><pubDate>Fri, 11 Sep 2026 11:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/fully-homomorphic-encryption-fhe-explained/</guid><description>&lt;img src="http://kenji.blog/p/fully-homomorphic-encryption-fhe-explained/img/eyecatch.jpg" alt="Featured image of post Qu'est-ce que le chiffrement homomorphe complet (FHE) ? Explication de la clé de la sécurité de nouvelle génération" />&lt;p>Alors que le cloud computing et les technologies d&amp;rsquo;IA s&amp;rsquo;imposent comme les fondations de notre société, le compromis entre la « confidentialité des données » et l&amp;rsquo;« utilisation des données » est devenu l&amp;rsquo;un des défis les plus importants. Bien qu&amp;rsquo;il y ait une demande croissante pour que les IA analysent des données hautement confidentielles dans le cloud, telles que des données médicales, des informations financières ou des données biométriques personnelles, de nombreuses entreprises hésitent à envoyer leurs données à l&amp;rsquo;extérieur en raison de préoccupations liées à la sécurité.&lt;/p>
&lt;p>Les technologies de chiffrement traditionnelles (telles qu&amp;rsquo;AES et RSA) excellent à protéger les données stockées (Data at Rest) et les données en transit sur le réseau (Data in Transit). Cependant, &lt;strong>lorsque le serveur effectue des traitements (calculs)&lt;/strong> sur les données, comme des recherches ou de l&amp;rsquo;apprentissage automatique (Data in Use), &lt;strong>il est nécessaire de déchiffrer au préalable les données pour les ramener en texte clair&lt;/strong>. Si le serveur est piraté au moment du déchiffrement, ou si un administrateur interne malveillant jette un coup d&amp;rsquo;œil aux données, cela conduit directement à une fuite d&amp;rsquo;informations.&lt;/p>
&lt;p>La technologie de rêve qui surmonte cette faiblesse fondamentale du « déchiffrement lors du traitement » est le &lt;strong>Chiffrement Homomorphe Complet (Fully Homomorphic Encryption : FHE)&lt;/strong>. L&amp;rsquo;utilisation du FHE permet d&amp;rsquo;effectuer des calculs sur les données tout en les gardant chiffrées, sans jamais les déchiffrer, et de renvoyer uniquement le texte chiffré du résultat au client.&lt;/p>
&lt;p>Dans cet article, nous expliquerons en profondeur le FHE, clé de la sécurité de nouvelle génération, de son concept à son histoire, en passant par la percée révolutionnaire de Craig Gentry, ses bases mathématiques (comme le Ring-LWE), son plus grand défi qu&amp;rsquo;est le « bruit » et sa solution (le bootstrapping), jusqu&amp;rsquo;aux dernières bibliothèques d&amp;rsquo;implémentation.&lt;/p>
&lt;hr>
&lt;h2 id="1-quest-ce-que-le-chiffrement-homomorphe--concepts-de-base">1. Qu&amp;rsquo;est-ce que le chiffrement homomorphe ? Concepts de base
&lt;/h2>&lt;p>« Homomorphe » est un terme d&amp;rsquo;algèbre qui désigne la propriété de pouvoir mapper des ensembles ayant une certaine structure tout en préservant la structure de leurs opérations. Dans la théorie de la cryptographie, l&amp;rsquo;« homomorphisme » est la propriété selon laquelle &lt;strong>les opérations dans l&amp;rsquo;espace du texte clair correspondent aux opérations dans l&amp;rsquo;espace du texte chiffré&lt;/strong>.&lt;/p>
&lt;p>Exprimé par une formule mathématique simple, soit $E(\cdot)$ la fonction de chiffrement et $D(\cdot)$ la fonction de déchiffrement pour les textes clairs $m_1$ et $m_2$. Si $\circ$ est une opération (comme l&amp;rsquo;addition ou la multiplication) sur les textes clairs, et $\diamond$ une opération sur les textes chiffrés, la relation suivante est établie :&lt;/p>
$$ D(E(m_1) \diamond E(m_2)) = m_1 \circ m_2 $$
&lt;p>En d&amp;rsquo;autres termes, déchiffrer le résultat de l&amp;rsquo;application d&amp;rsquo;une certaine opération $\diamond$ sur les textes chiffrés $E(m_1)$ et $E(m_2)$ donnera exactement le même résultat que l&amp;rsquo;opération $\circ$ appliquée sur les textes clairs d&amp;rsquo;origine.&lt;/p>
&lt;h3 id="flux-de-données-dans-le-cloud-computing">Flux de données dans le cloud computing
&lt;/h3>&lt;p>L&amp;rsquo;architecture de traitement dans le cloud utilisant le FHE est complètement différente des architectures traditionnelles. Le diagramme ci-dessous illustre le flux de traitement de données sécurisé tirant parti du FHE.&lt;/p>
&lt;div class="mermaid">graph TD
A["Client (Détient la clé privée)"] -->|1. Chiffre le texte clair x : E(x)| B["Serveur Cloud (Uniquement données chiffrées)"]
B -->|2. Applique la fonction f en gardant le chiffrement : E(f(x))| B
B -->|3. Texte chiffré du résultat du calcul E(y)| A
A -->|4. Déchiffre avec la clé privée : y = f(x)| A
style A fill:#d4edda,stroke:#28a745
style B fill:#f8d7da,stroke:#dc3545&lt;/div>
&lt;p>Le serveur reçoit les données chiffrées $E(x)$, mais ne possédant pas la clé privée, il lui est absolument impossible d&amp;rsquo;en connaître le contenu. Cependant, en utilisant les propriétés du FHE, il peut appliquer une fonction $f$ (par exemple, un modèle d&amp;rsquo;inférence d&amp;rsquo;apprentissage automatique) au texte chiffré pour générer $E(f(x))$. Le client le reçoit et le déchiffre avec sa propre clé privée, obtenant ainsi le résultat souhaité $y = f(x)$.&lt;/p>
&lt;hr>
&lt;h2 id="2-lhistoire-de-lévolution-du-chiffrement-homomorphe--phe-she-fhe">2. L&amp;rsquo;histoire de l&amp;rsquo;évolution du chiffrement homomorphe : PHE, SHE, FHE
&lt;/h2>&lt;p>Le chiffrement homomorphe n&amp;rsquo;a pas atteint sa forme « complète » actuelle en une seule fois. Il est largement classé en trois étapes selon le type et le nombre d&amp;rsquo;opérations réalisables.&lt;/p>
&lt;h3 id="chiffrement-partiellement-homomorphe-phe--partially-homomorphic-encryption">Chiffrement Partiellement Homomorphe (PHE : Partially Homomorphic Encryption)
&lt;/h3>&lt;p>Le PHE est un schéma de chiffrement permettant d&amp;rsquo;effectuer &lt;strong>soit des additions, soit des multiplications&lt;/strong>, de manière illimitée. En réalité, des chiffrements possédant cette propriété existent depuis longtemps.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Chiffrement RSA (homomorphisme vis-à-vis de la multiplication)&lt;/strong>
Le chiffrement RSA possède involontairement un homomorphisme multiplicatif. Soit les textes clairs $m_1, m_2$ et la clé publique $(e, N)$ :
$$ E(m_1) = m_1^e \pmod N $$
$$ E(m_2) = m_2^e \pmod N $$
En les multipliant :
$$ E(m_1) \times E(m_2) = (m_1 \cdot m_2)^e \pmod N = E(m_1 \times m_2) $$
Ainsi, la multiplication des textes chiffrés correspond à la multiplication des textes clairs.&lt;/li>
&lt;li>&lt;strong>Chiffrement de Paillier (homomorphisme vis-à-vis de l&amp;rsquo;addition)&lt;/strong>
Inventé en 1999, le chiffrement de Paillier possède un homomorphisme pour l&amp;rsquo;addition. Il est utilisé de manière pratique dans des applications telles que le vote électronique (où les votes chiffrés sont comptés, et seul le résultat final est déchiffré).&lt;/li>
&lt;/ul>
&lt;h3 id="chiffrement-quelque-peu-homomorphe-she--somewhat-homomorphic-encryption">Chiffrement Quelque Peu Homomorphe (SHE : Somewhat Homomorphic Encryption)
&lt;/h3>&lt;p>C&amp;rsquo;est une méthode permettant d&amp;rsquo;exécuter &lt;strong>à la fois&lt;/strong> des additions et des multiplications, mais avec &lt;strong>une limite sur le nombre d&amp;rsquo;opérations (la profondeur du circuit)&lt;/strong>. En raison de l&amp;rsquo;accumulation du « bruit » (expliqué plus tard), effectuer plus d&amp;rsquo;un certain nombre de multiplications rend le déchiffrement impossible. Le chiffrement BGN (Boneh-Goh-Nissim) de 2005 en est un exemple, mais il a ses limites pour effectuer des calculs pratiques complexes (comme le deep learning).&lt;/p>
&lt;h3 id="chiffrement-homomorphe-complet-fhe--fully-homomorphic-encryption">Chiffrement Homomorphe Complet (FHE : Fully Homomorphic Encryption)
&lt;/h3>&lt;p>Il s&amp;rsquo;agit d&amp;rsquo;un schéma de chiffrement permettant d&amp;rsquo;effectuer à la fois l&amp;rsquo;addition et la multiplication &lt;strong>un nombre illimité de fois&lt;/strong>. Semblable à la complétude de Turing en théorie de l&amp;rsquo;information, pouvoir combiner infiniment des additions (équivalentes au XOR) et des multiplications (équivalentes au AND) signifie qu&amp;rsquo;en principe, n&amp;rsquo;importe quelle fonction ou algorithme calculable peut être exécuté tout en restant chiffré.&lt;/p>
&lt;p>Le FHE a longtemps été considéré comme le « Saint Graal de la cryptographie », et certains disaient même qu&amp;rsquo;il pourrait être irréalisable. Cependant, en 2009, &lt;strong>Craig Gentry&lt;/strong>, alors étudiant en doctorat à l&amp;rsquo;Université de Stanford, a proposé le premier schéma FHE utilisant les réseaux idéaux (Ideal Lattices), bouleversant ainsi le monde.&lt;/p>
&lt;hr>
&lt;h2 id="3-les-bases-mathématiques-du-fhe--le-problème-lwe-et-ring-lwe">3. Les bases mathématiques du FHE : le problème LWE et Ring-LWE
&lt;/h2>&lt;p>La plupart des schémas FHE actuellement dominants sont basés sur le &lt;strong>problème LWE (Learning With Errors)&lt;/strong>, un défi mathématique de la « cryptographie fondée sur les réseaux (Lattice-based Cryptography) », également connue sous le nom de cryptographie post-quantique.&lt;/p>
&lt;h3 id="compréhension-intuitive-du-problème-lwe">Compréhension intuitive du problème LWE
&lt;/h3>&lt;p>Résoudre un système d&amp;rsquo;équations linéaires est facile en utilisant l&amp;rsquo;élimination de Gauss ou des méthodes similaires.&lt;/p>
$$ \begin{cases} 3s_1 + 4s_2 + 2s_3 \equiv 12 \pmod{17} \\ 1s_1 + 9s_2 + 5s_3 \equiv 8 \pmod{17} \\ \vdots \end{cases} $$
&lt;p>Mais que se passe-t-il si l&amp;rsquo;on ajoute une très petite « erreur (bruit) aléatoire » $e$ au résultat de ces équations ?&lt;/p>
$$ \begin{cases} 3s_1 + 4s_2 + 2s_3 + e_1 \equiv 13 \pmod{17} \\ 1s_1 + 9s_2 + 5s_3 + e_2 \equiv 7 \pmod{17} \\ \vdots \end{cases} $$
&lt;p>Le simple ajout de cette erreur $e$ transforme le problème de la découverte du vecteur de variables secrètes $\vec{s}$ en un problème NP-difficile, complexe à déchiffrer même en utilisant les supercalculateurs actuels ou les ordinateurs quantiques. C&amp;rsquo;est le problème LWE.&lt;/p>
&lt;h3 id="le-problème-ring-lwe-rlwe">Le problème Ring-LWE (RLWE)
&lt;/h3>&lt;p>Comme le problème LWE standard implique des opérations matricielles, la taille des clés est extrêmement importante (atteignant parfois des gigaoctets) et l&amp;rsquo;efficacité des calculs est faible. Pour résoudre ce problème, le &lt;strong>problème Ring-LWE (RLWE)&lt;/strong> utilisant des opérations sur des anneaux de polynômes a été introduit.&lt;/p>
&lt;p>Dans le RLWE, les éléments appartiennent à l&amp;rsquo;anneau polynomial $R_q = \mathbb{Z}_q[x] / (x^N + 1)$ (où $N$ est une puissance de 2 et $q$ est un nombre premier servant de modulo).
Soit $s(x)$ le polynôme représentant la clé privée, $a(x)$ un polynôme aléatoire et $e(x)$ un petit polynôme de bruit, la clé publique sera la paire suivante :&lt;/p>
$$ (a(x), b(x)) \quad \text{where} \quad b(x) = -a(x) \cdot s(x) + e(x) \pmod q $$
&lt;p>Lors du chiffrement, on utilise les propriétés de ces polynômes pour encoder le texte clair $m(x)$ et générer le texte chiffré.&lt;/p>
&lt;hr>
&lt;h2 id="4-le-plus-grand-obstacle--le--bruit--et-le-bootstrapping-de-gentry">4. Le plus grand obstacle : le « bruit » et le Bootstrapping de Gentry
&lt;/h2>&lt;p>Le concept le plus important pour comprendre le FHE est la &lt;strong>« gestion du bruit »&lt;/strong>.&lt;/p>
&lt;p>Dans les chiffrements basés sur LWE/RLWE, on introduit intentionnellement un petit « bruit (erreur) » pour garantir la sécurité.
En termes généraux, le processus de déchiffrement d&amp;rsquo;un texte chiffré $c$ d&amp;rsquo;un texte clair $m$ peut être exprimé par l&amp;rsquo;équation suivante :&lt;/p>
$$ D(c) = (c \cdot s) \pmod q = m + \text{noise} $$
&lt;p>Lors du déchiffrement, le texte clair correct $m$ est obtenu en éliminant ce &lt;code>noise&lt;/code> par un processus tel que l&amp;rsquo;arrondi. Cependant, effectuer des opérations homomorphes (en particulier la multiplication) entre des textes chiffrés amplifie considérablement ce bruit.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Addition homomorphe&lt;/strong> : Le bruit augmente de manière additive ($e_1 + e_2$). C&amp;rsquo;est une augmentation relativement modérée.&lt;/li>
&lt;li>&lt;strong>Représentation mathématique de l&amp;rsquo;homomorphisme par addition homomorphe&lt;/strong> :
$$ E(m_1) \oplus E(m_2) = E(m_1 + m_2) $$&lt;/li>
&lt;li>&lt;strong>Multiplication homomorphe&lt;/strong> : Le bruit explose de manière multiplicative (car il implique des termes comme $e_1 \times e_2$). Après seulement quelques multiplications, le bruit dépasse le seuil $q/2$, ce qui rend l&amp;rsquo;arrondi correct impossible et entraîne un échec de déchiffrement.&lt;/li>
&lt;li>&lt;strong>Représentation mathématique de l&amp;rsquo;homomorphisme par multiplication homomorphe&lt;/strong> :
$$ E(m_1) \otimes E(m_2) = E(m_1 \times m_2) $$&lt;/li>
&lt;/ul>
&lt;p>C&amp;rsquo;est la raison pour laquelle le FHE est resté longtemps irréalisable, se limitant au SHE (avec un nombre d&amp;rsquo;opérations restreint).&lt;/p>
&lt;h3 id="la-magie-du-bootstrapping">La magie du Bootstrapping
&lt;/h3>&lt;p>La contribution géniale de Craig Gentry a été d&amp;rsquo;inventer une méthode de réduction de bruit appelée &lt;strong>« bootstrapping »&lt;/strong>. Ce fut un changement de paradigme en cryptographie.&lt;/p>
&lt;p>Intuitivement, il s&amp;rsquo;agit d&amp;rsquo;une opération où l&amp;rsquo;« on &amp;lsquo;déchiffre&amp;rsquo; le texte chiffré tout en le gardant à l&amp;rsquo;état chiffré pour le nettoyer et le placer dans un nouveau texte chiffré avant qu&amp;rsquo;il ne soit submergé de bruit et ne se corrompe ».&lt;/p>
&lt;ol>
&lt;li>Supposons qu&amp;rsquo;il y ait un texte chiffré avec un bruit élevé, $C_{noisy}$.&lt;/li>
&lt;li>Le client remet au préalable au serveur sa clé privée $sk$ « chiffrée avec la clé publique » $E_{pk}(sk)$ (appelée clé de bootstrapping).&lt;/li>
&lt;li>Le serveur exécute homomorphiquement un &lt;strong>circuit de déchiffrement (Decryption Circuit)&lt;/strong> sur $C_{noisy}$.&lt;/li>
&lt;li>Concrètement, il effectue un « déchiffrement dans l&amp;rsquo;espace chiffré » sur $E_{pk}(C_{noisy})$ en utilisant $E_{pk}(sk)$.&lt;/li>
&lt;li>Bien que ce circuit de déchiffrement lui-même soit une opération homomorphe et génère donc un nouveau bruit, le bruit du nouveau texte chiffré produit, $C_{fresh}$, est réinitialisé à un « niveau fixe » constant.&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph LR
A["Texte chiffré à haut bruit C_noisy"] --> B["Circuit de déchiffrement homomorphe (Eval_Dec)"]
C["Clé privée chiffrée E(sk)"] --> B
B --> D["Texte chiffré à faible bruit C_fresh"]
style B fill:#ffeeba,stroke:#ffc107&lt;/div>
&lt;p>En exécutant périodiquement ce bootstrapping au cours des calculs, il est théoriquement devenu possible de calculer des circuits d&amp;rsquo;une profondeur infinie (réalisant ainsi le FHE). Cependant, dans le schéma initial de Gentry, le coût de calcul du processus de bootstrapping était désespérément élevé, prenant de quelques dizaines de minutes à plusieurs heures pour chaque exécution.&lt;/p>
&lt;hr>
&lt;h2 id="5-générations-de-fhe-et-évolution-des-principaux-schémas">5. Générations de FHE et évolution des principaux schémas
&lt;/h2>&lt;p>Afin de rendre le FHE pratique, les cryptographes du monde entier ont rivalisé pour améliorer les algorithmes. Actuellement, le FHE est principalement classé en quatre générations ou familles.&lt;/p>
&lt;h3 id="2ème-génération--opérations-exactes-sur-les-entiers-bgv-bfv">2ème Génération : Opérations exactes sur les entiers (BGV, BFV)
&lt;/h3>&lt;p>Apparus entre 2011 et 2012, il s&amp;rsquo;agit des schémas &lt;strong>BGV (Brakerski-Gentry-Vaikuntanathan)&lt;/strong> et &lt;strong>BFV (Brakerski/Fan-Vercauteren)&lt;/strong>. Ils sont basés sur le RLWE et sont adaptés à l&amp;rsquo;arithmétique modulaire sur les nombres entiers (calculs exacts).
Leur particularité est de supporter des techniques de traitement par lots (Batching) telles que SIMD (Single Instruction, Multiple Data), ce qui permet de regrouper des milliers d&amp;rsquo;emplacements de données dans un seul énorme texte chiffré polynomial pour effectuer des calculs parallèles en une seule fois.&lt;/p>
&lt;h3 id="3ème-génération--accélération-du-bootstrapping-gsw-fhew-tfhe">3ème Génération : Accélération du Bootstrapping (GSW, FHEW, TFHE)
&lt;/h3>&lt;p>Le schéma &lt;strong>GSW (Gentry-Sahai-Waters)&lt;/strong> de 2013 a simplifié la structure du FHE. Et son développement a conduit au &lt;strong>TFHE (Fast Fully Homomorphic Encryption over the Torus)&lt;/strong>, qui est l&amp;rsquo;un des schémas dominants aujourd&amp;rsquo;hui.
La caractéristique du TFHE est que son bootstrapping est extrêmement rapide (de l&amp;rsquo;ordre de la milliseconde). Il excelle dans les opérations au niveau des portes (circuits logiques tels que AND, XOR), et la taille de son texte chiffré étant relativement petite, il est adapté à l&amp;rsquo;évaluation rapide de n&amp;rsquo;importe quel circuit logique.&lt;/p>
&lt;h3 id="4ème-génération--spécialisation-dans-les-calculs-approchés-et-lapprentissage-automatique-ckks">4ème Génération : Spécialisation dans les calculs approchés et l&amp;rsquo;apprentissage automatique (CKKS)
&lt;/h3>&lt;p>Le schéma &lt;strong>CKKS (Cheon-Kim-Kim-Song)&lt;/strong> proposé par Cheon et al. en 2017 est actuellement considéré comme la technologie ultime pour la protection de la vie privée dans l&amp;rsquo;IA et l&amp;rsquo;apprentissage automatique.
Contrairement aux FHE précédents qui se concentraient sur les « calculs entiers exacts », CKKS supporte les &lt;strong>« calculs approchés de nombres à virgule flottante »&lt;/strong> tout en conservant le chiffrement. Il offre des performances écrasantes dans les calculs de nombres réels où de petites erreurs sont tolérées, comme la formation ou l&amp;rsquo;inférence des réseaux de neurones.&lt;/p>
&lt;p>Le tableau ci-dessous résume comment choisir un schéma en fonction de l&amp;rsquo;objectif.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Nom du Schéma&lt;/th>
&lt;th style="text-align:left">Type de Données Préféré&lt;/th>
&lt;th style="text-align:left">Cas d&amp;rsquo;Utilisation Recommandés&lt;/th>
&lt;th style="text-align:left">Caractéristiques&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>BFV / BGV&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Entiers (Integer)&lt;/td>
&lt;td style="text-align:left">Calculs statistiques exacts, agrégation de données financières, recherche dans des bases de données&lt;/td>
&lt;td style="text-align:left">Haut débit grâce au traitement par lots SIMD&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>CKKS&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Nombres réels (Real/Complex)&lt;/td>
&lt;td style="text-align:left">Apprentissage automatique (DNN, régression logistique), traitement du signal&lt;/td>
&lt;td style="text-align:left">Accélération par calculs approchés, redimensionnement&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>TFHE&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Valeurs booléennes (Boolean)&lt;/td>
&lt;td style="text-align:left">N&amp;rsquo;importe quel circuit logique, recherche de chaînes de caractères, évaluation de fonctions non linéaires&lt;/td>
&lt;td style="text-align:left">Bootstrapping ultra-rapide (de l&amp;rsquo;ordre de la milliseconde)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="6-pratique--bibliothèques-fhe-et-code-conceptuel">6. Pratique : Bibliothèques FHE et code conceptuel
&lt;/h2>&lt;p>Aujourd&amp;rsquo;hui, il existe de nombreuses bibliothèques open-source permettant d&amp;rsquo;utiliser le FHE sans nécessiter une connaissance approfondie de la cryptographie.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Microsoft SEAL (Simple Encrypted Arithmetic Library)&lt;/strong> : Une bibliothèque C++ supportant BFV, BGV et CKKS. C&amp;rsquo;est l&amp;rsquo;une des normes de l&amp;rsquo;industrie. Son binding Python, &lt;strong>TenSEAL&lt;/strong>, est très populaire parmi les ingénieurs en IA.&lt;/li>
&lt;li>&lt;strong>Zama (Concrete)&lt;/strong> : Un framework basé sur TFHE. Il peut être écrit en Rust/Python et fournit la fonctionnalité de compiler des modèles PyTorch existants pour les exécuter sur le FHE (Concrete ML).&lt;/li>
&lt;li>&lt;strong>OpenFHE&lt;/strong> : Le successeur de PALISADE, c&amp;rsquo;est une bibliothèque C++ complète qui supporte tous les principaux schémas.&lt;/li>
&lt;/ul>
&lt;h3 id="exemple-de-programmation-fhe-avec-python-tenseal">Exemple de programmation FHE avec Python (TenSEAL)
&lt;/h3>&lt;p>Ici, nous présentons un exemple conceptuel de code Python utilisant le schéma CKKS pour additionner et multiplier des vecteurs de nombres réels tout en les gardant chiffrés.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">tenseal&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">ts&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. Configuration du contexte (incluant la génération des clés)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Utilise le schéma CKKS et définit le degré du polynôme à 8192&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">context&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">context&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">SCHEME_TYPE&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CKKS&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">poly_modulus_degree&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">8192&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">coeff_mod_bit_sizes&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">60&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">40&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">40&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">60&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">context&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">generate_galois_keys&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">context&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">global_scale&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="mi">40&lt;/span> &lt;span class="c1"># Facteur d&amp;#39;échelle pour les nombres réels&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. Côté client : Chiffrement des données&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">vector1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mf">1.5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">2.5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">3.5&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">vector2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mf">2.0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">3.0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">4.0&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Convertit les vecteurs en texte clair en textes chiffrés (initialement exécuté côté client)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">enc_v1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ckks_vector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">context&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">vector1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">enc_v2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ckks_vector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">context&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">vector2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. Côté serveur : Opérations tout en gardant le chiffrement (Protection des Data in Use)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Le serveur ne connaît pas le texte clair, mais peut effectuer des additions et des multiplications&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">enc_add&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">enc_v1&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">enc_v2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">enc_mul&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">enc_v1&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">enc_v2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 4. Côté client : Déchiffrement des résultats&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Seul le client possédant la clé privée peut voir le résultat&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">res_add&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">enc_add&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decrypt&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">res_mul&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">enc_mul&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decrypt&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Résultat de l&amp;#39;addition déchiffrée : &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">res_add&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Exemple de sortie : [3.5000001, 5.5000001, 7.5000002] (Comprend de légères erreurs dues au calcul approché)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Résultat de la multiplication déchiffrée : &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">res_mul&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Exemple de sortie : [3.0000002, 7.5000005, 14.0000003]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Comme on peut le voir dans le code ci-dessus, les opérateurs Python normaux comme &lt;code>enc_v1 + enc_v2&lt;/code> peuvent être surchargés pour écrire des calculs entre des textes chiffrés de manière intuitive. Du côté du serveur, l&amp;rsquo;opération vectorielle est réalisée sans jamais connaître le contenu du vecteur.&lt;/p>
&lt;hr>
&lt;h2 id="7-les-défis-du-fhe--performances-et-accélération-matérielle">7. Les défis du FHE : Performances et Accélération Matérielle
&lt;/h2>&lt;p>Le FHE offre une sécurité théoriquement parfaite, mais son plus grand défi en matière d&amp;rsquo;application pratique est la &lt;strong>« surcharge de performances »&lt;/strong>.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Surcharge de calcul&lt;/strong> : Comparés aux calculs en texte clair, les calculs sur les textes chiffrés sont des milliers à des dizaines de milliers de fois plus lents sur un CPU. La multiplication de polynômes et le bootstrapping nécessitent d&amp;rsquo;énormes calculs de FFT (Transformée de Fourier Rapide) et de NTT (Transformée Théorique des Nombres).&lt;/li>
&lt;li>&lt;strong>Expansion de la taille des données (Ciphertext Expansion)&lt;/strong> : Quelques octets de texte clair peuvent devenir plusieurs mégaoctets une fois chiffrés. Cela exerce une forte pression sur la bande passante de la mémoire et du réseau.&lt;/li>
&lt;/ol>
&lt;h3 id="approches-de-résolution-basées-sur-le-matériel">Approches de résolution basées sur le matériel
&lt;/h3>&lt;p>Pour surmonter cette surcharge, des accélérateurs matériels dédiés au FHE (supportant ASIC, FPGA, GPU) sont en cours de développement dans le monde entier.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Accélération GPU&lt;/strong> : Des efforts sont en cours pour paralléliser les calculs NTT et le bootstrapping à l&amp;rsquo;aide de GPU puissants de NVIDIA et d&amp;rsquo;autres, rapportant des accélérations de plusieurs dizaines de fois par rapport aux implémentations logicielles (par exemple : 100x.ai, le backend CUDA TFHE-rs de Zama).&lt;/li>
&lt;li>&lt;strong>Projet DARPA DPRIVE&lt;/strong> : La Defense Advanced Research Projects Agency (DARPA) mène un projet de développement matériel dédié appelé « DPRIVE (Data Protection in Virtual Environments) » visant à ramener la vitesse de calcul du FHE à un niveau équivalent à celui du traitement en texte clair (une surcharge inférieure à 10 fois), avec la participation d&amp;rsquo;entreprises telles qu&amp;rsquo;Intel, Microsoft et Intellectual Ventures.&lt;/li>
&lt;li>&lt;strong>L&amp;rsquo;émergence du FPU (FHE Processing Unit)&lt;/strong> : Des startups comme Cornami et Optalysys se lancent dans le développement de puces dédiées au FHE utilisant l&amp;rsquo;informatique optique ou des architectures en silicium spécialisées.&lt;/li>
&lt;/ul>
&lt;p>Dans un avenir proche, tout comme pour les NPU (Neural Processing Unit) en IA, nous pourrions voir une époque où les « FPU » deviendront des équipements standard dans les serveurs et les infrastructures cloud.&lt;/p>
&lt;hr>
&lt;h2 id="8-cas-dutilisation-attendus">8. Cas d&amp;rsquo;utilisation attendus
&lt;/h2>&lt;p>Maintenant que le FHE atteint des vitesses pratiques, des innovations disruptives sont attendues dans les domaines suivants :&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Protection de la vie privée dans le domaine médical et l&amp;rsquo;analyse génomique&lt;/strong> :
En utilisant le FHE pour former l&amp;rsquo;IA dans le cloud sur des dossiers médicaux et des données ADN de patients provenant de plusieurs hôpitaux tout en conservant les données chiffrées, il est possible de développer des modèles de diagnostic du cancer très précis et de nouveaux médicaments sans violer les lois sur la vie privée (comme HIPAA ou le RGPD).&lt;/li>
&lt;li>&lt;strong>Détection des fraudes et lutte contre le blanchiment d&amp;rsquo;argent (AML) dans les institutions financières&lt;/strong> :
Des banques concurrentes pourraient effectuer des analyses interbancaires en croisant leurs données à l&amp;rsquo;état chiffré, sans révéler les informations des comptes de leurs clients ou l&amp;rsquo;historique de leurs transactions, ce qui permettrait de détecter d&amp;rsquo;énormes réseaux de transferts frauduleux.&lt;/li>
&lt;li>&lt;strong>API d&amp;rsquo;inférence d&amp;rsquo;IA sécurisée (MaaS : Model as a Service)&lt;/strong> :
Les utilisateurs chiffrent leur propre voix, l&amp;rsquo;image de leur visage ou leurs requêtes avant de les envoyer à des services d&amp;rsquo;IA (tels que des LLM comme ChatGPT). Le fournisseur d&amp;rsquo;IA génère une réponse sans jamais connaître l&amp;rsquo;entrée de l&amp;rsquo;utilisateur, et la renvoie sous forme de texte chiffré. Cela dissipe complètement la crainte que « l&amp;rsquo;IA apprenne ou s&amp;rsquo;approprie des informations personnelles ».&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="9-conclusion--lavenir-de-la-cryptographie-se-dirige-vers-le--calcul-invisible-">9. Conclusion : L&amp;rsquo;avenir de la cryptographie se dirige vers le « calcul invisible »
&lt;/h2>&lt;p>Tout comme l&amp;rsquo;invention de la cryptographie à clé publique (RSA) dans les années 1970 a rendu possible des communications sécurisées sur Internet (comme le HTTPS), l&amp;rsquo;invention du FHE par Craig Gentry constitue l&amp;rsquo;une des étapes les plus importantes de l&amp;rsquo;histoire de la cryptographie.&lt;/p>
&lt;p>Aujourd&amp;rsquo;hui, le Chiffrement Homomorphe Complet (FHE) est sorti de la théorie des laboratoires, et des entreprises telles que Microsoft, IBM, Intel, Google et de nombreuses startups se font une concurrence féroce pour le rendre pratique. Bien que des défis liés aux coûts de calcul et à la taille des données subsistent, grâce au raffinement des algorithmes et à l&amp;rsquo;évolution des accélérateurs matériels, les performances continuent de s&amp;rsquo;améliorer à un rythme dépassant la loi de Moore.&lt;/p>
&lt;p>Dans quelques années, « effectuer des calculs sur des données tout en les gardant chiffrées » ne sera plus quelque chose de spécial, mais deviendra une bonne pratique standard en matière de protection des données dans les services cloud. Le FHE est la clé de la sécurité de nouvelle génération qui réalise &lt;strong>l&amp;rsquo;équilibre ultime entre la vie privée et l&amp;rsquo;utilisation des données&lt;/strong> dans une société axée sur les données.&lt;/p></description></item><item><title>Fondements mathématiques de la cryptographie sur les courbes elliptiques (ECC) et implémentation en C++</title><link>http://kenji.blog/fr/p/elliptic-curve-cryptography-math-cpp/</link><pubDate>Fri, 11 Sep 2026 10:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/elliptic-curve-cryptography-math-cpp/</guid><description>&lt;img src="http://kenji.blog/p/elliptic-curve-cryptography-math-cpp/img/eyecatch.jpg" alt="Featured image of post Fondements mathématiques de la cryptographie sur les courbes elliptiques (ECC) et implémentation en C++" />&lt;h1 id="fondements-mathématiques-de-la-cryptographie-sur-les-courbes-elliptiques-ecc-et-implémentation-en-c">Fondements mathématiques de la cryptographie sur les courbes elliptiques (ECC) et implémentation en C++
&lt;/h1>&lt;p>Dans les technologies de cryptographie modernes, la &lt;strong>cryptographie sur les courbes elliptiques (Elliptic Curve Cryptography : ECC)&lt;/strong> joue un rôle extrêmement important. De nos communications Internet quotidiennes (HTTPS/TLS) aux enclaves sécurisées des smartphones, en passant par l&amp;rsquo;authentification des serveurs via SSH, l&amp;rsquo;authentification sans mot de passe comme FIDO, et même les crypto-actifs tels que Bitcoin et Ethereum, on peut dire sans exagérer que la base de confiance de la société numérique moderne est soutenue par l&amp;rsquo;ECC.&lt;/p>
&lt;p>Dans cet article, nous expliquerons en profondeur, avec un volume de contenu impressionnant, le fonctionnement de cette cryptographie sur les courbes elliptiques. Nous partirons de la théorie mathématique sous-jacente, belle mais complexe (géométrie algébrique sur les corps finis), pour aller jusqu&amp;rsquo;à la méthode d&amp;rsquo;implémentation réelle en C++, et enfin aux techniques de codage sécurisé pour prévenir les attaques par canaux auxiliaires (attaques temporelles).&lt;/p>
&lt;hr>
&lt;h2 id="1-pourquoi-la-cryptographie-sur-les-courbes-elliptiques--comparaison-avec-rsa">1. Pourquoi la cryptographie sur les courbes elliptiques ? (Comparaison avec RSA)
&lt;/h2>&lt;p>Pendant longtemps, le synonyme de cryptographie à clé publique a été la &lt;strong>cryptographie RSA&lt;/strong>. La sécurité de RSA repose sur la &amp;ldquo;difficulté de la factorisation en nombres premiers de très grands nombres composés&amp;rdquo;. Cependant, avec l&amp;rsquo;amélioration de la puissance de calcul des ordinateurs, il a été nécessaire d&amp;rsquo;allonger continuellement la taille des clés RSA (le nombre de bits du module) pour maintenir la sécurité. Aujourd&amp;rsquo;hui, une taille de clé d&amp;rsquo;au moins 2048 bits est recommandée, voire 3072 bits ou 4096 bits pour plus de sécurité.&lt;/p>
&lt;p>En revanche, la cryptographie sur les courbes elliptiques (ECC) repose sur une autre difficulté mathématique appelée le &lt;strong>&amp;ldquo;problème du logarithme discret sur les courbes elliptiques (ECDLP)&amp;rdquo;&lt;/strong>. Jusqu&amp;rsquo;à présent, aucun algorithme efficace (comme les algorithmes en temps sous-exponentiel) pour résoudre l&amp;rsquo;ECDLP n&amp;rsquo;a été découvert, et même les méthodes d&amp;rsquo;attaque les plus efficaces connues nécessitent un temps exponentiel.&lt;/p>
&lt;p>Grâce à cette propriété, l&amp;rsquo;ECC possède l&amp;rsquo;avantage décisif de &lt;strong>pouvoir atteindre un niveau de sécurité équivalent à celui de RSA avec une taille de clé beaucoup plus courte&lt;/strong>.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:center">Niveau de sécurité (bits)&lt;/th>
&lt;th style="text-align:center">Taille de clé RSA (bits)&lt;/th>
&lt;th style="text-align:center">Taille de clé ECC (bits)&lt;/th>
&lt;th style="text-align:center">Ratio des tailles de clé&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:center">80&lt;/td>
&lt;td style="text-align:center">1024&lt;/td>
&lt;td style="text-align:center">160&lt;/td>
&lt;td style="text-align:center">1:6&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">112&lt;/td>
&lt;td style="text-align:center">2048&lt;/td>
&lt;td style="text-align:center">224&lt;/td>
&lt;td style="text-align:center">1:9&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">128&lt;/td>
&lt;td style="text-align:center">3072&lt;/td>
&lt;td style="text-align:center">256&lt;/td>
&lt;td style="text-align:center">1:12&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">192&lt;/td>
&lt;td style="text-align:center">7680&lt;/td>
&lt;td style="text-align:center">384&lt;/td>
&lt;td style="text-align:center">1:20&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">256&lt;/td>
&lt;td style="text-align:center">15360&lt;/td>
&lt;td style="text-align:center">512&lt;/td>
&lt;td style="text-align:center">1:30&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Comme le montre le tableau ci-dessus, pour obtenir un niveau de sécurité de 128 bits (le standard actuel), RSA nécessite une clé de 3072 bits, alors que l&amp;rsquo;ECC ne nécessite que 256 bits. Cela permet de réduire la quantité de calculs, l&amp;rsquo;utilisation de la mémoire et d&amp;rsquo;économiser la bande passante du réseau. L&amp;rsquo;ECC présente ainsi une supériorité écrasante, en particulier dans les environnements aux ressources limitées comme les appareils IoT et les cartes à puce.&lt;/p>
&lt;hr>
&lt;h2 id="2-prérequis-mathématiques--la-théorie-des-groupes-et-le-monde-des-corps-finis">2. Prérequis mathématiques : La théorie des groupes et le monde des corps finis
&lt;/h2>&lt;p>Pour véritablement comprendre la cryptographie sur les courbes elliptiques, il est nécessaire de maîtriser les concepts de base de l&amp;rsquo;algèbre abstraite (théorie des groupes et théorie des corps). Nous résumons ici brièvement les connaissances préalables pour construire l&amp;rsquo;ECC.&lt;/p>
&lt;h3 id="21-groupes-group-et-groupes-abéliens">2.1. Groupes (Group) et Groupes abéliens
&lt;/h3>&lt;p>Un &lt;strong>groupe (Group)&lt;/strong> est défini par un ensemble $G$ et une opération binaire sur cet ensemble (nous utiliserons ici l&amp;rsquo;addition $+$) formant une paire $(G, +)$ qui satisfait aux 4 axiomes suivants :&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Clôture (Closure)&lt;/strong> : Pour tous $a, b \in G$, $a + b \in G$.&lt;/li>
&lt;li>&lt;strong>Associativité (Associativity)&lt;/strong> : Pour tous $a, b, c \in G$, $(a + b) + c = a + (b + c)$.&lt;/li>
&lt;li>&lt;strong>Existence de l&amp;rsquo;élément neutre (Identity element)&lt;/strong> : Il existe un élément $e \in G$ tel que pour tout $a \in G$, $a + e = e + a = a$. Dans le cas d&amp;rsquo;un groupe additif, cet élément neutre est généralement noté $0$ ou $\mathcal{O}$.&lt;/li>
&lt;li>&lt;strong>Existence de l&amp;rsquo;inverse (Inverse element)&lt;/strong> : Pour tout $a \in G$, il existe un élément $b \in G$ tel que $a + b = b + a = e$. Ce $b$ est noté $-a$.&lt;/li>
&lt;/ol>
&lt;p>De plus, un groupe qui satisfait la condition suivante, où l&amp;rsquo;ordre des opérations ne change pas le résultat, est appelé un &lt;strong>groupe abélien (ou groupe commutatif)&lt;/strong> :&lt;/p>
&lt;ol start="5">
&lt;li>&lt;strong>Commutativité (Commutativity)&lt;/strong> : Pour tous $a, b \in G$, $a + b = b + a$.&lt;/li>
&lt;/ol>
&lt;p>L&amp;rsquo;ensemble des points sur une courbe elliptique forme ce &lt;strong>groupe abélien&lt;/strong> en définissant une règle d&amp;rsquo;addition spécifique.&lt;/p>
&lt;h3 id="22-corps-finis-finite-field">2.2. Corps finis (Finite Field)
&lt;/h3>&lt;p>Dans la théorie cryptographique, nous n&amp;rsquo;utilisons pas des corps ayant un nombre infini et continu d&amp;rsquo;éléments comme les nombres réels ou complexes, mais plutôt des &lt;strong>corps finis (Finite Field)&lt;/strong> ou corps de Galois (Galois Field), dont le nombre d&amp;rsquo;éléments est fini.&lt;/p>
&lt;p>Le corps fini le plus fondamental est le &lt;strong>corps premier $\mathbb{F}_p$&lt;/strong> utilisant un nombre premier $p$. Il s&amp;rsquo;agit de l&amp;rsquo;ensemble des entiers $\{0, 1, 2, \dots, p-1\}$ muni des quatre opérations arithmétiques (addition, soustraction, multiplication, division) définies modulo $p$ (le reste de la division par $p$).&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Addition&lt;/strong> : $(a + b) \pmod p$&lt;/li>
&lt;li>&lt;strong>Soustraction&lt;/strong> : $(a - b) \pmod p$&lt;/li>
&lt;li>&lt;strong>Multiplication&lt;/strong> : $(a \times b) \pmod p$&lt;/li>
&lt;li>&lt;strong>Division&lt;/strong> : $a \times b^{-1} \pmod p$ (où $b^{-1}$ est l&amp;rsquo;inverse multiplicatif de $b$ modulo $p$)&lt;/li>
&lt;/ul>
&lt;p>Le calcul de l&amp;rsquo;&lt;strong>inverse multiplicatif (Modular Multiplicative Inverse)&lt;/strong> est extrêmement important dans l&amp;rsquo;implémentation cryptographique. Pour trouver $b^{-1}$ satisfaisant $b \times b^{-1} \equiv 1 \pmod p$, les deux algorithmes suivants sont principalement utilisés :&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Algorithme d&amp;rsquo;Euclide étendu (Extended Euclidean Algorithm)&lt;/strong> : Il est rapide, mais selon l&amp;rsquo;implémentation, le temps de traitement dépend des valeurs d&amp;rsquo;entrée, ce qui présente un risque d&amp;rsquo;attaque temporelle.&lt;/li>
&lt;li>&lt;strong>Petit théorème de Fermat (Fermat&amp;rsquo;s Little Theorem)&lt;/strong> : Lorsque $p$ est un nombre premier et $b \neq 0$, $b^{p-1} \equiv 1 \pmod p$ est vrai. En divisant les deux côtés par $b$, on obtient $b^{p-2} \equiv b^{-1} \pmod p$. Autrement dit, l&amp;rsquo;inverse peut être trouvé en calculant $b$ à la puissance $p-2$. Comme l&amp;rsquo;opération d&amp;rsquo;exponentiation est plus facile à implémenter en temps constant, elle est préférée dans les implémentations cryptographiques.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="3-léquation-de-la-courbe-elliptique-et-géométrie">3. L&amp;rsquo;équation de la courbe elliptique et géométrie
&lt;/h2>&lt;h3 id="31-forme-normale-de-weierstrass">3.1. Forme normale de Weierstrass
&lt;/h3>&lt;p>Une &lt;strong>courbe elliptique (Elliptic Curve)&lt;/strong> est une courbe plane généralement définie par l&amp;rsquo;équation suivante, appelée &lt;strong>forme normale de Weierstrass (Weierstrass normal form)&lt;/strong> :&lt;/p>
$$ y^2 = x^3 + ax + b $$
&lt;p>Ici, $a$ et $b$ sont des constantes, et pour que la courbe n&amp;rsquo;ait pas de points singuliers (auto-intersections ou points de rebroussement) (pour qu&amp;rsquo;elle soit une courbe lisse), la condition est que le &lt;strong>discriminant (Discriminant) $\Delta$&lt;/strong> suivant ne soit pas nul :&lt;/p>
$$ \Delta = -16(4a^3 + 27b^2) \neq 0 $$
&lt;p>Les courbes avec des points singuliers compromettent la sécurité cryptographique, c&amp;rsquo;est pourquoi on choisit toujours des coefficients $a, b$ qui satisfont à cette condition.&lt;/p>
&lt;h3 id="32-le-point-à-linfini-point-at-infinity">3.2. Le point à l&amp;rsquo;infini (Point at Infinity)
&lt;/h3>&lt;p>Pour faire de la courbe elliptique un groupe mathématiquement complet, en plus des points sur le plan, un point virtuel appelé &lt;strong>&amp;ldquo;point à l&amp;rsquo;infini (Point at Infinity)&amp;rdquo;&lt;/strong> est introduit. Il est noté $\mathcal{O}$ (O majuscule).&lt;/p>
&lt;p>Le point à l&amp;rsquo;infini $\mathcal{O}$ est défini comme le point où toutes les lignes verticales se croisent à l&amp;rsquo;infini. Dans la théorie des groupes, ce point à l&amp;rsquo;infini $\mathcal{O}$ fonctionne comme &lt;strong>l&amp;rsquo;élément neutre de l&amp;rsquo;addition&lt;/strong> (zéro).&lt;/p>
&lt;p>Autrement dit, pour tout point $P$ sur la courbe :
&lt;/p>
$$ P + \mathcal{O} = \mathcal{O} + P = P $$
&lt;p>De plus, l&amp;rsquo;inverse $-P$ du point $P = (x, y)$ est défini comme le point symétrique par rapport à l&amp;rsquo;axe des x, soit $(x, -y)$. Par conséquent :
&lt;/p>
$$ P + (-P) = \mathcal{O} $$
&lt;hr>
&lt;h2 id="4-opérations-de-groupe-sur-la-courbe-elliptique-addition-de-points-et-doublement">4. Opérations de groupe sur la courbe elliptique (Addition de points et doublement)
&lt;/h2>&lt;p>Le fondement de la cryptographie sur les courbes elliptiques est l&amp;rsquo;opération d&amp;rsquo;&lt;strong>&amp;ldquo;addition (Addition)&amp;rdquo;&lt;/strong> de points sur la courbe. Ceci est différent de l&amp;rsquo;addition d&amp;rsquo;entiers ordinaires et est défini sur la base d&amp;rsquo;opérations géométriques.&lt;/p>
&lt;h3 id="41-addition-géométrique-méthode-de-la-tangente-et-de-la-sécante">4.1. Addition géométrique (Méthode de la tangente et de la sécante)
&lt;/h3>&lt;p>La procédure pour ajouter deux points distincts $P$ et $Q$ sur la courbe pour obtenir un nouveau point $R$ ($R = P + Q$) est la suivante :&lt;/p>
&lt;ol>
&lt;li>Tracez une ligne droite (sécante) passant par les points $P$ et $Q$.&lt;/li>
&lt;li>Cette droite coupera toujours la courbe elliptique en un autre point (que nous appellerons $-R$). (*Selon un théorème de la géométrie algébrique)&lt;/li>
&lt;li>Le point symétrique de l&amp;rsquo;intersection $-R$ par rapport à l&amp;rsquo;axe des x (le point avec le signe de la coordonnée y inversé) est le point recherché $R$.&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph TD
Step1["Tracer une droite reliant P(x1, y1) et Q(x2, y2)"] --> Step2["Trouver la 3ème intersection avec la courbe, -R"]
Step2 --> Step3["Refléter -R sur l'axe des x pour obtenir R(x3, y3)"]
Step3 -.-> Result["Ceci est R = P + Q"]&lt;/div>
&lt;h3 id="42-doublement-de-point-point-doubling">4.2. Doublement de point (Point Doubling)
&lt;/h3>&lt;p>Lorsque l&amp;rsquo;on ajoute le même point $P$ à $P$ ($P + P = 2P$), on ne peut pas tracer une ligne passant par deux points. Dans ce cas, nous tracons &lt;strong>la tangente (Tangent) à la courbe au point $P$&lt;/strong>.&lt;/p>
&lt;ol>
&lt;li>Tracez la tangente à la courbe au point $P$.&lt;/li>
&lt;li>Cette tangente coupera la courbe en un autre point $-R$.&lt;/li>
&lt;li>Le point symétrique de cette intersection par rapport à l&amp;rsquo;axe des x est le point recherché $R = 2P$.&lt;/li>
&lt;/ol>
&lt;h3 id="43-formules-de-calcul-algébrique">4.3. Formules de calcul algébrique
&lt;/h3>&lt;p>Nous transposons les opérations géométriques en formules algébriques afin qu&amp;rsquo;elles puissent être calculées par un ordinateur.
Tous les calculs sont effectués &lt;strong>sur le corps fini $\mathbb{F}_p$ (modulo $p$)&lt;/strong>.&lt;/p>
&lt;p>Soient le point $P = (x_1, y_1)$ et le point $Q = (x_2, y_2)$.
Et soit le point de résultat calculé $R = P + Q = (x_3, y_3)$.&lt;/p>
&lt;p>Soit $\lambda$ (lambda) la pente de la droite.&lt;/p>
&lt;p>&lt;strong>[Cas 1 : Lorsque $P \neq Q$ (Addition de points)]&lt;/strong>
La pente $\lambda$ est le taux de variation entre les deux points.
&lt;/p>
$$ \lambda \equiv \frac{y_2 - y_1}{x_2 - x_1} \pmod p $$
$$ \lambda \equiv (y_2 - y_1) \cdot (x_2 - x_1)^{-1} \pmod p $$
&lt;p>En utilisant ce $\lambda$, $x_3, y_3$ sont calculés comme suit :
&lt;/p>
$$ x_3 \equiv \lambda^2 - x_1 - x_2 \pmod p $$
$$ y_3 \equiv \lambda(x_1 - x_3) - y_1 \pmod p $$
&lt;p>&lt;strong>[Cas 2 : Lorsque $P = Q$ (Doublement de point)]&lt;/strong>
La pente $\lambda$ est la pente de la tangente obtenue par dérivation. (On dérive implicitement $y^2 = x^3 + ax + b$)
&lt;/p>
$$ 2y \cdot y' = 3x^2 + a \implies y' = \frac{3x^2 + a}{2y} $$
&lt;p>
Par conséquent,
&lt;/p>
$$ \lambda \equiv (3x_1^2 + a) \cdot (2y_1)^{-1} \pmod p $$
&lt;p>Les équations pour $x_3, y_3$ ont la même forme que l&amp;rsquo;addition, mais puisque $x_2 = x_1$, elles deviennent :
&lt;/p>
$$ x_3 \equiv \lambda^2 - 2x_1 \pmod p $$
$$ y_3 \equiv \lambda(x_1 - x_3) - y_1 \pmod p $$
&lt;blockquote>
&lt;p>[!IMPORTANT]
Ces formules contiennent des &lt;strong>divisions (calcul de l&amp;rsquo;inverse modulo)&lt;/strong> telles que $(x_2 - x_1)^{-1}$ et $(2y_1)^{-1}$. Le calcul de l&amp;rsquo;inverse modulo ayant un coût de calcul très élevé, les implémentations réelles utilisent généralement des systèmes de coordonnées projectives comme les &lt;strong>&amp;ldquo;coordonnées jacobiennes (Jacobian Coordinates)&amp;rdquo;&lt;/strong> pour retarder la division.&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h2 id="5-multiplication-scalaire-et-problème-du-logarithme-discret-sur-les-courbes-elliptiques-ecdlp">5. Multiplication scalaire et problème du logarithme discret sur les courbes elliptiques (ECDLP)
&lt;/h2>&lt;p>Dans la cryptographie sur les courbes elliptiques, l&amp;rsquo;opération qui demande le plus de calculs et qui constitue le cœur de la sécurité est la &lt;strong>multiplication scalaire (Scalar Multiplication)&lt;/strong>.&lt;/p>
&lt;h3 id="51-quest-ce-que-la-multiplication-scalaire-">5.1. Qu&amp;rsquo;est-ce que la multiplication scalaire ?
&lt;/h3>&lt;p>L&amp;rsquo;opération consistant à additionner un certain point $P$, $k$ fois est appelée multiplication scalaire, notée $kP$.
&lt;/p>
$$ kP = \underbrace{P + P + \dots + P}_{k\text{ fois}} $$
&lt;p>Ici, $k$ est un très grand nombre entier (par exemple, un entier de 256 bits).&lt;/p>
&lt;h3 id="52-problème-du-logarithme-discret-sur-les-courbes-elliptiques-ecdlp">5.2. Problème du logarithme discret sur les courbes elliptiques (ECDLP)
&lt;/h3>&lt;p>La sécurité de l&amp;rsquo;ECC dépend de la difficulté du problème suivant :&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Problème du logarithme discret sur les courbes elliptiques (Elliptic Curve Discrete Logarithm Problem : ECDLP)&lt;/strong>
Étant donné un point connu $P$ (point de base) et un point calculé $Q$, trouver le scalaire $k$ tel que $Q = kP$.&lt;/p>
&lt;/blockquote>
&lt;p>Il est facile (en temps polynomial) de calculer $Q$ à partir de $k$ et $P$ (sens direct) en utilisant l&amp;rsquo;algorithme décrit plus loin, mais il est pratiquement impossible de calculer à l&amp;rsquo;envers $k$ à partir de $P$ et $Q$ (sens inverse), car il n&amp;rsquo;existe pas de méthode efficace autre que la recherche exhaustive (fonction à sens unique).
Dans les protocoles cryptographiques, &lt;strong>$k$ correspond à la &amp;ldquo;clé privée&amp;rdquo; et $Q$ à la &amp;ldquo;clé publique&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;h3 id="53-lalgorithme-double-and-add">5.3. L&amp;rsquo;algorithme Double-and-Add
&lt;/h3>&lt;p>Lorsque $k$ est un nombre énorme (par exemple, $2^{256}$), l&amp;rsquo;addition naïve de $P$ $k$ fois ne se terminerait pas avant la fin de l&amp;rsquo;univers. Par conséquent, pour effectuer rapidement la multiplication scalaire, on utilise la méthode &lt;strong>Double-and-Add (méthode binaire)&lt;/strong>.&lt;/p>
&lt;p>C&amp;rsquo;est la version courbe elliptique de l&amp;rsquo;&amp;ldquo;exponentiation rapide&amp;rdquo; utilisée pour calculer rapidement les puissances entières. Le scalaire $k$ est représenté en binaire, et traité dans l&amp;rsquo;ordre, du bit de poids fort au bit de poids faible.&lt;/p>
&lt;ol>
&lt;li>Initialiser le point de résultat $R$ avec $\mathcal{O}$.&lt;/li>
&lt;li>Répéter ce qui suit du bit de poids fort de $k$ jusqu&amp;rsquo;au bit de poids faible :
&lt;ul>
&lt;li>Doubler $R$ (Point Doubling : $R = 2R$)&lt;/li>
&lt;li>Si le bit actuel est &lt;code>1&lt;/code>, ajouter $P$ à $R$ (Point Addition : $R = R + P$)&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>Grâce à cet algorithme, la complexité passe de $O(k)$ à $O(\log_2 k)$ de façon drastique, permettant des calculs dans un temps réaliste (de l&amp;rsquo;ordre de la milliseconde).&lt;/p>
&lt;hr>
&lt;h2 id="6-léchange-de-clés-diffie-hellman-sur-courbes-elliptiques-ecdh">6. L&amp;rsquo;échange de clés Diffie-Hellman sur courbes elliptiques (ECDH)
&lt;/h2>&lt;p>Nous expliquons ici le fonctionnement du &lt;strong>protocole d&amp;rsquo;échange de clés ECDH (Elliptic Curve Diffie-Hellman)&lt;/strong>, qui est l&amp;rsquo;application la plus représentative de l&amp;rsquo;ECC. L&amp;rsquo;ECDH est un mécanisme permettant à Alice et Bob de générer et de partager en toute sécurité une clé secrète commune (clé de session) sur un canal de communication vulnérable à l&amp;rsquo;écoute (c&amp;rsquo;est le cœur du handshake TLS).&lt;/p>
&lt;p>&lt;strong>[Paramètres préalables (Paramètres de domaine)]&lt;/strong>
Les deux parties partagent au préalable la courbe elliptique $E$ à utiliser, le nombre premier $p$ et le point de base $G$. (Par exemple NIST P-256 ou secp256k1)&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant Alice as "Alice"
participant Bob as "Bob"
Note over Alice,Bob: "Paramètres publics : Courbe E, point de base G, premier p"
Alice->>Alice: "Générer la clé privée d_A (entier aléatoire)"
Alice->>Alice: "Calculer la clé publique Q_A = d_A * G"
Bob->>Bob: "Générer la clé privée d_B (entier aléatoire)"
Bob->>Bob: "Calculer la clé publique Q_B = d_B * G"
Alice->>Bob: "Envoyer la clé publique Q_A (en clair)"
Bob->>Alice: "Envoyer la clé publique Q_B (en clair)"
Alice->>Alice: "Calculer le secret partagé S = d_A * Q_B"
Bob->>Bob: "Calculer le secret partagé S = d_B * Q_A"
Note over Alice,Bob: "S = d_A * (d_B * G) = d_B * (d_A * G) = (d_A * d_B) * G"
Note over Alice,Bob: "Les résultats de calcul S des deux parties correspondent parfaitement !"&lt;/div>
&lt;p>Un attaquant (Eve) peut intercepter $G$, $Q_A$ et $Q_B$ circulant sur le canal de communication, mais en raison de la difficulté de l&amp;rsquo;ECDLP, il ne peut pas déduire la clé privée d&amp;rsquo;Alice $d_A$ à partir de $Q_A = d_A \cdot G$. De plus, multiplier $Q_A$ et $Q_B$ ne donne pas la clé partagée $S$, donc un attaquant ne peut pas calculer $S$.&lt;/p>
&lt;hr>
&lt;h2 id="7-pièges-dimplémentation--attaques-par-canaux-auxiliaires-et-contre-mesures">7. Pièges d&amp;rsquo;implémentation : Attaques par canaux auxiliaires et contre-mesures
&lt;/h2>&lt;p>Même avec un algorithme cryptographique théoriquement parfait, des vulnérabilités peuvent apparaître lors du processus d&amp;rsquo;implémentation du programme. C&amp;rsquo;est ce qu&amp;rsquo;on appelle les &lt;strong>&amp;ldquo;attaques par canaux auxiliaires (Side-Channel Attack)&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;h3 id="71-attaque-temporelle-timing-attack">7.1. Attaque temporelle (Timing Attack)
&lt;/h3>&lt;p>Revenons sur l&amp;rsquo;algorithme Double-and-Add mentionné précédemment.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Pseudo-code vulnérable du Double-and-Add
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="n">R&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Infinity&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">255&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">--&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">R&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PointDoubling&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Toujours exécuté
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">bit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">R&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PointAddition&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Exécuté uniquement quand le bit est à 1 !
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Cette implémentation présente un défaut fatal. Comme la Point Addition est exécutée lorsque le bit est &lt;code>1&lt;/code>, le temps de calcul est &lt;strong>légèrement plus long&lt;/strong> que lorsque le bit est &lt;code>0&lt;/code>. De plus, la prédiction de branchement du processeur et le comportement de la mémoire cache changent.
En observant statistiquement cette infime différence de temps de calcul (ou de consommation d&amp;rsquo;énergie) des milliers de fois, un attaquant peut &lt;strong>récupérer complètement la séquence de bits de la clé privée $k$ un par un&lt;/strong>. C&amp;rsquo;est une attaque temporelle.&lt;/p>
&lt;h3 id="72-implémentation-en-temps-constant-constant-time--léchelle-de-montgomery-montgomery-ladder">7.2. Implémentation en temps constant (Constant-Time) : L&amp;rsquo;échelle de Montgomery (Montgomery Ladder)
&lt;/h3>&lt;p>Pour empêcher les attaques temporelles, il est nécessaire d&amp;rsquo;adopter un algorithme dont &lt;strong>la séquence d&amp;rsquo;instructions exécutées et le temps de calcul sont toujours constants (Constant-Time), quelle que soit la valeur des bits de la clé privée&lt;/strong>.&lt;/p>
&lt;p>L&amp;rsquo;exemple le plus représentatif est l&amp;rsquo;&lt;strong>échelle de Montgomery (Montgomery Ladder)&lt;/strong>.&lt;/p>
&lt;div class="mermaid">graph TD
Start["Initialisation : R0 = O, R1 = P"] --> LoopStart["Pour chaque bit i (depuis le poids fort)"]
LoopStart --> Cond{"Valeur de k_i ?"}
Cond -->|0| Branch0["R1 = R0 + R1&lt;br>R0 = 2 * R0"]
Cond -->|1| Branch1["R0 = R0 + R1&lt;br>R1 = 2 * R1"]
Branch0 --> LoopEnd["Bit suivant"]
Branch1 --> LoopEnd
LoopEnd --> LoopStart
LoopStart -.->|"Tous les bits terminés"| End["Fin : R0 est le résultat (kP)"]&lt;/div>
&lt;p>La beauté de l&amp;rsquo;échelle de Montgomery réside dans le fait que, que le bit soit &lt;code>0&lt;/code> ou &lt;code>1&lt;/code>, &lt;strong>&amp;ldquo;exactement 1 Point Addition et 1 Point Doubling&amp;rdquo;&lt;/strong> sont toujours exécutés. Cela élimine complètement la dépendance des données sur le temps de calcul.&lt;/p>
&lt;p>Cependant, si le branchement conditionnel (&lt;code>if (k_i == 0)&lt;/code>) lui-même existe, il reste un risque que le temps d&amp;rsquo;exécution fluctue en raison des optimisations du compilateur ou de la prédiction de branchement du processeur. Par conséquent, dans les implémentations réelles en temps constant, les branchements conditionnels (instructions &lt;code>if&lt;/code>) sont éliminés, et un &lt;strong>échange conditionnel utilisant des opérations bit à bit (Conditional Swap)&lt;/strong> est utilisé.&lt;/p>
&lt;hr>
&lt;h2 id="8-implémentation-de-la-cryptographie-sur-les-courbes-elliptiques-en-c">8. Implémentation de la cryptographie sur les courbes elliptiques en C++
&lt;/h2>&lt;p>À partir de là, nous allons traduire la théorie en code C++. Les bibliothèques cryptographiques pratiques (telles que OpenSSL ou libsodium) utilisent des optimisations avancées en assembleur et des systèmes de coordonnées jacobiennes, mais ici, pour approfondir la compréhension mathématique, nous présenterons le squelette d&amp;rsquo;une &lt;strong>implémentation claire en temps constant utilisant des coordonnées affines&lt;/strong>.&lt;/p>
&lt;p>Nous supposerons l&amp;rsquo;utilisation de &lt;code>boost::multiprecision::cpp_int&lt;/code> pour les opérations sur les très grands entiers.&lt;/p>
&lt;h3 id="81-arithmétique-modulaire-et-inverse">8.1. Arithmétique modulaire et inverse
&lt;/h3>&lt;p>Tout d&amp;rsquo;abord, nous définissons des fonctions d&amp;rsquo;aide pour les opérations sur les corps finis. Nous implémentons le calcul de l&amp;rsquo;inverse en utilisant le petit théorème de Fermat.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;stdexcept&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;boost/multiprecision/cpp_int.hpp&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="k">namespace&lt;/span> &lt;span class="n">boost&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">multiprecision&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Exemple avec le premier p et les paramètres de secp256k1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">p&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">7&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Opération modulo retournant un reste positif
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nl">m&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">r&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Calcul de l&amp;#39;exponentiation modulaire (x^y mod m)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">powerMod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">exp&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">base&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">exp&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">exp&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">res&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">base&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">base&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exp&lt;/span> &lt;span class="o">/=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">res&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Inverse modulo utilisant le petit théorème de Fermat
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">modInverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Prémisse que m est premier : n^(m-2) ≡ n^(-1) mod m
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">powerMod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="82-représentation-des-points-et-opérations-de-groupe-addition-doublement">8.2. Représentation des points et opérations de groupe (Addition, Doublement)
&lt;/h3>&lt;p>Nous définissons une structure &lt;code>Point&lt;/code> qui gère le point à l&amp;rsquo;infini avec un drapeau, et nous implémentons les formules d&amp;rsquo;addition.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">struct&lt;/span> &lt;span class="nc">Point&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="n">isInfinity&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Création d&amp;#39;un point à l&amp;#39;infini
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">isInfinity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">true&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Création d&amp;#39;un point normal
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">isInfinity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">false&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Addition de points sur la courbe elliptique (R = P + Q)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="nf">pointAdd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isInfinity&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isInfinity&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// P + (-P) = Point à l&amp;#39;infini
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">lambda&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Point Doubling (Cas où P = Q)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// lambda = (3x^2 + a) / 2y
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">den&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">modInverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lambda&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">den&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Point Addition (Cas où P != Q)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// lambda = (y2 - y1) / (x2 - x1)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">den&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">modInverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lambda&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">den&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x3&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">lambda&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">lambda&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">y3&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">lambda&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">x3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y3&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="83-implémentation-du-conditional-swap-en-temps-constant">8.3. Implémentation du Conditional Swap en temps constant
&lt;/h3>&lt;p>Lors de l&amp;rsquo;échange du contenu des variables basé sur la valeur du bit de la clé privée, nous effectuons l&amp;rsquo;échange uniquement avec des opérations bit à bit (masque) sans utiliser l&amp;rsquo;instruction &lt;code>if&lt;/code>. Cela garantit que le chemin d&amp;rsquo;exécution reste parfaitement constant.&lt;/p>
&lt;blockquote>
&lt;p>[!TIP]
Dans une implémentation réelle, une classe d&amp;rsquo;entiers à précision multiple allouée dynamiquement comme &lt;code>cpp_int&lt;/code> ne convient pas au traitement en temps constant. En effet, des informations temporelles fuient en raison des allocations de mémoire et des variations de taille des tableaux. Les bibliothèques pratiques les représentent sous forme de taille fixe (par exemple, un tableau de uint64_t × 4 éléments) et implémentent le traitement des masques au niveau du bit. Voici un exemple conceptuel.&lt;/p>
&lt;/blockquote>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Conditional Swap conceptuel en temps constant (supposant des entiers de taille fixe)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Si le bit est 1, échanger P1 et P2, sinon ne pas échanger
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">void&lt;/span> &lt;span class="nf">cswap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">bit&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// bit vaut 0 ou 1. Le masque est tout à 1 (0xFF..) si bit=1, et tout à 0 si bit=0.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// (Ici pour l&amp;#39;explication, nous supposons que chaque mot de la classe BigInt de taille fixe est w)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="cm">/*
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> uint64_t mask = 0 - (uint64_t)bit;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> for (int i = 0; i &amp;lt; NUM_WORDS; i++) {
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> uint64_t dummy = mask &amp;amp; (P1.x.words[i] ^ P2.x.words[i]);
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> P1.x.words[i] ^= dummy;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> P2.x.words[i] ^= dummy;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> // Traiter les coordonnées y et le drapeau isInfinity de la même manière
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// * Un échange parfait en temps constant est difficile avec boost::multiprecision,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// donc nous nous limitons ici à une simulation par branchement pour la compréhension de la logique.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">bit&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">P1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">P2&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="84-multiplication-scalaire-avec-léchelle-de-montgomery">8.4. Multiplication scalaire avec l&amp;rsquo;échelle de Montgomery
&lt;/h3>&lt;p>En combinant les &lt;code>pointAdd&lt;/code> et &lt;code>cswap&lt;/code> précédents, nous implémentons une multiplication scalaire sécurisée.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Multiplication scalaire k * P (Méthode Montgomery Ladder)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="nf">scalarMultiply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">k&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Point&lt;/span> &lt;span class="n">R0&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// Point à l&amp;#39;infini
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Point&lt;/span> &lt;span class="n">R1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Obtenir la longueur en bits de k (256 bits pour secp256k1)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">numBits&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">256&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">numBits&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">--&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Obtenir la valeur du i-ème bit (0 ou 1)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">bit&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">static_cast&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">uint8_t&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bit_test&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Si bit == 1, échanger R0 et R1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cswap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">bit&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Toujours exécuter les mêmes opérations (Point Addition et Point Doubling)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">R1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pointAdd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">R0&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pointAdd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Si bit == 1, échanger à nouveau pour restaurer l&amp;#39;état
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cswap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">bit&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">R0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Avec cette logique d&amp;rsquo;implémentation, que chaque bit du scalaire $k$ soit &lt;code>0&lt;/code> ou &lt;code>1&lt;/code>, les opérations exécutées dans chaque itération de la boucle (&lt;code>cswap&lt;/code> $\to$ &lt;code>pointAdd&lt;/code> $\to$ &lt;code>pointAdd&lt;/code> $\to$ &lt;code>cswap&lt;/code>) suivent exactement le même flux. Cela empêche efficacement la fuite d&amp;rsquo;informations secrètes via des différences de timing ou de modèles d&amp;rsquo;accès au cache.&lt;/p>
&lt;hr>
&lt;h2 id="9-conclusion">9. Conclusion
&lt;/h2>&lt;p>La cryptographie sur les courbes elliptiques (ECC) peut sembler mystérieuse à première vue : &amp;ldquo;Comment une opération géométrique consistant à tracer une droite et refléter son intersection peut-elle devenir une cryptographie ?&amp;rdquo;. Cependant, en la mappant sur le monde discret des corps finis, on peut construire une magnifique fonction à sens unique (problème du logarithme discret), fruit d&amp;rsquo;une fusion miraculeuse entre les mathématiques et la cryptographie.&lt;/p>
&lt;p>Cet article a expliqué les points importants suivants :&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Supériorité par rapport à RSA&lt;/strong> : Offre une sécurité forte avec une taille de clé très courte, ce qui est optimal pour l&amp;rsquo;ère moderne du mobile et de l&amp;rsquo;IoT.&lt;/li>
&lt;li>&lt;strong>Fondements de la théorie des groupes et des corps finis&lt;/strong> : Les structures mathématiques sur lesquelles repose l&amp;rsquo;ECC.&lt;/li>
&lt;li>&lt;strong>Formules d&amp;rsquo;addition et de doublement&lt;/strong> : Méthode d&amp;rsquo;implémentation des opérations algébriques de groupe à l&amp;rsquo;aide de l&amp;rsquo;équation de Weierstrass.&lt;/li>
&lt;li>&lt;strong>Menace des attaques par canaux auxiliaires&lt;/strong> : Le fait que les branchements conditionnels dépendants des bits de la clé privée créent une vulnérabilité fatale.&lt;/li>
&lt;li>&lt;strong>Implémentation en temps constant (Constant-Time)&lt;/strong> : Technique de codage en C++ pour homogénéiser le comportement au niveau matériel et prévenir les attaques à l&amp;rsquo;aide du Montgomery Ladder et du Conditional Swap.&lt;/li>
&lt;/ol>
&lt;p>Écrire soi-même une bibliothèque cryptographique fonctionnant en environnement de production est fortement déconseillé (&amp;ldquo;Don&amp;rsquo;t roll your own crypto&amp;rdquo;) car les risques de sécurité sont extrêmement élevés. Cependant, comprendre en profondeur les algorithmes et le contexte mathématique qui fonctionnent en son sein devrait être une arme incroyablement puissante pour les ingénieurs concevant et exploitant des systèmes plus sécurisés et plus performants.&lt;/p>
&lt;p>Dans le prochain article, nous approfondirons le mécanisme de l&amp;rsquo;&lt;strong>ECDSA (Elliptic Curve Digital Signature Algorithm)&lt;/strong>, un algorithme de signature numérique utilisant ces courbes elliptiques, ainsi que les &lt;strong>signatures de Schnorr&lt;/strong> adoptées par Bitcoin.&lt;/p></description></item><item><title>Simulation de l'algorithme de Shor en Python</title><link>http://kenji.blog/fr/p/shors-algorithm-simulation-python/</link><pubDate>Fri, 11 Sep 2026 08:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/shors-algorithm-simulation-python/</guid><description>&lt;img src="http://kenji.blog/p/shors-algorithm-simulation-python/img/eyecatch.jpg" alt="Featured image of post Simulation de l'algorithme de Shor en Python" />&lt;h1 id="1-introduction--la-crise-de-la-cryptographie-provoquée-par-les-ordinateurs-quantiques">1. Introduction : La crise de la cryptographie provoquée par les ordinateurs quantiques
&lt;/h1>&lt;p>Une grande partie de la sécurité dans notre société Internet moderne repose sur la &lt;strong>cryptographie à clé publique&lt;/strong> (en particulier le chiffrement RSA). Lorsque nous transmettons nos informations de carte de crédit lors d&amp;rsquo;achats en ligne ou que nous échangeons des données hautement confidentielles, ces communications sont solidement protégées par le chiffrement RSA.&lt;/p>
&lt;p>La sécurité du chiffrement RSA repose sur un fait mathématique : « &lt;strong>la factorisation en nombres premiers de très grands entiers est extrêmement difficile pour les ordinateurs classiques (les PC ou supercalculateurs que nous utilisons habituellement)&lt;/strong> ». Cependant, l&amp;rsquo;« &lt;strong>algorithme de Shor&lt;/strong> » (Shor&amp;rsquo;s Algorithm), publié en 1994 par Peter Shor, a complètement remis en cause ce postulat. Il a été prouvé mathématiquement que si l&amp;rsquo;algorithme de Shor était exécuté sur un ordinateur quantique à grande échelle, il pourrait résoudre en quelques minutes ou quelques heures une factorisation qui prendrait plus de temps que l&amp;rsquo;âge de l&amp;rsquo;univers sur un ordinateur classique.&lt;/p>
&lt;p>Dans cet article, nous expliquerons en détail comment cet algorithme de Shor parvient à effectuer cette factorisation à grande vitesse, de son mécanisme mathématique jusqu&amp;rsquo;à une implémentation de simulation concrète en Python utilisant le framework de calcul quantique &lt;strong>Qiskit&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h1 id="2-le-changement-spectaculaire-de-la-complexité--de-la-fonction-exponentielle-au-temps-polynomial">2. Le changement spectaculaire de la complexité : De la fonction exponentielle au temps polynomial
&lt;/h1>&lt;p>Pourquoi la factorisation en nombres premiers est-elle si difficile ? Même en utilisant le « crible général du corps de nombres » (General Number Field Sieve, GNFS), connu comme le meilleur algorithme de factorisation pour les ordinateurs classiques, sa complexité en temps reste sous-exponentielle.&lt;/p>
&lt;p>La complexité en temps pour factoriser un nombre composé de $N$ chiffres avec une méthode classique est la suivante :&lt;/p>
$$ O\left(\exp\left( c (\log N)^{1/3} (\log \log N)^{2/3} \right)\right) $$
&lt;p>Pour cette raison, il suffit d&amp;rsquo;augmenter la longueur de la clé (par exemple à 2048 ou 4096 bits) pour que le temps de décryptage sur un ordinateur classique devienne irréaliste, atteignant des milliers ou des dizaines de milliers d&amp;rsquo;années.&lt;/p>
&lt;p>Cependant, en utilisant l&amp;rsquo;&lt;strong>algorithme de Shor&lt;/strong> sur un ordinateur quantique, la complexité est considérablement réduite à un temps polynomial par rapport au nombre de bits d&amp;rsquo;entrée $\log N$.&lt;/p>
$$ O((\log N)^3) $$
&lt;p>Cela signifie que si l&amp;rsquo;on double le nombre de bits, le temps de calcul augmente de manière astronomique pour un ordinateur classique, alors qu&amp;rsquo;il n&amp;rsquo;est multiplié que par 8 environ pour un ordinateur quantique. Cette &lt;strong>réduction de la classe de complexité d&amp;rsquo;un temps exponentiel à un temps polynomial (inclusion dans la classe BQP)&lt;/strong> est ce qui rend l&amp;rsquo;algorithme de Shor si impressionnant.&lt;/p>
&lt;div class="mermaid">graph TD
A["Augmentation de la taille de l'entrée N (nombre de bits)"] --> B{"Choix de l'algorithme"}
B -->|Classique : Crible général du corps de nombres| C["Augmentation sous-exponentielle O(exp(...))"]
B -->|Quantique : Algorithme de Shor| D["Temps polynomial O((log N)^3)"]
C --> E["Milliers à milliards d'années (Indéchiffrable)"]
D --> F["Quelques minutes à quelques heures (Déchiffrable en un temps réaliste)"]&lt;/div>
&lt;hr>
&lt;h1 id="3-vue-densemble-de-lalgorithme-et-contexte-mathématique">3. Vue d&amp;rsquo;ensemble de l&amp;rsquo;algorithme et contexte mathématique
&lt;/h1>&lt;p>En réalité, l&amp;rsquo;algorithme de Shor n&amp;rsquo;effectue pas toutes les opérations sur un ordinateur quantique. Il repose sur la collaboration entre des pré-traitements et post-traitements par un ordinateur classique, et la partie centrale (l&amp;rsquo;algorithme de recherche de période) exécutée par un ordinateur quantique.&lt;/p>
&lt;p>Le flux global de l&amp;rsquo;algorithme est le suivant :&lt;/p>
&lt;div class="mermaid">graph TD
A["Entrée : Nombre composé N à factoriser"] --> B["Choisir un nombre aléatoire a tel que a &lt; N"]
B --> C{"gcd(a, N) > 1 ?"}
C -- "Oui" --> D["Afficher le facteur trivial gcd(a, N) et terminer"]
C -- "Non" --> E["Trouver la période r de f(x) = a^x mod N avec un algorithme quantique"]
E --> F{"r est pair ET a^(r/2) ≢ -1 mod N ?"}
F -- "Non" --> B
F -- "Oui" --> G["Calculer les facteurs p = gcd(a^(r/2) - 1, N), q = gcd(a^(r/2) + 1, N)"]
G --> H["Sortie : p, q"]&lt;/div>
&lt;h2 id="réduction-de-la-factorisation-au-problème-de-recherche-de-période">Réduction de la factorisation au problème de recherche de période
&lt;/h2>&lt;p>L&amp;rsquo;intuition géniale de Shor réside dans la transformation du « &lt;strong>problème de factorisation&lt;/strong> » en un « &lt;strong>problème de recherche de période&lt;/strong> » (Order Finding Problem).&lt;/p>
&lt;p>Considérons un entier $N$ (le nombre à factoriser) et un entier premier avec lui $a$ ($1 &lt; a &lt; N$). Nous définissons la fonction d&amp;rsquo;exponentiation modulaire suivante :&lt;/p>
$$ f(x) = a^x \bmod N $$
&lt;p>Cette fonction possède une certaine période $r$. Cela signifie que pour tout $x$, on a $f(x+r) = f(x)$. En particulier pour $x=0$, le plus petit entier positif $r$ tel que :&lt;/p>
$$ a^r \equiv 1 \pmod N $$
&lt;p>est appelé l&amp;rsquo;« ordre » (Order) de $a$ modulo $N$. Si nous parvenons à trouver cette période $r$, nous pouvons en déduire les facteurs premiers de la manière suivante.&lt;/p>
&lt;p>En transformant l&amp;rsquo;équation, on obtient :
&lt;/p>
$$ a^r - 1 \equiv 0 \pmod N $$
&lt;p>
Si $r$ est pair, nous pouvons factoriser en utilisant la différence de deux carrés :
&lt;/p>
$$ (a^{r/2} - 1)(a^{r/2} + 1) \equiv 0 \pmod N $$
&lt;p>Cela implique que $N$ partage un diviseur commun avec $(a^{r/2} - 1)$ ou $(a^{r/2} + 1)$ (à condition que $a^{r/2} \not\equiv -1 \pmod N$). Ainsi, en utilisant l&amp;rsquo;algorithme d&amp;rsquo;Euclide pour calculer :&lt;/p>
$$ p = \gcd(a^{r/2} - 1, N) $$
$$ q = \gcd(a^{r/2} + 1, N) $$
&lt;p>nous pouvons trouver des facteurs non triviaux $p$ et $q$ de $N$. Ces calculs (le plus grand commun diviseur et la génération de nombres aléatoires) sont très rapides sur un ordinateur classique. Le cœur du problème est donc de savoir &lt;strong>comment trouver rapidement la période $r$&lt;/strong>. Sur un ordinateur classique, trouver cette période requiert un temps exponentiel. C&amp;rsquo;est ici que l&amp;rsquo;ordinateur quantique entre en jeu.&lt;/p>
&lt;hr>
&lt;h1 id="4-la-partie-algorithmique-quantique--le-mécanisme-de-recherche-de-période">4. La partie algorithmique quantique : Le mécanisme de recherche de période
&lt;/h1>&lt;p>La sous-routine permettant de trouver la période $r$ à l&amp;rsquo;aide d&amp;rsquo;un ordinateur quantique se compose des 4 étapes suivantes :&lt;/p>
&lt;div class="mermaid">graph LR
subgraph "Évolution de l'état quantique"
S1["|0⟩|0⟩ (Initialisation)"] --> S2["Porte H : Superposition Σ|x⟩|0⟩"]
S2 --> S3["Oracle U : Σ|x⟩|a^x mod N⟩"]
S3 --> S4["QFT : Extraction de la période par interférence"]
S4 --> S5["Mesure : Obtention de la valeur approchée y"]
end&lt;/div>
&lt;h2 id="étape-1--initialisation-des-registres-quantiques-et-superposition">Étape 1 : Initialisation des registres quantiques et superposition
&lt;/h2>&lt;p>Tout d&amp;rsquo;abord, nous préparons deux registres quantiques. Le premier registre sert à entrer l&amp;rsquo;état, et le second sert à stocker le résultat du calcul de la fonction.
L&amp;rsquo;état initial est entièrement $|0\rangle$.&lt;/p>
$$ |\psi_0\rangle = |0\rangle_1 |0\rangle_2 $$
&lt;p>Nous appliquons une porte de Hadamard (Hadamard Gate) à tous les qubits du premier registre, créant un état de superposition équiprobable de toutes les entrées possibles $x$ (de $0$ à $Q-1$, avec $Q=2^n$).&lt;/p>
$$ |\psi_1\rangle = \frac{1}{\sqrt{Q}} \sum_{x=0}^{Q-1} |x\rangle_1 |0\rangle_2 $$
&lt;p>Ainsi, l&amp;rsquo;ordinateur quantique conserve simultanément l&amp;rsquo;état pour les $Q$ entrées en une seule opération. C&amp;rsquo;est la source puissante du &lt;strong>parallélisme quantique&lt;/strong>.&lt;/p>
&lt;h2 id="étape-2--application-de-la-fonction-oracle-exponentiation-modulaire">Étape 2 : Application de la fonction oracle (exponentiation modulaire)
&lt;/h2>&lt;p>Ensuite, nous utilisons un circuit quantique $U_f$ pour calculer la fonction $f(x) = a^x \bmod N$ et stockons le résultat dans le second registre.&lt;/p>
$$ |\psi_2\rangle = \frac{1}{\sqrt{Q}} \sum_{x=0}^{Q-1} |x\rangle_1 |a^x \bmod N\rangle_2 $$
&lt;p>À ce stade, le premier et le second registre sont dans un état d&amp;rsquo;&lt;strong>intrication quantique&lt;/strong> (entanglement). Si (hypothétiquement) nous observions le second registre et obtenions une valeur spécifique $k = a^{x_0} \bmod N$, l&amp;rsquo;état du premier registre s&amp;rsquo;effondrerait sur la superposition des $x$ qui donnent cette valeur $k$. Puisque la fonction a une période $r$, les états restants seront espacés de $r$, soit $x_0, x_0+r, x_0+2r, \dots$.&lt;/p>
$$ |\psi_3\rangle = \sqrt{\frac{r}{Q}} \sum_{j=0}^{M-1} |x_0 + j r\rangle_1 |k\rangle_2 $$
&lt;p>Cependant, ce n&amp;rsquo;est pas $x_0$ que nous voulons connaître, mais la période $r$ elle-même. Il est impossible d&amp;rsquo;observer directement $r$ à partir de cet état. C&amp;rsquo;est pourquoi nous utilisons la transformée de Fourier quantique.&lt;/p>
&lt;h2 id="étape-3--interférence-de-phase-par-la-transformée-de-fourier-quantique-qft">Étape 3 : Interférence de phase par la transformée de Fourier quantique (QFT)
&lt;/h2>&lt;p>Nous appliquons la &lt;strong>transformée de Fourier quantique&lt;/strong> (Quantum Fourier Transform, QFT) au premier registre. La QFT est la version quantique de la transformée de Fourier discrète classique et convertit les amplitudes des vecteurs d&amp;rsquo;état. L&amp;rsquo;action de la QFT sur l&amp;rsquo;état de base $|x\rangle$ est définie comme suit :&lt;/p>
$$ QFT |x\rangle = \frac{1}{\sqrt{Q}} \sum_{y=0}^{Q-1} \omega^{xy} |y\rangle $$
&lt;p>Où $\omega = e^{2\pi i / Q}$.&lt;/p>
&lt;p>Lorsque la QFT est appliquée, les amplitudes de l&amp;rsquo;état interfèrent. Bien que nous omettions les détails mathématiques, lorsqu&amp;rsquo;on applique la QFT à un état ayant une période $r$, les ondes provoquent une &lt;strong>interférence constructive&lt;/strong> uniquement lorsque $y$ est très proche d&amp;rsquo;un multiple entier de $Q/r$. Pour les autres états, les amplitudes de probabilité s&amp;rsquo;annulent à cause d&amp;rsquo;une &lt;strong>interférence destructive&lt;/strong> et s&amp;rsquo;approchent de zéro.&lt;/p>
&lt;h2 id="étape-4--mesure-et-développement-en-fractions-continues">Étape 4 : Mesure et développement en fractions continues
&lt;/h2>&lt;p>Enfin, nous mesurons le premier registre. La valeur mesurée $y$ satisfait très probablement à la condition suivante :&lt;/p>
$$ y \approx c \frac{Q}{r} \implies \frac{y}{Q} \approx \frac{c}{r} $$
&lt;p>($c$ est un entier inconnu tel que $0 \le c &lt; r$)&lt;/p>
&lt;p>En appliquant un algorithme classique de &lt;strong>développement en fractions continues&lt;/strong> (Continued Fraction Expansion) au nombre rationnel obtenu $y/Q$, nous pouvons calculer la fraction approchée $c/r$ et extraire la période $r$ du dénominateur.&lt;/p>
&lt;hr>
&lt;h1 id="5-implémentation-de-simulation-avec-python-et-qiskit">5. Implémentation de simulation avec Python et Qiskit
&lt;/h1>&lt;p>Puisque la théorie seule peut être abstraite, simulons l&amp;rsquo;algorithme de Shor en pratique avec Python et le framework quantique d&amp;rsquo;IBM, &lt;strong>Qiskit&lt;/strong>.&lt;/p>
&lt;p>Nous implémenterons ici le scénario le plus classique et le plus célèbre : &lt;strong>« factoriser $N=15$ en utilisant $a=7$ »&lt;/strong>.&lt;/p>
&lt;h2 id="préparation-de-lenvironnement-dexécution">Préparation de l&amp;rsquo;environnement d&amp;rsquo;exécution
&lt;/h2>&lt;p>Veuillez installer Qiskit au préalable.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">pip install qiskit qiskit-aer numpy
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="aperçu-du-code-de-limplémentation-python">Aperçu du code de l&amp;rsquo;implémentation Python
&lt;/h2>&lt;p>Le code suivant est un exemple d&amp;rsquo;implémentation de l&amp;rsquo;algorithme de Shor spécifiquement pour $N=15$ et $a=7$. Étant donné que le coût de calcul pour construire un circuit d&amp;rsquo;exponentiation modulaire généralisé est trop élevé sur les simulateurs actuels, la logique des portes pour le cas particulier de $a=7$ a été codée en dur (hardcoded).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt"> 10
&lt;/span>&lt;span class="lnt"> 11
&lt;/span>&lt;span class="lnt"> 12
&lt;/span>&lt;span class="lnt"> 13
&lt;/span>&lt;span class="lnt"> 14
&lt;/span>&lt;span class="lnt"> 15
&lt;/span>&lt;span class="lnt"> 16
&lt;/span>&lt;span class="lnt"> 17
&lt;/span>&lt;span class="lnt"> 18
&lt;/span>&lt;span class="lnt"> 19
&lt;/span>&lt;span class="lnt"> 20
&lt;/span>&lt;span class="lnt"> 21
&lt;/span>&lt;span class="lnt"> 22
&lt;/span>&lt;span class="lnt"> 23
&lt;/span>&lt;span class="lnt"> 24
&lt;/span>&lt;span class="lnt"> 25
&lt;/span>&lt;span class="lnt"> 26
&lt;/span>&lt;span class="lnt"> 27
&lt;/span>&lt;span class="lnt"> 28
&lt;/span>&lt;span class="lnt"> 29
&lt;/span>&lt;span class="lnt"> 30
&lt;/span>&lt;span class="lnt"> 31
&lt;/span>&lt;span class="lnt"> 32
&lt;/span>&lt;span class="lnt"> 33
&lt;/span>&lt;span class="lnt"> 34
&lt;/span>&lt;span class="lnt"> 35
&lt;/span>&lt;span class="lnt"> 36
&lt;/span>&lt;span class="lnt"> 37
&lt;/span>&lt;span class="lnt"> 38
&lt;/span>&lt;span class="lnt"> 39
&lt;/span>&lt;span class="lnt"> 40
&lt;/span>&lt;span class="lnt"> 41
&lt;/span>&lt;span class="lnt"> 42
&lt;/span>&lt;span class="lnt"> 43
&lt;/span>&lt;span class="lnt"> 44
&lt;/span>&lt;span class="lnt"> 45
&lt;/span>&lt;span class="lnt"> 46
&lt;/span>&lt;span class="lnt"> 47
&lt;/span>&lt;span class="lnt"> 48
&lt;/span>&lt;span class="lnt"> 49
&lt;/span>&lt;span class="lnt"> 50
&lt;/span>&lt;span class="lnt"> 51
&lt;/span>&lt;span class="lnt"> 52
&lt;/span>&lt;span class="lnt"> 53
&lt;/span>&lt;span class="lnt"> 54
&lt;/span>&lt;span class="lnt"> 55
&lt;/span>&lt;span class="lnt"> 56
&lt;/span>&lt;span class="lnt"> 57
&lt;/span>&lt;span class="lnt"> 58
&lt;/span>&lt;span class="lnt"> 59
&lt;/span>&lt;span class="lnt"> 60
&lt;/span>&lt;span class="lnt"> 61
&lt;/span>&lt;span class="lnt"> 62
&lt;/span>&lt;span class="lnt"> 63
&lt;/span>&lt;span class="lnt"> 64
&lt;/span>&lt;span class="lnt"> 65
&lt;/span>&lt;span class="lnt"> 66
&lt;/span>&lt;span class="lnt"> 67
&lt;/span>&lt;span class="lnt"> 68
&lt;/span>&lt;span class="lnt"> 69
&lt;/span>&lt;span class="lnt"> 70
&lt;/span>&lt;span class="lnt"> 71
&lt;/span>&lt;span class="lnt"> 72
&lt;/span>&lt;span class="lnt"> 73
&lt;/span>&lt;span class="lnt"> 74
&lt;/span>&lt;span class="lnt"> 75
&lt;/span>&lt;span class="lnt"> 76
&lt;/span>&lt;span class="lnt"> 77
&lt;/span>&lt;span class="lnt"> 78
&lt;/span>&lt;span class="lnt"> 79
&lt;/span>&lt;span class="lnt"> 80
&lt;/span>&lt;span class="lnt"> 81
&lt;/span>&lt;span class="lnt"> 82
&lt;/span>&lt;span class="lnt"> 83
&lt;/span>&lt;span class="lnt"> 84
&lt;/span>&lt;span class="lnt"> 85
&lt;/span>&lt;span class="lnt"> 86
&lt;/span>&lt;span class="lnt"> 87
&lt;/span>&lt;span class="lnt"> 88
&lt;/span>&lt;span class="lnt"> 89
&lt;/span>&lt;span class="lnt"> 90
&lt;/span>&lt;span class="lnt"> 91
&lt;/span>&lt;span class="lnt"> 92
&lt;/span>&lt;span class="lnt"> 93
&lt;/span>&lt;span class="lnt"> 94
&lt;/span>&lt;span class="lnt"> 95
&lt;/span>&lt;span class="lnt"> 96
&lt;/span>&lt;span class="lnt"> 97
&lt;/span>&lt;span class="lnt"> 98
&lt;/span>&lt;span class="lnt"> 99
&lt;/span>&lt;span class="lnt">100
&lt;/span>&lt;span class="lnt">101
&lt;/span>&lt;span class="lnt">102
&lt;/span>&lt;span class="lnt">103
&lt;/span>&lt;span class="lnt">104
&lt;/span>&lt;span class="lnt">105
&lt;/span>&lt;span class="lnt">106
&lt;/span>&lt;span class="lnt">107
&lt;/span>&lt;span class="lnt">108
&lt;/span>&lt;span class="lnt">109
&lt;/span>&lt;span class="lnt">110
&lt;/span>&lt;span class="lnt">111
&lt;/span>&lt;span class="lnt">112
&lt;/span>&lt;span class="lnt">113
&lt;/span>&lt;span class="lnt">114
&lt;/span>&lt;span class="lnt">115
&lt;/span>&lt;span class="lnt">116
&lt;/span>&lt;span class="lnt">117
&lt;/span>&lt;span class="lnt">118
&lt;/span>&lt;span class="lnt">119
&lt;/span>&lt;span class="lnt">120
&lt;/span>&lt;span class="lnt">121
&lt;/span>&lt;span class="lnt">122
&lt;/span>&lt;span class="lnt">123
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">numpy&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">np&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">qiskit&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">QuantumCircuit&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">qiskit_aer&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">AerSimulator&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">qiskit.visualization&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">plot_histogram&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">fractions&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Fraction&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">math&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. Fonction pour construire la transformée de Fourier quantique inverse (QFT†)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">qft_dagger&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Génère le circuit de la transformée de Fourier quantique inverse pour n qubits&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">QuantumCircuit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Portes SWAP pour inverser l&amp;#39;ordre&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">qubit&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="o">//&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">qubit&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">qubit&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Application des portes de phase contrôlée et H&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">j&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">m&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">cp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pi&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="nb">float&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">)),&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">j&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">h&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;QFT_dagger&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">qc&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. Fonction pour construire l&amp;#39;opération contrôlée d&amp;#39;exponentiation modulaire 7^x mod 15&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">c_amod15&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">power&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Génère la porte U contrôlée pour un &amp;#39;a&amp;#39; spécifique et une puissance (Dédié à N=15)&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">QuantumCircuit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">power&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Logique codée en dur pour 7^x mod 15 avec a=7&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">13&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">7&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">11&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">7&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">11&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">13&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">q&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">q&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_gate&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">^&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">power&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> mod 15&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">c_U&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">control&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">c_U&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. Construction du circuit quantique principal&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">shor_circuit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n_count&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># n_count : nombre de bits du registre de contrôle&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Le registre cible utilise 4 bits pour représenter de 0 à 15&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">QuantumCircuit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n_count&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n_count&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Initialisation du 1er registre (registre de contrôle) pour créer la superposition&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">q&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n_count&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">h&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">q&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Initialisation du 2ème registre (registre cible) à |1&amp;gt; (0001)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">n_count&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Application de l&amp;#39;opération d&amp;#39;exponentiation modulaire contrôlée (Oracle)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">q&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n_count&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Applique l&amp;#39;opération à la puissance 2^q&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">c_amod15&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="n">q&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="n">q&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="n">n_count&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">)])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Application de la transformée de Fourier quantique inverse au 1er registre&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">qft_dagger&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n_count&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n_count&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Mesure du 1er registre&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">measure&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n_count&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n_count&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">qc&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># --- Section d&amp;#39;exécution ---&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">N&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">15&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">7&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">n_count&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">8&lt;/span> &lt;span class="c1"># Utilisation de 8 qubits pour le registre de contrôle (Q=256)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Paramètres de recherche : N=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">N&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">, a=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">, qubits de contrôle=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">n_count&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Génération du circuit&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">shor_circuit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n_count&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Exécution avec le simulateur&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sim&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AerSimulator&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># La transpilation est recommandée dans les versions récentes de Qiskit&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kn">from&lt;/span> &lt;span class="nn">qiskit&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">transpile&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">compiled_circuit&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">transpile&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">qc&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">sim&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">job&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sim&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">compiled_circuit&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">shots&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1024&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">job&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">counts&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_counts&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">Résultats de la mesure (chaîne de bits : nombre d&amp;#39;observations) :&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">bitstring&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">count&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">counts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34; &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">bitstring&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> : &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">count&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> fois&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Post-traitement classique : Détermination de la période r via les fractions continues&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">--- Calcul de la période et factorisation ---&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">phases&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">output&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">counts&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Conversion de la chaîne de bits en décimal&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">decimal&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">output&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Phase = valeur mesurée / 2^n_count&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">phase&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">decimal&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="n">n_count&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">phases&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">phase&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Obtention de la fraction approchée. Le dénominateur max est N=15&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">frac&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Fraction&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">phase&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">limit_denominator&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">15&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">r&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">frac&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">denominator&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Mesure : &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">decimal&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">3d&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> | Phase : &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">phase&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.4f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> | Fraction continue : &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">frac&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> | Période estimée r = &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">r&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Vérification : la période r est-elle paire et produit-elle un résultat valide ?&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">guess1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">math&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">r&lt;/span>&lt;span class="o">//&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">guess2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">math&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">r&lt;/span>&lt;span class="o">//&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">guess1&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="ow">or&lt;/span> &lt;span class="n">guess2&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34; =&amp;gt; Succès ! Les facteurs de &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">N&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> sont &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">guess1&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> et &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">guess2&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34; =&amp;gt; Facteurs triviaux uniquement. À refaire.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34; =&amp;gt; Échec car la période est impaire.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="explication-du-code-et-analyse-des-résultats">Explication du code et analyse des résultats
&lt;/h2>&lt;p>L&amp;rsquo;exécution du code ci-dessus montre des pics spécifiques (valeurs mesurées) avec une forte probabilité pour le registre de contrôle. Dans le cas où &lt;code>n_count=8&lt;/code> ($Q=256$), si nous avions un ordinateur quantique idéal (ou un simulateur), les valeurs &lt;code>0&lt;/code>, &lt;code>64&lt;/code>, &lt;code>128&lt;/code>, &lt;code>192&lt;/code> apparaîtraient avec une probabilité écrasante.&lt;/p>
&lt;p>En divisant ces valeurs par $Q=256$, nous obtenons les phases respectives $y/Q$ de $0.0$, $0.25$, $0.5$ et $0.75$.
Le développement en fractions continues de ces phases donne :&lt;/p>
&lt;ul>
&lt;li>$0.25 \to 1/4$ (Période estimée $r=4$)&lt;/li>
&lt;li>$0.50 \to 1/2$ (Période estimée $r=2$)&lt;/li>
&lt;li>$0.75 \to 3/4$ (Période estimée $r=4$)&lt;/li>
&lt;/ul>
&lt;p>En utilisant la période $r=4$ ainsi obtenue, nous calculons les facteurs premiers.
Puisque $a=7$ et $r=4$,
$p = \gcd(7^2 - 1, 15) = \gcd(48, 15) = 3$
$q = \gcd(7^2 + 1, 15) = \gcd(50, 15) = 5$&lt;/p>
&lt;p>Nous avons réussi brillamment la factorisation de $15 = 3 \times 5$.&lt;/p>
&lt;blockquote>
&lt;p>[!TIP]
Si la valeur mesurée est $y=128$ (phase $0.5$), le dénominateur devient $2$, et nous obtenons un diviseur de la vraie période au lieu de $r=4$. Dans ce cas, nous pouvons relancer l&amp;rsquo;algorithme ou tester les multiples de la période $r$ obtenue pour trouver la vraie période.&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h1 id="6-défis-pour-lapplication-pratique-et-les-limites-de-lère-nisq">6. Défis pour l&amp;rsquo;application pratique et les limites de l&amp;rsquo;ère NISQ
&lt;/h1>&lt;p>Bien qu&amp;rsquo;il soit facile de factoriser $N=15$ sur un simulateur, factoriser le chiffrement RSA-2048 utilisé dans le monde réel (un nombre de 617 chiffres) se heurte encore à de nombreux obstacles avec les ordinateurs quantiques actuels.&lt;/p>
&lt;p>L&amp;rsquo;époque dans laquelle nous vivons actuellement est appelée l&amp;rsquo;&lt;strong>ère NISQ (Noisy Intermediate-Scale Quantum : ordinateurs quantiques bruités de taille intermédiaire)&lt;/strong>. Les qubits sont extrêmement sensibles au bruit ambiant et subissent de la « décohérence » pendant les calculs, ce qui détruit leur état.&lt;/p>
&lt;p>Pour exécuter avec précision un circuit profond (avec de nombreuses portes quantiques) comme l&amp;rsquo;algorithme de Shor, il est indispensable de disposer de la &lt;strong>correction d&amp;rsquo;erreurs quantiques&lt;/strong> (Quantum Error Correction). Pour créer un seul « qubit logique » sans bruit, il faut encoder des milliers de « qubits physiques » en utilisant des méthodes comme le code de surface (Surface Code).&lt;/p>
&lt;p>Pour casser le chiffrement RSA 2048 bits, on estime qu&amp;rsquo;il faudrait quelques milliers de qubits logiques parfaits, ce qui nécessiterait un ordinateur quantique tolérant aux pannes (fault-tolerant) doté de &lt;strong>plusieurs millions à dizaines de millions de qubits physiques&lt;/strong>. Les processeurs quantiques les plus avancés d&amp;rsquo;aujourd&amp;rsquo;hui ne comptant que quelques centaines à quelques milliers de qubits physiques, les chiffrements du monde entier ne seront pas brisés dans l&amp;rsquo;immédiat.&lt;/p>
&lt;blockquote>
&lt;p>[!WARNING]
Cependant, il existe un modèle de menace appelé « Store Now, Decrypt Later » (Sauvegarder maintenant, déchiffrer plus tard). Des attaquants pourraient stocker massivement les communications chiffrées actuelles et les déchiffrer entièrement dans 10 à 20 ans dès qu&amp;rsquo;un ordinateur quantique suffisamment puissant sera construit.&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h1 id="7-transition-vers-la-cryptographie-post-quantique-pqc">7. Transition vers la cryptographie post-quantique (PQC)
&lt;/h1>&lt;p>Pour se préparer à l&amp;rsquo;arrivée du « Q-Day » (le jour où les ordinateurs quantiques briseront la cryptographie), les cryptographes du monde entier, menés par le National Institute of Standards and Technology (NIST) américain, élaborent la &lt;strong>cryptographie post-quantique (Post-Quantum Cryptography, PQC)&lt;/strong>.&lt;/p>
&lt;p>La PQC est basée sur de nouveaux problèmes mathématiques (problèmes de réseaux euclidiens, polynômes multivariés, fonctions de hachage, etc.) que l&amp;rsquo;on considère impossibles à résoudre efficacement même avec l&amp;rsquo;algorithme de Shor (ou l&amp;rsquo;algorithme de Grover). Des algorithmes comme « CRYSTALS-Kyber » et « CRYSTALS-Dilithium » ont déjà été sélectionnés comme normes standards, et leur intégration commence progressivement dans les protocoles de communication des navigateurs web ou iMessage d&amp;rsquo;Apple.&lt;/p>
&lt;p>Pour les ingénieurs qui gèrent les infrastructures informatiques, intégrer l&amp;rsquo;« agilité cryptographique » (la capacité à changer rapidement de méthode de chiffrement) pour passer du RSA existant ou de la cryptographie sur les courbes elliptiques à la PQC, constituera une mission majeure dans le futur.&lt;/p>
&lt;hr>
&lt;h1 id="8-conclusion">8. Conclusion
&lt;/h1>&lt;p>Dans cet article, nous avons fourni une explication exhaustive d&amp;rsquo;environ 10 000 caractères, allant du contexte mathématique théorique de l&amp;rsquo;algorithme de Shor aux mécanismes d&amp;rsquo;extraction de période par la transformée de Fourier quantique, jusqu&amp;rsquo;au code de simulation concret avec Python et Qiskit.&lt;/p>
&lt;p>Le fait que les lois physiques du monde microscopique de la mécanique quantique bouleversent fondamentalement les fondations de l&amp;rsquo;informatique macroscopique telles que la théorie de la complexité et la cryptographie est l&amp;rsquo;un des changements de paradigme les plus excitants de l&amp;rsquo;histoire des sciences. Il est crucial de continuer à suivre cette bataille en cours entre l&amp;rsquo;évolution des technologies informatiques quantiques et les nouvelles technologies cryptographiques conçues pour y résister.&lt;/p>
&lt;p>N&amp;rsquo;hésitez pas à exécuter le code Python présenté dans cet article sur votre propre environnement pour expérimenter la « magie du calcul » créée par la superposition et l&amp;rsquo;interférence des états quantiques.&lt;/p>
&lt;hr>
&lt;p>&lt;strong>Références&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Shor, P. W. (1994). &amp;ldquo;Algorithms for quantum computation: discrete logarithms and factoring&amp;rdquo;. Proceedings 35th Annual Symposium on Foundations of Computer Science.&lt;/li>
&lt;li>Nielsen, M. A., &amp;amp; Chuang, I. L. (2010). &amp;ldquo;Quantum Computation and Quantum Information&amp;rdquo;. Cambridge University Press.&lt;/li>
&lt;li>Documentation Qiskit : &lt;a class="link" href="https://qiskit.org/documentation/" target="_blank" rel="noopener"
>https://qiskit.org/documentation/&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>【Illustration PQC】 Comparaison des principaux algorithmes de la cryptographie post-quantique</title><link>http://kenji.blog/fr/p/post-quantum-cryptography-algorithms-comparison/</link><pubDate>Fri, 11 Sep 2026 07:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/post-quantum-cryptography-algorithms-comparison/</guid><description>&lt;img src="http://kenji.blog/p/post-quantum-cryptography-algorithms-comparison/img/eyecatch.jpg" alt="Featured image of post 【Illustration PQC】 Comparaison des principaux algorithmes de la cryptographie post-quantique" />&lt;h2 id="1-introduction--la--crise-de-la-cryptographie--provoquée-par-les-ordinateurs-quantiques">1. Introduction : La « crise de la cryptographie » provoquée par les ordinateurs quantiques
&lt;/h2>&lt;p>Dans la société Internet moderne, la cryptographie à clé publique est une infrastructure indispensable pour protéger la confidentialité des communications et l&amp;rsquo;intégrité des données. Les méthodes de cryptographie largement utilisées aujourd&amp;rsquo;hui, telles que RSA et la cryptographie sur les courbes elliptiques (ECC), reposent sur des barrières mathématiques telles que la « difficulté de la factorisation de très grands nombres composés » ou la « difficulté du problème du logarithme discret sur les courbes elliptiques » pour garantir leur sécurité. Avec les ordinateurs classiques (les ordinateurs que nous utilisons actuellement, y compris les superordinateurs), il a été prouvé qu&amp;rsquo;il faudrait plus de temps que l&amp;rsquo;âge de l&amp;rsquo;univers pour résoudre ces problèmes mathématiques, ce qui constitue le fondement de leur sécurité.&lt;/p>
&lt;p>Cependant, cette prémisse solide est sur le point d&amp;rsquo;être fondamentalement bouleversée par l&amp;rsquo;avancée de la théorie et de la mise en pratique des &lt;strong>ordinateurs quantiques&lt;/strong>. En 1994, l&amp;rsquo;algorithme de Shor, publié par le cryptographe Peter Shor (« &lt;strong>Algorithme de Shor&lt;/strong> »), a prouvé théoriquement que les problèmes de factorisation et de logarithme discret pourraient être résolus en « temps polynomial » s&amp;rsquo;ils étaient exécutés sur un ordinateur quantique universel tolérant aux pannes (CRQC : Cryptographically Relevant Quantum Computer) d&amp;rsquo;une capacité suffisante. Cela signifie que toutes les cryptographies à clé publique utilisées actuellement seront rendues inefficaces.&lt;/p>
&lt;div class="mermaid">graph TD
A["Ordinateur quantique à grande échelle (CRQC)"] -->|Exécution| B["Algorithme de Shor"]
B -->|Déchiffrement en temps polynomial| C["Problème de factorisation en nombres premiers (RSA)"]
B -->|Déchiffrement en temps polynomial| D["Problème du logarithme discret (ECC / ECDSA)"]
C --> E["Écoute de communications chiffrées, altération de données, usurpation d'identité"]
D --> E
F["Store Now, Decrypt Later (SNDL)"] --> E&lt;/div>
&lt;p>Il est très dangereux de penser que « l&amp;rsquo;achèvement à grande échelle des ordinateurs quantiques n&amp;rsquo;est pas prévu avant plusieurs décennies, il n&amp;rsquo;y a donc pas de problème ». En effet, la méthode d&amp;rsquo;attaque appelée &lt;strong>Store Now, Decrypt Later (SNDL : Stocker maintenant, déchiffrer plus tard)&lt;/strong> est déjà une menace réelle. Il s&amp;rsquo;agit d&amp;rsquo;une attaque dans laquelle des États malveillants ou des groupes de pirates stockent massivement les données de communication chiffrées actuelles (comme le trafic TLS) sur des supports de stockage, afin de les déchiffrer toutes dès qu&amp;rsquo;un ordinateur quantique puissant sera disponible à l&amp;rsquo;avenir. Les secrets d&amp;rsquo;État, les informations d&amp;rsquo;infrastructure et les données médicales qui doivent être protégées à long terme sont déjà exposés à cette menace.&lt;/p>
&lt;p>De plus, il existe l&amp;rsquo;&lt;strong>algorithme de Grover&lt;/strong>, découvert en 1996, qui s&amp;rsquo;applique à la cryptographie à clé symétrique (comme AES) et aux fonctions de hachage (comme SHA-256). Cet algorithme réduit la complexité de l&amp;rsquo;attaque par force brute à sa racine carrée. En d&amp;rsquo;autres termes, le niveau de sécurité de l&amp;rsquo;AES-128 est effectivement réduit de moitié, pour atteindre 2 à la puissance 64. Par conséquent, à l&amp;rsquo;ère quantique, il est recommandé d&amp;rsquo;utiliser des longueurs de clés et des longueurs de hachage plus grandes, telles que l&amp;rsquo;AES-256 et le SHA-384.&lt;/p>
&lt;p>Pour faire face à cette crise cryptographique sans précédent, une nouvelle &lt;strong>cryptographie post-quantique (Post-Quantum Cryptography : PQC)&lt;/strong> a vu le jour, reposant sur de nouveaux problèmes mathématiques difficiles à déchiffrer même avec des ordinateurs quantiques. Cet article explique de manière très détaillée, sur la base des résultats du processus de standardisation PQC mené par le National Institute of Standards and Technology (NIST) des États-Unis, les principaux algorithmes PQC, depuis leur contexte mathématique jusqu&amp;rsquo;à leurs mécanismes et la comparaison de leurs architectures.&lt;/p>
&lt;hr>
&lt;h2 id="2-aperçu-et-histoire-du-projet-de-standardisation-pqc-par-le-nist">2. Aperçu et histoire du projet de standardisation PQC par le NIST
&lt;/h2>&lt;p>La transition des technologies cryptographiques, qui implique la refonte des protocoles, la mise à jour des systèmes et le remplacement du matériel, prendra des années, voire des décennies. C&amp;rsquo;est pourquoi les cryptographes du monde entier ont commencé très tôt à faire des recherches sur la PQC. Le NIST (National Institute of Standards and Technology) américain a joué un rôle central dans ce domaine. En 2016, le NIST a lancé un appel public pour le processus de standardisation de la PQC et a accepté des propositions de tout nouveaux algorithmes cryptographiques de la part de la communauté cryptographique mondiale.&lt;/p>
&lt;p>Les deux principales catégories ciblées par la standardisation étaient les suivantes :&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Cryptographie à clé publique / Mécanisme d&amp;rsquo;encapsulation de clé (KEM : Key Encapsulation Mechanism)&lt;/strong> : Mécanisme permettant de partager (distribuer) en toute sécurité une clé symétrique pour chiffrer le canal de communication dans des connexions telles que TLS.&lt;/li>
&lt;li>&lt;strong>Signatures numériques (Digital Signatures)&lt;/strong> : Mécanisme permettant de prouver, dans les mises à jour logicielles et les certificats électroniques, que les données n&amp;rsquo;ont pas été altérées et qu&amp;rsquo;il n&amp;rsquo;y a pas d&amp;rsquo;usurpation d&amp;rsquo;identité de l&amp;rsquo;expéditeur (authenticité).&lt;/li>
&lt;/ol>
&lt;p>Après environ six années de concurrence acharnée en matière d&amp;rsquo;évaluation, d&amp;rsquo;analyse et de cryptanalyse (Round 1 à Round 3), une évaluation supplémentaire (Round 4) a été menée pour certains algorithmes. En conséquence, les algorithmes suivants ont été officiellement publiés en tant que Federal Information Processing Standards (FIPS) en 2024, s&amp;rsquo;établissant comme les futures normes mondiales.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>FIPS 203 (ML-KEM)&lt;/strong> : KEM basé sur CRYSTALS-Kyber&lt;/li>
&lt;li>&lt;strong>FIPS 204 (ML-DSA)&lt;/strong> : Signature numérique basée sur CRYSTALS-Dilithium&lt;/li>
&lt;li>&lt;strong>FIPS 205 (SLH-DSA)&lt;/strong> : Signature basée sur le hachage sans état (stateless) reposant sur SPHINCS+&lt;/li>
&lt;li>&lt;strong>(À formuler ultérieurement) FN-DSA&lt;/strong> : Signature numérique basée sur FALCON&lt;/li>
&lt;/ul>
&lt;p>Ces algorithmes sélectionnés reposent chacun sur des « problèmes de difficulté » mathématiques différents. Ainsi, si une vulnérabilité fatale venait à être découverte dans l&amp;rsquo;un des algorithmes à l&amp;rsquo;avenir, la diversité (Crypto Agility) est assurée pour éviter que l&amp;rsquo;ensemble du système ne s&amp;rsquo;effondre. Dans le processus de standardisation, la cryptographie basée sur les réseaux (Lattice-based cryptography) a joué le rôle principal en raison de ses performances, mais la cryptographie basée sur le hachage et la cryptographie basée sur les codes ont été adoptées comme de solides solutions de secours.&lt;/p>
&lt;hr>
&lt;h2 id="3-classification-des-principales-approches-mathématiques-de-la-pqc">3. Classification des principales approches mathématiques de la PQC
&lt;/h2>&lt;p>Les algorithmes PQC sont principalement classés en cinq catégories en fonction des problèmes mathématiques qui sous-tendent leur sécurité. Dans cet article, nous approfondirons particulièrement les trois premiers.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Cryptographie basée sur les réseaux (Lattice-based Cryptography)&lt;/strong> :
Elle repose sur le problème du vecteur le plus court (SVP) et le problème du vecteur le plus proche (CVP) dans un espace de réseau multidimensionnel, ainsi que sur le problème LWE qui en dérive. Elle est au cœur de la standardisation du NIST, et Kyber, Dilithium et FALCON en font partie. Elle offre le meilleur équilibre entre la vitesse de traitement, la taille de la clé publique et la taille du texte chiffré, ce qui la rend adaptée à une utilisation polyvalente.&lt;/li>
&lt;li>&lt;strong>Cryptographie basée sur le hachage (Hash-based Cryptography)&lt;/strong> :
Elle fonde sa sécurité uniquement sur la « résistance aux collisions » et la « propriété unidirectionnelle » des fonctions de hachage cryptographique (telles que SHA-2 et SHAKE). Bien qu&amp;rsquo;elle ne soit applicable qu&amp;rsquo;aux signatures numériques (comme SPHINCS+), ses preuves de sécurité sont les plus robustes et elle se caractérise par une résistance extrêmement élevée aux attaques mathématiques inconnues.&lt;/li>
&lt;li>&lt;strong>Cryptographie basée sur les codes (Code-based Cryptography)&lt;/strong> :
Basée sur la théorie des codes correcteurs d&amp;rsquo;erreurs, elle dépend de la difficulté du problème du décodage de syndrome (Syndrome Decoding Problem). Le Classic McEliece, proposé dans les années 1970, en est représentatif et possède une très longue histoire et une sécurité éprouvée, bien que la taille de la clé publique soit extrêmement importante (de l&amp;rsquo;ordre du mégaoctet).&lt;/li>
&lt;li>&lt;strong>Cryptographie polynomiale multivariée (Multivariate Polynomial Cryptography)&lt;/strong> :
Elle repose sur la difficulté de résoudre des systèmes d&amp;rsquo;équations quadratiques à plusieurs variables sur un corps fini (problème MQ). Principalement proposée pour les signatures numériques (comme Rainbow), une méthode d&amp;rsquo;attaque puissante permettant de la déchiffrer en quelques jours sur un simple PC a été découverte lors du dernier round du NIST, entraînant l&amp;rsquo;élimination de nombreux algorithmes de la standardisation.&lt;/li>
&lt;li>&lt;strong>Cryptographie basée sur les isogénies (Isogeny-based Cryptography)&lt;/strong> :
Elle repose sur le problème de recherche de chemin sur des graphes d&amp;rsquo;isogénies de courbes elliptiques. Avec des tailles de clé très petites, elle était attendue comme le successeur légitime de l&amp;rsquo;ECC, mais « SIKE », le candidat final, a été complètement déchiffré en seulement quelques heures sur un PC normal en 2022 à l&amp;rsquo;aide de mathématiques classiques (comme l&amp;rsquo;attaque de Castryck-Decru), symbolisant la fin dramatique, ainsi que la difficulté et le danger liés à la conception de la PQC.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="4-les-abysses-de-la-cryptographie-sur-les-réseaux--les-bases-mathématiques-du-problème-lwe-et-du-module-lwe">4. Les abysses de la cryptographie sur les réseaux : Les bases mathématiques du problème LWE et du Module-LWE
&lt;/h2>&lt;p>Considérée aujourd&amp;rsquo;hui comme la plus prometteuse et devenue le centre de la standardisation, voici la &lt;strong>cryptographie basée sur les réseaux (Lattice cryptography)&lt;/strong>. À la base de sa sécurité se trouve le &lt;strong>problème LWE (Learning with Errors : Apprentissage avec erreurs)&lt;/strong>. Proposé par Oded Regev en 2005, cette réalisation historique lui a valu le prix Gödel. Il est impossible de parler de la PQC moderne sans comprendre le problème LWE.&lt;/p>
&lt;h3 id="41-quest-ce-que-le-problème-lwe-learning-with-errors-">4.1. Qu&amp;rsquo;est-ce que le problème LWE (Learning with Errors) ?
&lt;/h3>&lt;p>Considérons tout d&amp;rsquo;abord un simple système d&amp;rsquo;équations linéaires. Sous un certain module $q$ (modulo $q$), supposons que nous ayons une matrice aléatoire connue $A$, un vecteur secret inconnu $\vec{s}$, et que leur produit $\vec{b}$ soit donné.&lt;/p>
$$ \vec{b} = A\vec{s} \pmod q $$
&lt;p>Dans ce cas, il est facile de trouver le vecteur inconnu $\vec{s}$ à partir des informations publiques $A$ et $\vec{b}$. En utilisant un algorithme classique comme « l&amp;rsquo;élimination de Gauss (ou pivot de Gauss) », on peut facilement calculer $\vec{s}$ en temps polynomial.&lt;/p>
&lt;p>Cependant, si l&amp;rsquo;on ajoute à cette équation une « petite erreur intentionnelle (bruit) », le niveau de difficulté du problème augmente considérablement. C&amp;rsquo;est ce qu&amp;rsquo;on appelle le &lt;strong>problème LWE&lt;/strong>.&lt;/p>
&lt;p>On prépare un vecteur secret inconnu $\vec{s} \in \mathbb{Z}_q^n$ et une matrice choisie au hasard $A \in \mathbb{Z}_q^{m \times n}$. De plus, un vecteur d&amp;rsquo;erreur $\vec{e} \in \mathbb{Z}_q^m$ dont « la valeur des éléments est suffisamment petite » est choisi selon une distribution normale ou binomiale, et $\vec{b}$ est calculé comme suit.&lt;/p>
$$ \vec{b} = A\vec{s} + \vec{e} \pmod q $$
&lt;p>Le &lt;strong>problème Search LWE (LWE de recherche)&lt;/strong> consiste à « trouver l&amp;rsquo;information secrète $\vec{s}$ à partir des informations publiques $(A, \vec{b})$ ». En raison de la présence de cette erreur $\vec{e}$, toute tentative d&amp;rsquo;utiliser des méthodes de résolution algébriques telles que l&amp;rsquo;élimination de Gauss fera que l&amp;rsquo;erreur $\vec{e}$ s&amp;rsquo;amplifiera de manière exponentielle lors de l&amp;rsquo;addition et de la soustraction des équations, devenant finalement indiscernable d&amp;rsquo;une valeur aléatoire et conduisant à un échec.&lt;/p>
&lt;p>La puissance du problème LWE réside dans le fait qu&amp;rsquo;il existe une forte preuve théorique (réduction) affirmant que le problème LWE ne peut pas non plus être résolu en moyenne (Average-case), à moins qu&amp;rsquo;il n&amp;rsquo;existe un algorithme quantique capable de résoudre le problème du plus court vecteur de décision (GapSVP) ou le problème des vecteurs indépendants les plus courts (SIVP), qui sont des problèmes de « complexité dans le pire des cas (Worst-case hardness) » sur les réseaux. En d&amp;rsquo;autres termes, même pour des clés de chiffrement générées aléatoirement, une sécurité robuste, soutenue par des limites théoriques, est garantie.&lt;/p>
&lt;h3 id="42-amélioration-drastique-de-lefficacité-grâce-à-ring-lwe-et-module-lwe">4.2. Amélioration drastique de l&amp;rsquo;efficacité grâce à Ring-LWE et Module-LWE
&lt;/h3>&lt;p>Le problème LWE normal (Standard LWE) a une base de sécurité très claire, mais n&amp;rsquo;est pas pratique car la taille de la matrice $A$ devient très grande et les tailles de clés atteignent le niveau du mégaoctet. L&amp;rsquo;approche proposée a donc été d&amp;rsquo;utiliser des anneaux de polynômes (Polynomial Rings) pour lui donner une structure algébrique.&lt;/p>
&lt;p>Dans le &lt;strong>problème Ring-LWE&lt;/strong>, on utilise des éléments (polynômes) d&amp;rsquo;un certain anneau de polynômes $R_q$ au lieu de simples vecteurs et matrices. Dans la norme NIST, l&amp;rsquo;anneau de polynômes cyclotomiques suivant est généralement utilisé.&lt;/p>
$$ R_q = \mathbb{Z}_q[X]/(X^n + 1) $$
&lt;p>Ici, $n$ est une puissance de 2 (par exemple 256) et $q$ est un nombre premier approprié. Sur cet anneau, on calcule $b = a \cdot s + e \pmod q$ en utilisant les éléments $a, s, e \in R_q$. Comme un seul polynôme $a$ possède $n$ coefficients, les données peuvent être considérablement compressées. De plus, l&amp;rsquo;utilisation d&amp;rsquo;une version de transformée de Fourier rapide (FFT) sur corps fini, appelée &lt;strong>NTT (Number Theoretic Transform : Transformée de la théorie des nombres)&lt;/strong>, permet une multiplication de polynômes ultra-rapide avec une complexité de calcul de $O(n \log n)$.&lt;/p>
&lt;p>Cependant, il y avait des inquiétudes concernant le Ring-LWE quant à « l&amp;rsquo;existence possible de vulnérabilités inconnues dues à la structure algébrique spécifique de l&amp;rsquo;anneau ». Il y avait également le défi d&amp;rsquo;ingénierie selon lequel, lors de la modification du niveau de sécurité (par exemple, équivalent à AES-128, 192, 256), il fallait modifier le degré $n$ du polynôme lui-même, ce qui nécessitait de réécrire l&amp;rsquo;ensemble de l&amp;rsquo;implémentation, y compris l&amp;rsquo;algorithme NTT.&lt;/p>
&lt;p>C&amp;rsquo;est pourquoi les algorithmes standardisés Kyber et Dilithium ont adopté le &lt;strong>problème Module-LWE (M-LWE)&lt;/strong>. Le Module-LWE est un compromis situé exactement entre le Standard LWE sans structure et le Ring-LWE qui possède trop de structure, en utilisant une matrice de taille $k \times k$ (module) dont les composants sont les éléments de l&amp;rsquo;anneau de polynômes $R_q$.&lt;/p>
$$ \vec{b} = A\vec{s} + \vec{e} \pmod{R_q} \quad (A \in R_q^{k \times k}, \vec{s}, \vec{e} \in R_q^k) $$
&lt;p>Le plus grand avantage du Module-LWE est qu&amp;rsquo;il permet de faire évoluer facilement le niveau de sécurité en modifiant simplement la dimension $k$ de la matrice, tout en gardant fixe le degré $n$ du polynôme (dans la norme NIST, $n=256$).
Par exemple, pour Kyber, la dimension $k$ est ajustée de la manière suivante :&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Kyber512 (Niveau 1)&lt;/strong> : $k = 2$ (équivalent AES-128)&lt;/li>
&lt;li>&lt;strong>Kyber768 (Niveau 3)&lt;/strong> : $k = 3$ (équivalent AES-192)&lt;/li>
&lt;li>&lt;strong>Kyber1024 (Niveau 5)&lt;/strong> : $k = 4$ (équivalent AES-256)&lt;/li>
&lt;/ul>
&lt;p>Cela a permis de réutiliser à 100 % le code NTT sous-jacent et le circuit matériel des opérations polynomiales pour tous les niveaux de sécurité, ce qui a permis d&amp;rsquo;améliorer considérablement la sécurité et l&amp;rsquo;efficacité de l&amp;rsquo;implémentation.&lt;/p>
&lt;hr>
&lt;h2 id="5-crystals-kyber-ml-kem--le-mécanisme-dencapsulation-de-clé-de-nouvelle-génération">5. CRYSTALS-Kyber (ML-KEM) : Le mécanisme d&amp;rsquo;encapsulation de clé de nouvelle génération
&lt;/h2>&lt;p>Officiellement standardisé sous le nom de &lt;strong>FIPS 203 (ML-KEM)&lt;/strong>, CRYSTALS-Kyber est un mécanisme d&amp;rsquo;encapsulation de clé (KEM) basé sur le problème Module-LWE susmentionné. Il s&amp;rsquo;agira de la norme mondiale de facto pour le partage sécurisé des clés de session à l&amp;rsquo;avenir, notamment pour TLS 1.3 et SSH.&lt;/p>
&lt;h3 id="51-architecture-du-kem-key-encapsulation-mechanism">5.1. Architecture du KEM (Key Encapsulation Mechanism)
&lt;/h3>&lt;p>À l&amp;rsquo;ère de la PQC, l&amp;rsquo;approche directe telle que RSA où « le client crée une clé partagée, la chiffre avec la clé publique du serveur et l&amp;rsquo;envoie » est remplacée par le cadre d&amp;rsquo;encapsulation appelé KEM.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant Client as "Client (Alice)"
participant Server as "Serveur (Bob)"
Note over Client: "ML-KEM KeyGen()"
Client->>Client: "Générer la clé secrète (sk) et la clé publique (pk)"
Client->>Server: "Envoyer la clé publique (pk)"
Note over Server: "ML-KEM Encaps()"
Server->>Server: "Générer une clé partagée aléatoire (K)"
Server->>Server: "Encapsuler K avec pk pour créer le texte chiffré (c)"
Server->>Client: "Envoyer le texte chiffré (c)"
Note over Client: "ML-KEM Decaps()"
Client->>Client: "Déchiffrer le texte chiffré (c) à l'aide de la clé secrète (sk)"
Client->>Client: "Désencapsuler et extraire la clé partagée (K)"
Note over Client, Server: "Commencer la communication chiffrée (par ex. AES) avec la clé partagée (K)"&lt;/div>
&lt;h3 id="52-fonctionnement-interne-de-kyber-et-transformation-de-fujisaki-okamoto">5.2. Fonctionnement interne de Kyber et Transformation de Fujisaki-Okamoto
&lt;/h3>&lt;p>La conception de Kyber est extrêmement raffinée. Tout d&amp;rsquo;abord, un schéma de chiffrement à clé publique (Kyber.CPAPKE), sûr uniquement contre les attaques à texte clair choisi (CPA), est construit, puis une technique cryptographique très puissante appelée &lt;strong>Transformation de Fujisaki-Okamoto (Fujisaki-Okamoto Transform)&lt;/strong> est appliquée, ce qui permet de le faire évoluer vers un KEM complet et sûr contre les attaques à chiffré choisi adaptatif (CCA).&lt;/p>
&lt;p>Le mécanisme de chiffrement et de déchiffrement au cœur de CPAPKE est le suivant :&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Génération de clé (Key Generation)&lt;/strong> :&lt;/p>
&lt;ul>
&lt;li>À partir d&amp;rsquo;une valeur de graine aléatoire (seed), générer une matrice $A \in R_q^{k \times k}$ sur le domaine NTT. Le modulo $q$ utilisé est $3329$.&lt;/li>
&lt;li>Échantillonner un vecteur secret $\vec{s}$ et un vecteur d&amp;rsquo;erreur $\vec{e}$ avec de petits coefficients à partir d&amp;rsquo;une distribution binomiale centrée (CBD).&lt;/li>
&lt;li>Calculer $\vec{t} = A\vec{s} + \vec{e}$. La clé publique est $(A, \vec{t})$ et la clé secrète est $\vec{s}$. (En pratique, $A$ est publiée en tant que valeur de graine (seed) pour économiser de la bande passante).&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Chiffrement (Encryption)&lt;/strong> :&lt;/p>
&lt;ul>
&lt;li>Encoder le message de 32 octets (matériau de la clé partagée) $m$ que l&amp;rsquo;on souhaite partager en un polynôme.&lt;/li>
&lt;li>Générer un nouveau vecteur aléatoire $\vec{r}$ et de petites erreurs $\vec{e_1}, e_2$.&lt;/li>
&lt;li>$\vec{u} = A^T\vec{r} + \vec{e_1}$&lt;/li>
&lt;li>$v = \vec{t}^T\vec{r} + e_2 + \lfloor q/2 \rceil \cdot m$&lt;/li>
&lt;li>Le texte chiffré est $(\vec{u}, v)$.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Déchiffrement (Decryption)&lt;/strong> :&lt;/p>
&lt;ul>
&lt;li>Le destinataire calcule $v - \vec{s}^T\vec{u}$.&lt;/li>
&lt;li>Le développement de cette équation donne ce qui suit.
$v - \vec{s}^T\vec{u} = (\vec{t}^T\vec{r} + e_2 + \lfloor q/2 \rceil \cdot m) - \vec{s}^T(A^T\vec{r} + \vec{e_1})$&lt;/li>
&lt;li>En remplaçant $\vec{t} = A\vec{s} + \vec{e}$, le terme principal $\vec{s}^TA^T\vec{r}$ s&amp;rsquo;annule.&lt;/li>
&lt;li>Il reste $\lfloor q/2 \rceil \cdot m + (\vec{e}^T\vec{r} + e_2 - \vec{s}^T\vec{e_1})$.&lt;/li>
&lt;li>Les termes entre parenthèses étant des « produits ou sommes de petites erreurs », l&amp;rsquo;ensemble reste une valeur (bruit) suffisamment petite. Par conséquent, en déterminant si chaque coefficient est proche de $0$ ou de $q/2$, les bits (0 ou 1) du message d&amp;rsquo;origine $m$ peuvent être parfaitement restaurés sans aucune erreur.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>La plus grande force de Kyber réside dans sa &lt;strong>vitesse de traitement&lt;/strong> impressionnante et sa &lt;strong>taille de clé modérée&lt;/strong>. Pour Kyber768, la taille de la clé publique est de 1 184 octets et la taille du texte chiffré est de 1 088 octets. Bien qu&amp;rsquo;elles soient plus importantes par rapport à RSA-3072 (taille de clé d&amp;rsquo;environ 384 octets), il est possible de les faire tenir dans l&amp;rsquo;unité de transmission maximale (MTU) des communications Internet modernes sans fragmentation des paquets, ce qui n&amp;rsquo;a presque aucun impact négatif sur la latence du réseau.&lt;/p>
&lt;hr>
&lt;h2 id="6-crystals-dilithium-ml-dsa--signature-numérique-polyvalente-basée-sur-les-réseaux">6. CRYSTALS-Dilithium (ML-DSA) : Signature numérique polyvalente basée sur les réseaux
&lt;/h2>&lt;p>Dans la standardisation des signatures numériques, des algorithmes avec différentes philosophies de conception ont concouru au sein de la même approche de la cryptographie sur les réseaux. Parmi eux, &lt;strong>CRYSTALS-Dilithium&lt;/strong> a été sélectionné comme signature numérique polyvalente sous le nom de &lt;strong>FIPS 204 (ML-DSA)&lt;/strong>.&lt;/p>
&lt;h3 id="61-le-paradigme-fiat-shamir-with-aborts">6.1. Le paradigme Fiat-Shamir with Aborts
&lt;/h3>&lt;p>Comme Kyber, Dilithium est un schéma de signature numérique basé sur le problème Module-LWE (ainsi que sur le problème Module-SIS). À la base de sa conception, le paradigme extrêmement important appelé « &lt;strong>Fiat-Shamir with Aborts (Transformation de Fiat-Shamir avec rejets)&lt;/strong> » est utilisé.&lt;/p>
&lt;p>La transformation de Fiat-Shamir elle-même est une méthode standard pour convertir un protocole interactif de preuve à divulgation nulle (zero-knowledge proof) en une signature numérique non interactive. Le prouveur (signataire) génère un engagement (commitment) $y$, calcule $w = Ay$ et le passe par une fonction de hachage pour obtenir un défi aléatoire $c$, puis calcule la réponse $z = y + cs$.&lt;/p>
&lt;p>Cependant, dans la cryptographie sur les réseaux, l&amp;rsquo;application naïve de cette méthode entraînait un problème fatal (fuite mathématique de type canal auxiliaire) où la distribution de la réponse $z$ devenait asymétrique en fonction de la valeur de la clé secrète $s$, et un attaquant observant de nombreuses signatures obtiendrait peu à peu des informations sur la clé secrète $s$.&lt;/p>
&lt;p>L&amp;rsquo;équipe de conception de Dilithium (Lyubashevsky et al.) a introduit une technique appelée « &lt;strong>Échantillonnage par rejet (Rejection Sampling)&lt;/strong> » : si les coefficients du résultat de la signature $z$ ne tombent pas dans une plage de seuil de sécurité prédéfinie, l&amp;rsquo;ensemble du processus de signature est abandonné (Abort) et le calcul est recommencé depuis le début en utilisant un nouveau nombre aléatoire $y$.&lt;/p>
&lt;p>Grâce à cela, la signature finale produite $z$ est une distribution complètement uniforme qui ne dépend en aucun cas de la clé secrète, réussissant à prévenir complètement la fuite d&amp;rsquo;informations sur le plan mathématique.&lt;/p>
&lt;h3 id="62-les-avantages-de-dilithium-et-la-facilité-de-son-implémentation">6.2. Les avantages de Dilithium et la facilité de son implémentation
&lt;/h3>&lt;p>Le grand avantage de la conception de Dilithium est qu&amp;rsquo;elle n&amp;rsquo;utilise &lt;strong>absolument pas&lt;/strong> d&amp;rsquo;« échantillonnage complexe à partir de distributions gaussiennes » ou d&amp;rsquo;« opérations en virgule flottante » dans le processus de génération de signature. Puisqu&amp;rsquo;il peut être mis en œuvre uniquement avec un échantillonnage à partir d&amp;rsquo;une distribution uniforme, des opérations simples en modulo entier, des NTT et des fonctions de hachage (SHAKE), il est facile de l&amp;rsquo;implémenter de manière sécurisée et en temps constant (Constant-time) dans un large éventail d&amp;rsquo;environnements, allant des microcontrôleurs embarqués aux serveurs cloud. De ce fait, il possède également une forte résistance contre les attaques physiques par canal auxiliaire, telles que les attaques par chronométrage (timing attacks).&lt;/p>
&lt;hr>
&lt;h2 id="7-falcon-fn-dsa--signature-sur-réseaux-ultra-compacte">7. FALCON (FN-DSA) : Signature sur réseaux ultra-compacte
&lt;/h2>&lt;p>Le NIST a sélectionné &lt;strong>FALCON (Fast-Fourier Lattice-based Compact Signatures over NTRU)&lt;/strong> comme autre candidat standard de signature basée sur les réseaux, avec des caractéristiques différentes de celles de Dilithium (actuellement en cours de rédaction en tant que FN-DSA).&lt;/p>
&lt;h3 id="71-réseaux-ntru-et-échantillonnage-gaussien">7.1. Réseaux NTRU et échantillonnage gaussien
&lt;/h3>&lt;p>La plus grande caractéristique de FALCON est qu&amp;rsquo;il n&amp;rsquo;utilise pas le problème LWE, mais plutôt le &lt;strong>réseau NTRU (N-th degree Truncated polynomial Ring Units)&lt;/strong>, très ancien et existant depuis 1996. De plus, il adopte le paradigme « &lt;strong>Hash-and-Sign (Hachage et Signature)&lt;/strong> » basé sur le framework GPV (Gentry-Peikert-Vaikuntanathan).&lt;/p>
&lt;p>Dans Hash-and-Sign, la valeur de hachage du message est utilisée comme point cible dans l&amp;rsquo;espace, et le point sur le réseau le plus proche de ce point (une solution approchée du problème du vecteur le plus proche) est trouvé pour servir de signature. Pour cela, il est nécessaire d&amp;rsquo;échantillonner des points selon une distribution gaussienne discrète en utilisant une « base courte de bonne qualité » qui est la clé secrète.&lt;/p>
&lt;p>FALCON a considérablement accéléré ce calcul intensif en utilisant une technique appelée « &lt;strong>Orthogonalisation de Fourier rapide (Fast Fourier Orthogonalization : FFO)&lt;/strong> ».&lt;/p>
&lt;h3 id="72-avantages-et-inconvénients-de-falcon">7.2. Avantages et inconvénients de FALCON
&lt;/h3>&lt;p>L&amp;rsquo;avantage écrasant de FALCON réside dans le fait que &lt;strong>la taille de sa signature et la taille de sa clé publique sont extrêmement petites (compactes)&lt;/strong>. Alors que la taille de la signature de Dilithium3 est d&amp;rsquo;environ 3 309 octets, celle de FALCON-512 n&amp;rsquo;est que d&amp;rsquo;environ 666 octets. La clé publique est également très petite, avec 897 octets, ce qui en fait un sauveur dans les environnements où la bande passante de communication est extrêmement limitée, pour les appareils IoT et dans certains protocoles réseau.&lt;/p>
&lt;p>Cependant, il existe un inconvénient majeur. Puisque l&amp;rsquo;échantillonnage gaussien discret impliquant des &lt;strong>opérations complexes en virgule flottante (64-bit IEEE 754)&lt;/strong> est indispensable lors de la génération de la signature, l&amp;rsquo;implémentation en temps constant (Constant-time implementation) pour prévenir les fuites de temps est extrêmement difficile, et le code devient énorme. C&amp;rsquo;est pourquoi FALCON est positionné comme un puissant algorithme spécialisé pour des usages spécifiques, par opposition à l&amp;rsquo;utilisation polyvalente (Dilithium).&lt;/p>
&lt;div class="mermaid">graph LR
A["Exigences en matière de signatures numériques"] --> B{"Quelle est la contrainte prioritaire ?"}
B -->|"Simplicité d'implémentation, polyvalence, facilité d'implémentation en temps constant"| C["Dilithium (ML-DSA)"]
B -->|"Minimisation de la bande passante de communication, compacité de la taille des données"| D["FALCON (FN-DSA)"]
C --> E["Certificats TLS génériques, signature électronique de logiciels"]
D --> F["Protocoles avec des limites strictes de taille de paquet, environnements spéciaux"]&lt;/div>
&lt;hr>
&lt;h2 id="8-sphincs-slh-dsa--signature-basée-sur-le-hachage-offrant-la-plus-forte-sécurité">8. SPHINCS+ (SLH-DSA) : Signature basée sur le hachage offrant la plus forte sécurité
&lt;/h2>&lt;p>Pour se préparer au pire des scénarios (le cas échéant) où la sécurité de la cryptographie sur les réseaux serait brisée à l&amp;rsquo;avenir par une percée d&amp;rsquo;un brillant mathématicien, le NIST a formulé &lt;strong>FIPS 205 (SLH-DSA)&lt;/strong>, c&amp;rsquo;est-à-dire &lt;strong>SPHINCS+&lt;/strong>, en tant que norme basée sur une approche complètement différente de celle de la cryptographie sur les réseaux.&lt;/p>
&lt;p>SPHINCS+ est classé comme une &lt;strong>signature basée sur le hachage&lt;/strong>. Sa sécurité repose uniquement sur un seul point : « la fonction de hachage cryptographique utilisée (comme SHA-2 ou SHAKE256) possède une résistance aux collisions et une propriété unidirectionnelle ». Contrairement au LWE ou à la factorisation, qui dépendent de problèmes mathématiques possédant des structures algébriques spécifiques, SPHINCS+ peut faire face à n&amp;rsquo;importe quel algorithme quantique puissant qui pourrait apparaître à l&amp;rsquo;avenir, simplement en allongeant la longueur de sortie de la fonction de hachage. Il s&amp;rsquo;enorgueillit ainsi d&amp;rsquo;une sécurité extrêmement robuste (la sécurité la plus conservatrice).&lt;/p>
&lt;h3 id="81-architecture-sans-état-stateless-avec-wots-et-fors">8.1. Architecture sans état (stateless) avec WOTS+ et FORS
&lt;/h3>&lt;p>L&amp;rsquo;histoire des signatures basées sur le hachage est ancienne et remonte aux signatures Lamport et aux signatures à usage unique (One-Time Signatures) Winternitz (WOTS) des années 1970. Il s&amp;rsquo;agissait de clés jetables où « l&amp;rsquo;on ne peut signer en toute sécurité qu&amp;rsquo;une seule fois ». Afin de pouvoir les utiliser plusieurs fois, des algorithmes tels que XMSS (eXtended Merkle Signature Scheme) et LMS ont été développés en combinant des arbres de Merkle pour gérer d&amp;rsquo;innombrables clés à usage unique avec un seul hachage racine.&lt;/p>
&lt;p>Cependant, XMSS et LMS présentaient un défaut majeur : ils étaient « &lt;strong>avec état (stateful)&lt;/strong> ». Chaque fois qu&amp;rsquo;une signature était effectuée, il était nécessaire de conserver un enregistrement strict de l&amp;rsquo;état de l&amp;rsquo;index « quelle clé à usage unique a été utilisée » dans une mémoire non volatile. Si l&amp;rsquo;état était restauré (par exemple, par la restauration d&amp;rsquo;un snapshot de machine virtuelle) et que la même clé à usage unique était utilisée deux fois, la clé secrète serait immédiatement divulguée et le système s&amp;rsquo;effondrerait.&lt;/p>
&lt;p>SPHINCS+ est une signature basée sur le hachage « &lt;strong>sans état (stateless)&lt;/strong> » qui a résolu les tracas liés à la gestion des états.
Sa technologie de base est la combinaison suivante :&lt;/p>
&lt;ol>
&lt;li>&lt;strong>WOTS+ (Winternitz One-Time Signature Plus)&lt;/strong> : Signature à usage unique de base.&lt;/li>
&lt;li>&lt;strong>FORS (Forest of Random Subsets)&lt;/strong> : Technologie de signature à faible fréquence d&amp;rsquo;utilisation (Few-Time Signature). La sécurité est maintenue même si la même clé est réutilisée un petit nombre de fois.&lt;/li>
&lt;li>&lt;strong>Hyper-Tree (Structure arborescente géante)&lt;/strong> : Structure géante composée de plusieurs couches d&amp;rsquo;arbres de Merkle empilées.&lt;/li>
&lt;/ol>
&lt;p>Dans SPHINCS+, lors de la signature, au lieu de gérer des états, une clé FORS est sélectionnée de manière aléatoire parmi un nombre colossal de clés au bas de l&amp;rsquo;Hyper-Tree à l&amp;rsquo;aide d&amp;rsquo;un nombre pseudo-aléatoire pour effectuer la signature. Étant donné que le nombre de feuilles de l&amp;rsquo;arbre est astronomique, la probabilité de sélectionner la même clé deux fois par accident (collision) est si faible qu&amp;rsquo;elle peut être ignorée, ce qui permet d&amp;rsquo;atteindre l&amp;rsquo;absence d&amp;rsquo;état (stateless).&lt;/p>
&lt;p>La seule et plus grande faiblesse de SPHINCS+ est que &lt;strong>la taille de sa signature est extrêmement grande&lt;/strong>. Selon les paramètres, la taille de la signature peut atteindre 17 kilo-octets à 49 kilo-octets, et la vitesse de génération des signatures est également très lente par rapport à la cryptographie sur les réseaux. Par conséquent, il est prévu de l&amp;rsquo;utiliser dans des applications nécessitant une sécurité absolue à long terme et où les signatures ne sont pas effectuées fréquemment, telles que les signatures de mise à jour logicielle et les certificats d&amp;rsquo;Autorité de Certification (CA) racine, plutôt que pour la navigation Web quotidienne.&lt;/p>
&lt;hr>
&lt;h2 id="9-cryptographie-basée-sur-les-codes--classic-mceliece-le-bon-vieux-géant">9. Cryptographie basée sur les codes : Classic McEliece, le bon vieux géant
&lt;/h2>&lt;p>Dans le processus de standardisation du NIST, &lt;strong>Classic McEliece&lt;/strong>, de la &lt;strong>cryptographie basée sur les codes&lt;/strong>, est une approche importante dont l&amp;rsquo;évaluation se poursuit toujours en tant que candidat final de la phase 4.&lt;/p>
&lt;p>Proposé par Robert McEliece en 1978, cet algorithme est l&amp;rsquo;un des plus anciens de l&amp;rsquo;histoire de la cryptographie à clé publique, aux côtés du RSA. Il utilise des codes de géométrie algébrique appelés « codes de Goppa », qui ajoutent intentionnellement une erreur (vecteur de bruit) au message lors du chiffrement. Seule la personne possédant la matrice de contrôle de parité du code de Goppa comme clé secrète peut utiliser sa puissante capacité de correction d&amp;rsquo;erreurs pour supprimer l&amp;rsquo;erreur et déchiffrer le message d&amp;rsquo;origine, un principe basé sur le « &lt;strong>problème du décodage de syndrome (Syndrome Decoding Problem)&lt;/strong> ».&lt;/p>
$$ \vec{c} = \vec{m} G + \vec{e} $$
&lt;p>
（$G$ est la matrice génératrice brouillée qui est la clé publique, et $\vec{e}$ est le vecteur d&amp;rsquo;erreur de poids $t$）&lt;/p>
&lt;p>Ce qui est surprenant avec Classic McEliece, c&amp;rsquo;est son bilan impressionnant : &lt;strong>bien que plus de 40 ans se soient écoulés depuis sa proposition et qu&amp;rsquo;il ait fait l&amp;rsquo;objet d&amp;rsquo;intenses recherches de déchiffrement par des cryptographes du monde entier, aucune vulnérabilité intrinsèque n&amp;rsquo;y a jamais été découverte&lt;/strong>. Il possède la « sécurité éprouvée par le temps » la plus solide de toute la PQC.&lt;/p>
&lt;p>De plus, il a l&amp;rsquo;avantage d&amp;rsquo;avoir une taille de texte chiffré très petite (seulement 100 à 200 octets). Cependant, il présente un défaut majeur : &lt;strong>la taille de la clé publique est en mégaoctets (Mo)&lt;/strong>. Même pour le niveau de sécurité le plus bas (équivalent à AES-128), la clé publique est d&amp;rsquo;environ 250 Ko, et elle dépasse 1 Mo pour des niveaux plus élevés.&lt;/p>
&lt;p>Pour cette raison, il est totalement inadapté aux applications qui envoient des clés publiques sur le réseau à chaque communication, telles que les poignées de main TLS. Cependant, pour des cas d&amp;rsquo;utilisation spécifiques où la clé publique peut être placée à l&amp;rsquo;avance dans le système, comme l&amp;rsquo;échange de clés pré-partagées pour les VPN, le codage en dur de clés publiques dans le firmware ou la communication par satellite, il continue d&amp;rsquo;être considéré comme une option très prometteuse en raison de sa forte sécurité.&lt;/p>
&lt;hr>
&lt;h2 id="10-comparaison-des-performances-et-compromis-de-chaque-algorithme-pqc">10. Comparaison des performances et compromis de chaque algorithme PQC
&lt;/h2>&lt;p>Le tableau suivant résume les caractéristiques de performance des principaux algorithmes abordés jusqu&amp;rsquo;à présent à des niveaux de sécurité courants (équivalents aux niveaux 2 à 3 du NIST, soit le niveau AES-128 à 192).&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Algorithme (Nom standard)&lt;/th>
&lt;th style="text-align:left">Catégorie&lt;/th>
&lt;th style="text-align:left">Base mathématique&lt;/th>
&lt;th style="text-align:left">Taille de la clé publique&lt;/th>
&lt;th style="text-align:left">Taille de la clé secrète&lt;/th>
&lt;th style="text-align:left">Taille du chiffré/signature&lt;/th>
&lt;th style="text-align:left">Tendance de la vitesse de traitement&lt;/th>
&lt;th style="text-align:left">Principales caractéristiques et utilisations&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Kyber768&lt;/strong>&lt;br>(ML-KEM)&lt;/td>
&lt;td style="text-align:left">KEM&lt;/td>
&lt;td style="text-align:left">Module-LWE&lt;/td>
&lt;td style="text-align:left">1 184 octets&lt;/td>
&lt;td style="text-align:left">2 400 octets&lt;/td>
&lt;td style="text-align:left">1 088 octets&lt;/td>
&lt;td style="text-align:left">Très rapide&lt;/td>
&lt;td style="text-align:left">Meilleur équilibre entre taille de clé et vitesse. Norme KEM générique comme TLS 1.3.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Dilithium3&lt;/strong>&lt;br>(ML-DSA)&lt;/td>
&lt;td style="text-align:left">Signature&lt;/td>
&lt;td style="text-align:left">Module-LWE&lt;/td>
&lt;td style="text-align:left">1 952 octets&lt;/td>
&lt;td style="text-align:left">4 032 octets&lt;/td>
&lt;td style="text-align:left">3 309 octets&lt;/td>
&lt;td style="text-align:left">Génération et vérification rapides&lt;/td>
&lt;td style="text-align:left">Implémentation simple. Norme de signature numérique polyvalente.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>FALCON-512&lt;/strong>&lt;br>(FN-DSA)&lt;/td>
&lt;td style="text-align:left">Signature&lt;/td>
&lt;td style="text-align:left">Réseaux NTRU&lt;/td>
&lt;td style="text-align:left">897 octets&lt;/td>
&lt;td style="text-align:left">1 281 octets&lt;/td>
&lt;td style="text-align:left">666 octets&lt;/td>
&lt;td style="text-align:left">Génération plus lente, vérification ultra-rapide&lt;/td>
&lt;td style="text-align:left">Taille de signature minime. Nécessite des opérations en virgule flottante. Pour IoT/embarqué.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>SPHINCS+&lt;/strong>&lt;br>(SLH-DSA)&lt;/td>
&lt;td style="text-align:left">Signature&lt;/td>
&lt;td style="text-align:left">Fonction de hachage&lt;/td>
&lt;td style="text-align:left">32 octets&lt;/td>
&lt;td style="text-align:left">64 octets&lt;/td>
&lt;td style="text-align:left">Env. 17 000 octets&lt;/td>
&lt;td style="text-align:left">Génération très lente&lt;/td>
&lt;td style="text-align:left">Risque mathématique quasi nul. Pour applications de haute sécurité comme certificats racine.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Classic McEliece&lt;/strong>&lt;/td>
&lt;td style="text-align:left">KEM&lt;/td>
&lt;td style="text-align:left">Codes de Goppa&lt;/td>
&lt;td style="text-align:left">&lt;strong>Env. 1.04 Mo&lt;/strong>&lt;/td>
&lt;td style="text-align:left">13 568 octets&lt;/td>
&lt;td style="text-align:left">&lt;strong>188 octets&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Encapsulation rapide&lt;/td>
&lt;td style="text-align:left">40 ans de sécurité éprouvée. Clé publique énorme. Pour environnements avec codage en dur.&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="comprendre-les-compromis">Comprendre les compromis
&lt;/h3>&lt;p>Dans le monde de la PQC, il n&amp;rsquo;existe pas d&amp;rsquo;algorithme unique et magique qui soit « petit en taille, rapide, et avec des garanties mathématiques parfaites ».&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Les normes d&amp;rsquo;Internet (Kyber / Dilithium)&lt;/strong> : Elles offrent le meilleur équilibre des performances et sont les mieux adaptées au remplacement direct (drop-in replacement) du RSA et de l&amp;rsquo;ECC actuels.&lt;/li>
&lt;li>&lt;strong>La conservativité ultime (SPHINCS+)&lt;/strong> : Elle est choisie lorsque l&amp;rsquo;on souhaite une assurance absolue contre les futures percées mathématiques, même au prix de la taille des données et de la vitesse de traitement.&lt;/li>
&lt;li>&lt;strong>Pour des environnements spécifiques (FALCON / Classic McEliece)&lt;/strong> : Ce sont des armes spécialisées choisies en fonction des contraintes de l&amp;rsquo;environnement, telles que des bandes passantes de communication extrêmement étroites ou la possibilité d&amp;rsquo;une distribution préalable.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="11-défis-vers-la-mise-en-pratique-et-la-solution-réaliste-de-la--cryptographie-hybride-">11. Défis vers la mise en pratique et la solution réaliste de la « cryptographie hybride »
&lt;/h2>&lt;p>Avec l&amp;rsquo;achèvement de la standardisation par le NIST et la publication officielle des normes FIPS, la transition mondiale de l&amp;rsquo;infrastructure informatique vers la PQC (&lt;strong>Migration PQC&lt;/strong>) a véritablement commencé. Le navigateur Chrome de Google, iMessage d&amp;rsquo;Apple (protocole PQ3) et les fournisseurs de réseaux comme Cloudflare ont déjà implémenté le support de la PQC dans leurs protocoles et ont commencé leur exploitation commerciale.&lt;/p>
&lt;p>Cependant, basculer soudainement et complètement vers de nouveaux algorithmes de cryptographie comporte des risques très élevés. Si un brillant mathématicien venait à découvrir dans quelques années une faille mathématique fatale dans la cryptographie sur les réseaux (comme Kyber) qui pourrait être résolue même par un ordinateur classique, l&amp;rsquo;ensemble des systèmes qui en dépendent seraient instantanément exposés.&lt;/p>
&lt;p>L&amp;rsquo;approche réaliste et recommandée pour atténuer ce risque d&amp;rsquo;incertitude est la « &lt;strong>cryptographie hybride (Hybrid Cryptography)&lt;/strong> ».&lt;/p>
&lt;p>Dans la cryptographie hybride, l&amp;rsquo;échange de clés est effectué en utilisant simultanément les cryptographies classiques actuelles ayant fait leurs preuves depuis longtemps (par exemple, la cryptographie sur courbe elliptique comme X25519) et les nouvelles PQC (par exemple, Kyber768). Les composants de la clé partagée sont générés individuellement par chaque algorithme, puis enfin, une fonction de dérivation de clé (KDF) sécurisée est utilisée pour mélanger les deux composants et générer le secret maître final.&lt;/p>
&lt;div class="mermaid">graph TD
A["Client"] -->|① Envoi de la clé publique X25519 + clé publique Kyber| B["Serveur"]
B -->|② Réponse avec clé partagée X25519 + chiffré encapsulé Kyber| A
A --> C{"Dérivation du secret maître (KDF)"}
B --> C
C -->|"Entrée : (Clé partagée X25519) || (Clé partagée Kyber)"| D["Clé de communication sécurisée (AES-256 / ChaCha20)"]
D -->|"Résistance aux menaces quantiques ET aux vulnérabilités classiques"| E["Communication chiffrée hybride sécurisée (TLS 1.3)"]&lt;/div>
&lt;p>Grâce à cela, il est possible d&amp;rsquo;atteindre une sécurité robuste à deux niveaux : « même si un ordinateur quantique est réalisé et que l&amp;rsquo;ECC est brisé, Kyber protège la communication », et inversement, « même si un défaut mathématique inconnu est trouvé dans Kyber, l&amp;rsquo;ECC protège la communication ». Un exemple typique est le brouillon &lt;strong>X25519MLKEM768 (anciennement X25519Kyber768)&lt;/strong> en cours de standardisation à l&amp;rsquo;IETF, et la communication entre les navigateurs Web actuels et les serveurs de pointe est précisément réalisée à l&amp;rsquo;aide de cette méthode hybride.&lt;/p>
&lt;p>De plus, le concept de &lt;strong>Crypto Agility (Agilité cryptographique)&lt;/strong>, qui consiste à concevoir des systèmes avec « une architecture qui ne dépend pas excessivement d&amp;rsquo;un algorithme cryptographique spécifique et qui permet de basculer rapidement vers un autre algorithme (par exemple, de Kyber à McEliece, de Dilithium à SPHINCS+) en cas de compromission de l&amp;rsquo;algorithme », deviendra une exigence indispensable dans le développement futur des systèmes.&lt;/p>
&lt;hr>
&lt;h2 id="12-conclusion--un-nouvel-horizon-pour-les-technologies-cryptographiques">12. Conclusion : Un nouvel horizon pour les technologies cryptographiques
&lt;/h2>&lt;p>Paradoxalement, l&amp;rsquo;ordinateur quantique, la technologie de rêve de l&amp;rsquo;humanité, est devenu la plus grande menace, capable de briser les barrières mathématiques telles que la « factorisation en nombres premiers » et le « problème du logarithme discret » sur lesquelles nous nous reposons depuis de nombreuses années. Cependant, les cryptographes du monde entier ne se sont pas avoués vaincus et ont exploré des domaines mathématiques multidimensionnels plus complexes et profonds, tels que la théorie des réseaux, les arbres de fonctions de hachage et les codes correcteurs d&amp;rsquo;erreurs, pour bâtir une nouvelle barrière : la cryptographie post-quantique (PQC).&lt;/p>
&lt;p>L&amp;rsquo;achèvement de la standardisation des normes FIPS 203 (ML-KEM), FIPS 204 (ML-DSA) et FIPS 205 (SLH-DSA) par le NIST n&amp;rsquo;est pas une ligne d&amp;rsquo;arrivée. Ce n&amp;rsquo;est que la première étape d&amp;rsquo;un voyage épique de migration vers la PQC qui durera plusieurs décennies. Pour les ingénieurs logiciels et les architectes système, le grand défi technique de l&amp;rsquo;avenir consistera à adapter au mieux l&amp;rsquo;« augmentation de la taille des clés » et les « changements de coûts de calcul » apportés par ces nouveaux algorithmes aux protocoles réseau et aux systèmes.&lt;/p>
&lt;p>La bataille entre l&amp;rsquo;ordinateur quantique et la cryptographie est un domaine passionnant où la quête mathématique de l&amp;rsquo;humanité et l&amp;rsquo;évolution technologique se croisent de la manière la plus intense. À travers cet article, nous espérons que vous aurez acquis une compréhension approfondie de la belle théorie mathématique qui sous-tend la PQC, ainsi que des mécanismes surprenants de chaque algorithme qui façonnera l&amp;rsquo;avenir de la cybersécurité.&lt;/p>
&lt;hr>
&lt;p>&lt;em>Références :&lt;/em>&lt;/p>
&lt;ul>
&lt;li>&lt;em>NIST Post-Quantum Cryptography Standardization Program&lt;/em>&lt;/li>
&lt;li>&lt;em>FIPS 203: Module-Lattice-Based Key-Encapsulation Mechanism Standard&lt;/em>&lt;/li>
&lt;li>&lt;em>FIPS 204: Module-Lattice-Based Digital Signature Standard&lt;/em>&lt;/li>
&lt;li>&lt;em>FIPS 205: Stateless Hash-Based Digital Signature Standard&lt;/em>&lt;/li>
&lt;/ul></description></item><item><title>Le jour où les ordinateurs quantiques seront mis en pratique : situation en 2026</title><link>http://kenji.blog/fr/p/quantum-computing-2026-current-status/</link><pubDate>Fri, 11 Sep 2026 06:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/quantum-computing-2026-current-status/</guid><description>&lt;img src="http://kenji.blog/p/quantum-computing-2026-current-status/img/eyecatch.jpg" alt="Featured image of post Le jour où les ordinateurs quantiques seront mis en pratique : situation en 2026" />&lt;h2 id="1-introduction--où-en-sont-les-ordinateurs-quantiques-en-2026-">1. Introduction : Où en sont les ordinateurs quantiques en 2026 ?
&lt;/h2>&lt;p>En 2026, l&amp;rsquo;informatique quantique a connu un changement décisif, passant d&amp;rsquo;un ancien &amp;ldquo;rêve théorique&amp;rdquo; à une &amp;ldquo;réalité technique&amp;rdquo;. Alors que les limites des dispositifs &lt;strong>NISQ (Noisy Intermediate-Scale Quantum)&lt;/strong>, qui dominaient jusqu&amp;rsquo;à il y a quelques années, sont devenues claires, les instituts de recherche et les géants de la technologie du monde entier se sont orientés vers la réalisation de &amp;ldquo;l&amp;rsquo;informatique quantique tolérante aux pannes (FTQC : Fault-Tolerant Quantum Computing)&amp;rdquo;.&lt;/p>
&lt;p>Dans cet article, nous explorerons en profondeur l&amp;rsquo;état actuel des ordinateurs quantiques, en intégrant les dernières avancées de 2026. En particulier, nous détaillerons la correction d&amp;rsquo;erreurs quantiques (code de surface), la différence entre les qubits physiques et les qubits logiques, les progrès de l&amp;rsquo;informatique quantique topologique, et l&amp;rsquo;avant-garde des méthodes à supraconducteurs et à pièges à ions.&lt;/p>
&lt;hr>
&lt;h2 id="2-fondements-de-létat-quantique-et-fidélité-fidelity">2. Fondements de l&amp;rsquo;état quantique et fidélité (Fidelity)
&lt;/h2>&lt;p>L&amp;rsquo;unité fondamentale d&amp;rsquo;un ordinateur quantique, le bit quantique (Qubit), contrairement au bit classique (0 ou 1), peut prendre un état de superposition de 0 et de 1. L&amp;rsquo;état d&amp;rsquo;un seul qubit est représenté comme un vecteur dans l&amp;rsquo;espace de Hilbert comme suit :&lt;/p>
$$
|\psi\rangle = \alpha|0\rangle + \beta|1\rangle
$$
&lt;p>Ici, $\alpha$ et $\beta$ sont des amplitudes de probabilité complexes, satisfaisant la condition de normalisation suivante :&lt;/p>
$$
|\alpha|^2 + |\beta|^2 = 1
$$
&lt;p>Un indicateur extrêmement important pour mesurer les performances des calculs quantiques est la &lt;strong>fidélité (Fidelity)&lt;/strong>. La fidélité $F$ entre l&amp;rsquo;état quantique idéal $|\psi\rangle$ et la matrice densité réelle $\rho$, qui s&amp;rsquo;est dégradée pour devenir un état mixte à cause du bruit, est définie comme suit :&lt;/p>
$$
F(\rho, |\psi\rangle) = \langle \psi | \rho | \psi \rangle
$$
&lt;p>À l&amp;rsquo;heure actuelle en 2026, la fidélité des portes à 2 qubits (ex : portes CNOT et portes CZ) dépasse désormais de manière stable le mur des &lt;strong>99,99 %&lt;/strong> (ce que l&amp;rsquo;on appelle les &amp;ldquo;4 neufs&amp;rdquo;) dans les systèmes supraconducteurs. Il s&amp;rsquo;agit d&amp;rsquo;un chiffre qui dépasse largement le seuil de correction d&amp;rsquo;erreurs par le code de surface (environ 99 %), et constitue l&amp;rsquo;une des plus grandes avancées vers une application pratique.&lt;/p>
&lt;hr>
&lt;h2 id="3-les-limites-de-lère-nisq-et-le-changement-de-paradigme-vers-ftqc">3. Les limites de l&amp;rsquo;ère NISQ et le changement de paradigme vers FTQC
&lt;/h2>&lt;p>La période allant de la fin des années 2010 au début des années 2020 fut l&amp;rsquo;ère des NISQ (Noisy Intermediate-Scale Quantum), des dispositifs de quelques dizaines à quelques centaines de qubits dépourvus de correction d&amp;rsquo;erreurs. Cependant, les dispositifs NISQ avaient des limites claires.&lt;/p>
&lt;p>À mesure que la profondeur (Depth) du circuit augmente, les erreurs s&amp;rsquo;accumulent de manière exponentielle, rendant impossible l&amp;rsquo;obtention de résultats de calcul significatifs. La probabilité de succès globale $P_{success}$ à une profondeur de circuit $D$ décroît par rapport à la fidélité d&amp;rsquo;une seule porte $f$ et au nombre de portes $N$ comme suit :&lt;/p>
$$
P_{success} \approx f^N
$$
&lt;p>Si $f = 0.99$ et que 1000 portes sont appliquées, le résultat sera $0.99^{1000} \approx 4.3 \times 10^{-5}$, et sera presque enfoui dans le bruit aléatoire. Pour cette raison, en 2026, au lieu d&amp;rsquo;une mise à l&amp;rsquo;échelle directe des algorithmes NISQ (comme VQE ou QAOA), les ressources se concentrent sur la génération de &lt;strong>qubits logiques (Logical Qubit)&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h2 id="4-correction-derreurs-quantiques-et-qubits-logiques--à-la-pointe-du-code-de-surface">4. Correction d&amp;rsquo;erreurs quantiques et qubits logiques : À la pointe du code de surface
&lt;/h2>&lt;p>La correction d&amp;rsquo;erreurs quantiques (QEC : Quantum Error Correction) est une technologie qui encode plusieurs &amp;ldquo;qubits physiques&amp;rdquo; pour créer un &amp;ldquo;qubit logique&amp;rdquo;, permettant de détecter et de corriger les erreurs. Actuellement, le code le plus prometteur est le &lt;strong>code de surface (Surface Code)&lt;/strong>.&lt;/p>
&lt;h3 id="41-structure-du-code-de-surface-surface-code">4.1 Structure du code de surface (Surface Code)
&lt;/h3>&lt;p>Dans le code de surface, les qubits sont disposés dans une grille bidimensionnelle. Les qubits de données (conservant les informations réelles) et les qubits de mesure (pour la mesure du syndrome) sont disposés comme sur un damier.&lt;/p>
&lt;div class="mermaid">graph TD
A["Qubit de données (D1)"] --- B["Qubit de mesure (M1)"]
B --- C["Qubit de données (D2)"]
C --- D["Qubit de mesure (M2)"]
D --- E["Qubit de données (D3)"]
B --- F["Qubit de données (D4)"]
D --- G["Qubit de données (D5)"]
style A fill:#e1f5fe,stroke:#039be5
style C fill:#e1f5fe,stroke:#039be5
style E fill:#e1f5fe,stroke:#039be5
style F fill:#e1f5fe,stroke:#039be5
style G fill:#e1f5fe,stroke:#039be5
style B fill:#fff3e0,stroke:#fb8c00
style D fill:#fff3e0,stroke:#fb8c00&lt;/div>
&lt;p>Il utilise les opérateurs de stabilisateur $S_x$ et $S_z$ pour surveiller constamment le retournement de bit (erreur X) et le retournement de phase (erreur Z).&lt;/p>
$$
S_x = \prod_{i \in \text{star}} X_i, \quad S_z = \prod_{j \in \text{plaquette}} Z_j
$$
&lt;p>L&amp;rsquo;avancée majeure de 2026 est le dépassement complet du &amp;ldquo;seuil de rentabilité (Break-even point)&amp;rdquo;. En d&amp;rsquo;autres termes, le bruit éliminé par la correction d&amp;rsquo;erreurs est devenu plus important que le bruit causé par les circuits supplémentaires pour l&amp;rsquo;effectuer, permettant ainsi à la durée de vie du qubit logique de dépasser de plusieurs ordres de grandeur celle du qubit physique.&lt;/p>
&lt;h3 id="42-cycle-de-correction-derreurs-quantiques">4.2 Cycle de correction d&amp;rsquo;erreurs quantiques
&lt;/h3>&lt;p>La correction d&amp;rsquo;erreurs fonctionne comme une boucle de rétroaction continue.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant D as "Qubits de données"
participant M as "Qubits ancillaires/de mesure"
participant C as "Contrôleur classique"
loop "Cycle d'extraction de syndrome (approx 1 microsec)"
D->>M: "Intriquer (CNOT/CZ)"
M->>C: "Mesurer l'état (Syndrome)"
C->>C: "Décoder le syndrome (ex: Minimum Weight Perfect Matching)"
C-->>D: "Appliquer la correction de Pauli (si nécessaire)"
end&lt;/div>
&lt;p>Aujourd&amp;rsquo;hui, la technologie pour exécuter ce traitement de décodage classique (analyse de syndrome) en nanosecondes avec des FPGA ou des ASIC dédiés a été établie, et la correction d&amp;rsquo;erreurs en temps réel est entrée dans la phase de mise en œuvre pratique.&lt;/p>
&lt;hr>
&lt;h2 id="5-évolution-de-larchitecture-matérielle-édition-2026">5. Évolution de l&amp;rsquo;architecture matérielle (Édition 2026)
&lt;/h2>&lt;p>Le matériel quantique en 2026 évolue principalement selon trois axes : la &amp;ldquo;méthode à supraconducteurs&amp;rdquo;, la &amp;ldquo;méthode à pièges à ions&amp;rdquo; et la &amp;ldquo;méthode topologique&amp;rdquo;.&lt;/p>
&lt;h3 id="51-intégration-des-qubits-supraconducteurs">5.1 Intégration des qubits supraconducteurs
&lt;/h3>&lt;p>La méthode supraconductrice est un domaine mené par IBM et Google, et le qubit transmon utilisant des jonctions Josephson y est dominant. En 2026, des mégapuces intégrant des milliers à dix mille qubits physiques sur une seule puce ont été réalisées.&lt;/p>
&lt;p>Il convient de noter tout particulièrement l&amp;rsquo;établissement d&amp;rsquo;&lt;strong>interconnexions quantiques inter-modules (Quantum Interconnects)&lt;/strong>. La téléportation quantique entre puces utilisant des photons micro-ondes a été implémentée au niveau commercial, permettant de contourner les limites de taille d&amp;rsquo;un seul réfrigérateur à dilution.&lt;/p>
&lt;h3 id="52-mise-à-léchelle-bidimensionnelle-des-pièges-à-ions-et-interconnexion-optique">5.2 Mise à l&amp;rsquo;échelle bidimensionnelle des pièges à ions et interconnexion optique
&lt;/h3>&lt;p>La méthode des pièges à ions (menée par Quantinuum, IonQ, etc.) utilise les états d&amp;rsquo;énergie interne des ions en suspension dans le vide comme qubits. Comparée à la méthode supraconductrice, elle présente l&amp;rsquo;avantage d&amp;rsquo;un temps de cohérence T1/T2 extrêmement long et permet une connectivité globale (All-to-All Connectivity).&lt;/p>
&lt;p>La percée de 2026 fut la bidimensionnalisation de l&amp;rsquo;architecture QCCD (Quantum Charge Coupled Device) et la génération d&amp;rsquo;intrication à grande vitesse entre plusieurs pièges à l&amp;rsquo;aide d&amp;rsquo;interconnexions photoniques. Cela a considérablement amélioré la &amp;ldquo;lenteur de la vitesse de porte&amp;rdquo; et la &amp;ldquo;scalabilité&amp;rdquo;, qui étaient les points faibles des pièges à ions.&lt;/p>
&lt;h3 id="53-informatique-quantique-topologique--contrôle-des-anyons">5.3 Informatique quantique topologique : Contrôle des anyons
&lt;/h3>&lt;p>L&amp;rsquo;&lt;strong>informatique quantique topologique&lt;/strong>, longtemps considérée comme une existence théorique, est finalement entrée dans la phase de démonstration expérimentale en 2026. Cette méthode, promue par des entreprises telles que Microsoft, utilise des anyons non abéliens (Non-Abelian Anyons) appelés &amp;ldquo;modes zéro de Majorana (Majorana Zero Modes)&amp;rdquo;.&lt;/p>
&lt;p>Les portes quantiques sont exécutées par une opération de tressage (Braiding) qui intervertit les positions des particules d&amp;rsquo;anyons.&lt;/p>
$$
|\psi_{final}\rangle = B_{ij} |\psi_{initial}\rangle
$$
&lt;p>Ici, $B_{ij}$ est l&amp;rsquo;opérateur de tressage. L&amp;rsquo;approche topologique est intrinsèquement résistante au bruit de l&amp;rsquo;environnement (tolérance aux pannes au niveau matériel) car la préservation de l&amp;rsquo;information ne dépend pas de l&amp;rsquo;état local de la particule, mais de la topologie globale du &amp;ldquo;nœud&amp;rdquo;. En 2026, la création du premier qubit logique topologique à haute fidélité au monde a été confirmée, attirant l&amp;rsquo;attention en tant que raccourci puissant vers le FTQC.&lt;/p>
&lt;hr>
&lt;h2 id="6-feuille-de-route-et-perspectives-vers-une-application-pratique">6. Feuille de route et perspectives vers une application pratique
&lt;/h2>&lt;p>Pour que l&amp;rsquo;ordinateur quantique démontre véritablement l&amp;rsquo;&lt;strong>avantage quantique (Quantum Advantage)&lt;/strong> en surpassant les ordinateurs classiques (supercalculateurs) dans des domaines tels que la &amp;ldquo;chimie computationnelle&amp;rdquo;, la &amp;ldquo;science des matériaux&amp;rdquo; et la &amp;ldquo;modélisation financière&amp;rdquo;, des milliers de qubits logiques sont nécessaires.&lt;/p>
&lt;div class="mermaid">gantt
title "Feuille de route de l'informatique quantique (Révisée en 2026)"
dateFormat YYYY
axisFormat %Y
section "Ère NISQ"
"Qubits bruités (&lt;1000)" :done, 2018, 2024
section "Début de la FTQC"
"Démonstration du seuil de rentabilité" :done, 2024, 2026
"Centaines de qubits logiques" :active, 2026, 2028
section "FTQC à grande échelle"
"1000+ qubits logiques (App commerciale)" : 2028, 2030
"Ordinateur quantique universel tolérant aux pannes" : 2030, 2035&lt;/div>
&lt;h3 id="61-défis-actuels-et-avenir">6.1 Défis actuels et avenir
&lt;/h3>&lt;p>Le plus grand défi à l&amp;rsquo;heure actuelle en 2026 réside dans la capacité de refroidissement des immenses cryostats (réfrigérateurs à dilution) nécessaires au maintien de températures extrêmement basses, et dans le câblage (goulot d&amp;rsquo;étranglement des E/S) reliant l&amp;rsquo;équipement de contrôle à température ambiante et la puce quantique à température cryogénique. Face à cela, le développement de puces de contrôle CMOS fonctionnant en environnement cryogénique (Cryo-CMOS) progresse à un rythme effréné.&lt;/p>
&lt;h3 id="conclusion">Conclusion
&lt;/h3>&lt;p>L&amp;rsquo;année 2026 sera enregistrée dans l&amp;rsquo;histoire des ordinateurs quantiques comme &amp;ldquo;l&amp;rsquo;année inaugurale de la mise à l&amp;rsquo;échelle des qubits logiques&amp;rdquo;. Grâce à la démonstration des algorithmes de correction d&amp;rsquo;erreurs, à la modularisation du matériel et aux progrès rapides de l&amp;rsquo;approche topologique, le &amp;ldquo;jour de la mise en pratique&amp;rdquo; n&amp;rsquo;est plus une histoire lointaine, mais un jalon concret à atteindre d&amp;rsquo;ici quelques années. Pour les développeurs d&amp;rsquo;algorithmes quantiques et les entreprises, c&amp;rsquo;est le moment idéal pour investir sérieusement dans la résolution de problèmes en mode &amp;ldquo;quantum-native&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;p>&lt;em>Cet article a été rédigé sur la base des dernières recherches et tendances de l&amp;rsquo;industrie de l&amp;rsquo;informatique quantique en 2026.&lt;/em>&lt;/p></description></item></channel></rss>