<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Prime Numbers on kenji.blog</title><link>http://kenji.blog/fr/tags/prime-numbers/</link><description>Recent content in Prime Numbers on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>fr</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 16:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/fr/tags/prime-numbers/index.xml" rel="self" type="application/rss+xml"/><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></channel></rss>