<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Mathematics on kenji.blog</title><link>http://kenji.blog/de/categories/mathematics/</link><description>Recent content in Mathematics on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>de</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 22:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/de/categories/mathematics/index.xml" rel="self" type="application/rss+xml"/><item><title>Grundlagen und Implementierung der Verschlüsselung mit dem kleinen Satz von Fermat</title><link>http://kenji.blog/de/p/fermats-little-theorem-cryptography-implementation/</link><pubDate>Fri, 11 Sep 2026 22:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/fermats-little-theorem-cryptography-implementation/</guid><description>&lt;img src="http://kenji.blog/p/fermats-little-theorem-cryptography-implementation/img/eyecatch.jpg" alt="Featured image of post Grundlagen und Implementierung der Verschlüsselung mit dem kleinen Satz von Fermat" />&lt;h2 id="1-einführung-das-geheimnis-der-mathematik-hinter-der-modernen-kryptographie">1. Einführung: Das Geheimnis der Mathematik hinter der modernen Kryptographie
&lt;/h2>&lt;p>In der modernen digitalen Gesellschaft, insbesondere bei der Kommunikation über das Internet, ist &amp;ldquo;Verschlüsselung&amp;rdquo; zu einer unverzichtbaren Basistechnologie geworden. Dass wir Websites über HTTPS sicher in einem Webbrowser durchsuchen, Finanztransaktionen im Online-Banking durchführen und privat in Messaging-Apps kommunizieren können, liegt daran, dass kryptographische Protokolle, die durch fortgeschrittene mathematische Theorien gestützt werden, im Hintergrund arbeiten. Eine besonders wichtige Rolle spielt dabei die &amp;ldquo;Public-Key-Kryptographie&amp;rdquo;, deren prominentester Vertreter die &lt;strong>RSA-Verschlüsselung&lt;/strong> ist.&lt;/p>
&lt;p>Die Sicherheit und Gültigkeit vieler kryptographischer Algorithmen, einschließlich RSA, hängt stark von einem sehr schönen und mächtigen Satz ab, der im 17. Jahrhundert vom französischen Mathematiker Pierre de Fermat entdeckt wurde. Das ist der &lt;strong>kleine Satz von Fermat&lt;/strong>. Darüber hinaus spielt der Satz von Leonhard Euler, der diesen verallgemeinert, eine entscheidende Rolle in der Kryptographietheorie.&lt;/p>
&lt;p>In diesem Artikel werden wir von Grund auf ausführlich erklären, wie die Entdeckung der reinen Mathematik, der kleine Satz von Fermat, in der modernen, praktischen Kryptographie, insbesondere beim &amp;ldquo;Primzahltest&amp;rdquo; und bei der &amp;ldquo;RSA-Verschlüsselung&amp;rdquo;, Anwendung findet. Dies ist ein sehr detaillierter technischer Leitfaden, der mathematische Beweise, Ver- und Entschlüsselungsmechanismen sowie spezifische Algorithmus-Implementierungen in C++ und Python abdeckt.&lt;/p>
&lt;hr>
&lt;h2 id="2-grundlagen-der-kongruenzen-und-der-modularen-arithmetik">2. Grundlagen der Kongruenzen und der modularen Arithmetik
&lt;/h2>&lt;p>Um den kleinen Satz von Fermat zu verstehen, müssen wir uns zunächst mit dem mathematischen Konzept der &amp;ldquo;modularen Arithmetik (Kongruenz)&amp;rdquo; vertraut machen. Die modulare Arithmetik ist ein Rechensystem, das sich auf den &amp;ldquo;Rest&amp;rdquo; nach der Division durch eine bestimmte feste Zahl (Modul genannt) konzentriert. Da es sich um eine Berechnung wie beim Zifferblatt einer Uhr (die in 12 Stunden einen Umlauf macht) handelt, wird sie auch &amp;ldquo;Uhrenarithmetik&amp;rdquo; genannt.&lt;/p>
&lt;p>Wenn die Reste der Division der ganzen Zahlen $a$ und $b$ durch eine positive ganze Zahl $n$ gleich sind, wird dies mathematisch wie folgt beschrieben:&lt;/p>
$$
a \equiv b \pmod n
$$
&lt;p>Dies liest sich als &amp;ldquo;$a$ und $b$ sind kongruent modulo $n$&amp;rdquo;. Zum Beispiel ist der Rest von 17 geteilt durch 5 gleich 2, und der Rest von 12 geteilt durch 5 ist ebenfalls 2. Daher können wir schreiben:&lt;/p>
$$
17 \equiv 12 \pmod 5 \equiv 2 \pmod 5
$$
&lt;p>In der modularen Arithmetik gelten die üblichen vier Grundrechenarten (Addition, Subtraktion, Multiplikation) wie gewohnt:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Addition&lt;/strong>: Wenn $a \equiv b \pmod n$ und $c \equiv d \pmod n$, dann $a + c \equiv b + d \pmod n$&lt;/li>
&lt;li>&lt;strong>Subtraktion&lt;/strong>: Wenn $a \equiv b \pmod n$ und $c \equiv d \pmod n$, dann $a - c \equiv b - d \pmod n$&lt;/li>
&lt;li>&lt;strong>Multiplikation&lt;/strong>: Wenn $a \equiv b \pmod n$ und $c \equiv d \pmod n$, dann $a \times c \equiv b \times d \pmod n$&lt;/li>
&lt;li>&lt;strong>Potenzieren&lt;/strong>: Wenn $a \equiv b \pmod n$, dann $a^k \equiv b^k \pmod n$ für jede natürliche Zahl $k$&lt;/li>
&lt;/ol>
&lt;p>Bei der &lt;strong>Division&lt;/strong> ist jedoch Vorsicht geboten. Im Allgemeinen bedeutet $a \times c \equiv b \times c \pmod n$ nicht, dass wir beide Seiten durch $c$ teilen und $a \equiv b \pmod n$ erhalten können. Dies gilt nur, wenn $c$ und $n$ teilerfremd sind (ihr größter gemeinsamer Teiler ist 1). Dieses Konzept des &amp;ldquo;modularen Inversen&amp;rdquo; ist extrem wichtig bei der Schlüsselgenerierung der RSA-Verschlüsselung, die später beschrieben wird.&lt;/p>
&lt;hr>
&lt;h2 id="3-mathematischer-hintergrund-und-beweis-des-kleinen-satzes-von-fermat">3. Mathematischer Hintergrund und Beweis des kleinen Satzes von Fermat
&lt;/h2>&lt;p>Nachdem wir nun die Grundlagen der modularen Arithmetik behandelt haben, kommen wir zum Hauptthema: dem kleinen Satz von Fermat.&lt;/p>
&lt;h3 id="31-definition-des-satzes">3.1 Definition des Satzes
&lt;/h3>&lt;p>Der kleine Satz von Fermat wird wie folgt formuliert:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Kleiner Satz von Fermat (Fermat&amp;rsquo;s Little Theorem)&lt;/strong>
Sei $p$ eine Primzahl und $a$ eine beliebige ganze Zahl, die kein Vielfaches von $p$ ist (d.h. $a$ und $p$ sind teilerfremd). Dann gilt die folgende Kongruenz:
&lt;/p>
$$ a^{p-1} \equiv 1 \pmod p $$
&lt;/blockquote>
&lt;p>Es ist auch üblich, die Bedingung &amp;ldquo;$a$ ist kein Vielfaches von $p$&amp;rdquo; zu entfernen und es so auszudrücken, dass es für alle ganzen Zahlen $a$ gilt. In diesem Fall multiplizieren wir beide Seiten mit $a$ und erhalten:&lt;/p>
$$
a^p \equiv a \pmod p
$$
&lt;h3 id="32-bestätigung-durch-konkrete-beispiele">3.2 Bestätigung durch konkrete Beispiele
&lt;/h3>&lt;p>Lassen Sie uns anhand konkreter Zahlen prüfen, ob der Satz wirklich gilt.
Sei die Primzahl $p = 5$. Dann ist $p-1 = 4$. Wir wählen als $a$ ganze Zahlen, die keine Vielfachen von $p$ sind.&lt;/p>
&lt;ul>
&lt;li>Für $a = 2$: $2^{5-1} = 2^4 = 16$. $16 \div 5 = 3$ Rest $1$. Also $16 \equiv 1 \pmod 5$. (Gültig)&lt;/li>
&lt;li>Für $a = 3$: $3^{5-1} = 3^4 = 81$. $81 \div 5 = 16$ Rest $1$. Also $81 \equiv 1 \pmod 5$. (Gültig)&lt;/li>
&lt;li>Für $a = 4$: $4^{5-1} = 4^4 = 256$. $256 \div 5 = 51$ Rest $1$. Also $256 \equiv 1 \pmod 5$. (Gültig)&lt;/li>
&lt;/ul>
&lt;p>Wie Sie sehen können, egal welches $a$ Sie wählen (solange es kein Vielfaches von 5 ist), ist der Rest immer 1, wenn Sie es zur 4. Potenz erheben und durch 5 teilen. Es scheint wie Magie, aber es stammt von den wunderbaren Eigenschaften der Primzahlen ab.&lt;/p>
&lt;h3 id="33-mathematischer-beweis-des-satzes">3.3 Mathematischer Beweis des Satzes
&lt;/h3>&lt;p>Warum ist das so? Hier stellen wir einen eleganten Beweis mit Hilfe der Menge der Restklassen vor.&lt;/p>
&lt;p>Betrachten wir die Menge $S = \{1, 2, 3, \dots, p-1\}$. Dies sind Repräsentanten der ganzen Zahlen, deren Rest bei Division durch $p$ von $1$ bis $p-1$ reicht.
Betrachten wir nun eine neue Menge $T$, in der jedes Element mit einer zu $p$ teilerfremden ganzen Zahl $a$ multipliziert wird.
&lt;/p>
$$ T = \{1a, 2a, 3a, \dots, (p-1)a\} $$
&lt;p>Betrachten wir den Rest jedes Elements dieser Menge $T$ bei der Division durch $p$. Erstaunlicherweise stimmen diese Reste – obwohl ihre Reihenfolge vertauscht sein mag – genau mit der Menge der Elemente der ursprünglichen Menge $S$ überein.
Weil:&lt;/p>
&lt;ol>
&lt;li>Kein Element von $T$ ein Vielfaches von $p$ wird (da weder $a$ noch die ursprünglichen Elemente Vielfache von $p$ sind).&lt;/li>
&lt;li>Es in $T$ keine zwei verschiedenen Elemente gibt, die modulo $p$ kongruent sind. Wenn $ia \equiv ja \pmod p$ ($i \neq j$) wäre, könnten wir durch $a$ teilen, da $a$ und $p$ teilerfremd sind, und bekämen $i \equiv j \pmod p$, was ein Widerspruch ist.&lt;/li>
&lt;/ol>
&lt;p>Daher ist das Produkt aller Elemente von $S$ kongruent zum Produkt aller Elemente von $T$ modulo $p$.&lt;/p>
$$
(1a) \times (2a) \times \dots \times ((p-1)a) \equiv 1 \times 2 \times \dots \times (p-1) \pmod p
$$
&lt;p>Wenn wir die linke Seite umstellen, haben wir $p-1$ mal $a$, also:&lt;/p>
$$
a^{p-1} \cdot (p-1)! \equiv (p-1)! \pmod p
$$
&lt;p>Da $(p-1)!$ teilerfremd zu $p$ ist, können wir beide Seiten durch $(p-1)!$ teilen und erhalten schließlich den folgenden Satz:&lt;/p>
$$
a^{p-1} \equiv 1 \pmod p
$$
&lt;p>Dies ist der Beweis für den kleinen Satz von Fermat.&lt;/p>
&lt;hr>
&lt;h2 id="4-eulersche-phi-funktion-und-der-satz-von-euler">4. Eulersche Phi-Funktion und der Satz von Euler
&lt;/h2>&lt;p>Der kleine Satz von Fermat ist ein Satz über &amp;ldquo;Primzahlen $p$&amp;rdquo;, aber Leonhard Euler verallgemeinerte ihn für &amp;ldquo;beliebige positive ganze Zahlen $n$&amp;rdquo;. Diese Erweiterung ist entscheidend, um die RSA-Verschlüsselung zu verstehen.&lt;/p>
&lt;h3 id="41-die-eulersche-phi-funktion-phin">4.1 Die Eulersche Phi-Funktion $\phi(n)$
&lt;/h3>&lt;p>Die Eulersche Phi-Funktion (oder Eulersche Totientenfunktion) $\phi(n)$ ist eine Funktion, die die &amp;ldquo;Anzahl der ganzen Zahlen von $1$ bis $n$, die teilerfremd zu $n$ sind&amp;rdquo;, angibt.&lt;/p>
&lt;ul>
&lt;li>Für eine Primzahl $p$ sind alle ganzen Zahlen von $1$ bis $p-1$ teilerfremd zu $p$, also ist $\phi(p) = p - 1$.&lt;/li>
&lt;li>Für zwei verschiedene Primzahlen $p$ und $q$ und deren Produkt $n = p \times q$ kann $\phi(n)$ mit einer sehr einfachen Formel berechnet werden:
$$ \phi(p \times q) = \phi(p) \times \phi(q) = (p - 1)(q - 1) $$&lt;/li>
&lt;/ul>
&lt;p>Diese Eigenschaft ist die Kernlogik bei der Schlüsselgenerierung für die RSA-Verschlüsselung.&lt;/p>
&lt;h3 id="42-der-satz-von-euler">4.2 Der Satz von Euler
&lt;/h3>&lt;p>Euler verallgemeinerte den kleinen Satz von Fermat wie folgt:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Satz von Euler (Euler&amp;rsquo;s Theorem)&lt;/strong>
Für eine positive ganze Zahl $n$ und eine zu ihr teilerfremde ganze Zahl $a$ gilt:
&lt;/p>
$$ a^{\phi(n)} \equiv 1 \pmod n $$
&lt;/blockquote>
&lt;p>Wenn $n$ eine Primzahl $p$ ist, dann ist $\phi(p) = p - 1$, also ist dies genau der kleine Satz von Fermat ($a^{p-1} \equiv 1 \pmod p$). Der kleine Satz von Fermat ist also nur ein Spezialfall des Satzes von Euler.&lt;/p>
&lt;hr>
&lt;h2 id="5-riesige-primzahlen-finden-der-fermat-primzahltest">5. Riesige Primzahlen finden: Der Fermat-Primzahltest
&lt;/h2>&lt;p>In der Kryptographie (wie bei der RSA-Verschlüsselung und dem Diffie-Hellman-Schlüsselaustausch) ist es notwendig, schnell &amp;ldquo;riesige Primzahlen&amp;rdquo; mit hunderten von Ziffern zu finden. Um jedoch zu testen, ob eine riesige Zahl $N$ prim ist, würde die Methode der &amp;ldquo;Probedivision&amp;rdquo;, bei der man versucht, durch alle Zahlen von $2$ bis $\sqrt{N}$ zu teilen, etwa so lange dauern wie das Alter des Universums.&lt;/p>
&lt;p>Hier kommt der &lt;strong>Fermat-Primzahltest (Fermat Primality Test)&lt;/strong> ins Spiel, ein &amp;ldquo;probabilistischer Primzahltest&amp;rdquo;, der den kleinen Satz von Fermat umkehrt.&lt;/p>
&lt;h3 id="51-was-ist-ein-probabilistischer-primzahltest">5.1 Was ist ein probabilistischer Primzahltest?
&lt;/h3>&lt;p>Nach dem kleinen Satz von Fermat gilt, wenn $p$ eine Primzahl ist, für jedes $a$ ($1 &lt; a &lt; p$) immer $a^{p-1} \equiv 1 \pmod p$.
Wenn wir die Kontraposition davon nehmen, können wir sagen: &amp;ldquo;Wenn es ein $a$ gibt, für das $a^{p-1} \not\equiv 1 \pmod p$ ist, dann ist $p$ &lt;strong>absolut keine Primzahl (es ist eine zusammengesetzte Zahl)&lt;/strong>&amp;rdquo;.&lt;/p>
&lt;p>Wenn wir also testen wollen, ob $N$ prim ist, wählen wir zufällig einige $a$ und berechnen $a^{N-1} \pmod N$, um zu sehen, ob das Ergebnis $1$ ist. Wenn wir auch nur einmal ein anderes Ergebnis als $1$ erhalten, ist mit Sicherheit bestätigt, dass $N$ eine zusammengesetzte Zahl ist. Wenn das Ergebnis nach vielen Versuchen immer $1$ ist, können wir mit hoher Wahrscheinlichkeit schlussfolgern, dass $N$ &amp;ldquo;wahrscheinlich eine Primzahl ist&amp;rdquo;.&lt;/p>
&lt;h3 id="52-erklärung-des-algorithmus-und-flussdiagramm">5.2 Erklärung des Algorithmus und Flussdiagramm
&lt;/h3>&lt;p>Der Algorithmus für den Fermat-Test ist wie folgt:&lt;/p>
&lt;div class="mermaid">flowchart TD
Start["Start"] --> Input["Zahl p zum Testen und Anzahl der Tests k eingeben"]
Input --> LoopStart["Schleife von i = 0 bis k-1"]
LoopStart --> Condition{"i &lt; k ?"}
Condition -- "Ja" --> RandomA["Wähle zufällige ganze Zahl a im Bereich 1 &lt; a &lt; p-1"]
RandomA --> Calc["Berechne modulares Potenzieren a^(p-1) mod p"]
Calc --> CheckPrime{"Ist das Ergebnis 1?"}
CheckPrime -- "Nein" --> ReturnComposite["p ist eine zusammengesetzte Zahl (bestätigt)"]
CheckPrime -- "Ja" --> Increment["Erhöhe i"]
Increment --> Condition
Condition -- "Nein" --> ReturnPrime["p ist wahrscheinlich eine Primzahl (probabilistisch)"]
ReturnComposite --> End["Ende"]
ReturnPrime --> End&lt;/div>
&lt;h3 id="53-die-falle-der-carmichael-zahlen-pseudoprimzahlen">5.3 Die Falle der Carmichael-Zahlen (Pseudoprimzahlen)
&lt;/h3>&lt;p>Der Fermat-Test ist sehr schnell, hat aber einen großen Fehler. Es gibt teuflische Zahlen, die zusammengesetzt sind, aber dennoch $a^{N-1} \equiv 1 \pmod N$ für alle $a$ erfüllen. Diese werden &lt;strong>Carmichael-Zahlen (Carmichael numbers)&lt;/strong> genannt. Die kleinste Carmichael-Zahl ist $561$ ($3 \times 11 \times 17$).&lt;/p>
&lt;p>Aufgrund der Existenz von Carmichael-Zahlen kann ein reiner Fermat-Test allein keinen absoluten Primzahltest garantieren. Daher verwenden reale Verschlüsselungssysteme (wie OpenSSL) standardmäßig den &lt;strong>Miller-Rabin-Primzahltest&lt;/strong>, der eine Verbesserung des Fermat-Tests darstellt. Der Miller-Rabin-Test kann Carmichael-Zahlen erkennen, wodurch die Wahrscheinlichkeit eines falschen Ergebnisses praktisch auf Null reduziert wird.&lt;/p>
&lt;h3 id="54-schnelles-modulares-potenzieren-binäre-exponentiation">5.4 Schnelles modulares Potenzieren (Binäre Exponentiation)
&lt;/h3>&lt;p>Im Primzahltestalgorithmus müssen wir $a^{N-1} \pmod N$ berechnen. Wenn $N$ riesig ist, hat $a^{N-1}$ eine astronomische Anzahl von Ziffern und passt nicht in den Speicher des Computers.
Die Lösung dafür ist die &lt;strong>binäre Exponentiation (Exponentiation by Squaring)&lt;/strong> oder das modulare Potenzieren. Durch das Modulo (mod N) bei jedem Schritt der Berechnung wird der Wert immer kleiner als $N$ gehalten, und die Berechnung wird sehr schnell möglich (Zeitkomplexität $O(\log N)$).&lt;/p>
&lt;hr>
&lt;h2 id="6-implementierung-von-primzahltest-und-modularem-potenzieren">6. Implementierung von Primzahltest und modularem Potenzieren
&lt;/h2>&lt;p>Lassen Sie uns nun den Fermat-Primzahltest und die binäre Exponentiation in C++ und Python implementieren.&lt;/p>
&lt;h3 id="61-implementierung-in-c">6.1 Implementierung in C++
&lt;/h3>&lt;p>In C++ laufen Standard-Ganzzahltypen leicht über, daher ist eine Big-Integer-Bibliothek (wie GMP) erforderlich, um riesige Zahlen zu handhaben. Aber hier zeigen wir eine Implementierung innerhalb des Bereichs von 64-Bit-Ganzzahlen (&lt;code>unsigned long long&lt;/code>), um den Algorithmus zu verstehen.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;random&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="k">namespace&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Schnelles modulares Potenzieren (a^b mod m) - Binäre Exponentiation
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="nf">power_mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Wenn das niedrigstwertige Bit von b 1 ist, multipliziere das Ergebnis mit a
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">__int128&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="n">result&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// 128-Bit-Erweiterung zur Vermeidung von Überlauf
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// a quadrieren
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">__int128&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="n">a&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// b nach rechts verschieben (halbieren)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">/=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Fermat-Primzahltest
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">bool&lt;/span> &lt;span class="nf">fermat_is_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">iterations&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">random_device&lt;/span> &lt;span class="n">rd&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">mt19937_64&lt;/span> &lt;span class="n">gen&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">rd&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">uniform_int_distribution&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">dis&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">iterations&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dis&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">gen&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Wenn a^(p-1) mod p nicht 1 ist, ist es eine zusammengesetzte Zahl
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">power_mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Wahrscheinlich prim
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1000000007&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Bekannte Primzahl
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">fermat_is_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; is probably prime.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; is composite.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="62-implementierung-in-python">6.2 Implementierung in Python
&lt;/h3>&lt;p>Der Standard-Ganzzahltyp von Python unterstützt beliebig große Zahlen, sodass Sie sich keine Sorgen über einen Überlauf machen müssen. Darüber hinaus verwendet die in Python integrierte Funktion &lt;code>pow(a, b, m)&lt;/code> intern die binäre Exponentiation und ist sehr schnell.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">random&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">fermat_is_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">iterations&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> Probabilistischer Primzahltest unter Verwendung des Fermat-Primzahltests
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">iterations&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Wähle eine zufällige Zahl a zwischen 2 und p-2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Berechne a^(p-1) mod p. Das integrierte pow ist schnell.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span> &lt;span class="c1"># Bestätigt zusammengesetzt&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">True&lt;/span> &lt;span class="c1"># Wahrscheinlich prim&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Test&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">number_to_test&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">104729&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="n">fermat_is_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">number_to_test&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">number_to_test&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> ist wahrscheinlich prim.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">number_to_test&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> ist zusammengesetzt.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="7-anwendung-auf-die-rsa-verschlüsselung-wo-fermat-und-euler-zusammenkommen">7. Anwendung auf die RSA-Verschlüsselung: Wo Fermat und Euler zusammenkommen
&lt;/h2>&lt;p>Die großartigste Anwendung des kleinen Satzes von Fermat (und des Satzes von Euler) ist die &lt;strong>RSA-Verschlüsselung&lt;/strong>, die 1977 von Rivest, Shamir und Adleman entwickelt wurde.
Die RSA-Verschlüsselung ist ein revolutionäres &amp;ldquo;Public-Key-Kryptographie&amp;rdquo;-System, das es ermöglicht, den Schlüssel zur Verschlüsselung (öffentlicher Schlüssel) der ganzen Welt zugänglich zu machen, während nur der Empfänger den Schlüssel zur Entschlüsselung (privater Schlüssel) kennt.&lt;/p>
&lt;p>Diese Asymmetrie beruht auf der rechnerischen Sicherheit der Tatsache, dass &amp;ldquo;es extrem schwierig ist, eine riesige zusammengesetzte Zahl in ihre Primfaktoren zu zerlegen&amp;rdquo;.&lt;/p>
&lt;h3 id="71-wie-die-rsa-verschlüsselung-funktioniert-schlüsselgenerierung-verschlüsselung-entschlüsselung">7.1 Wie die RSA-Verschlüsselung funktioniert (Schlüsselgenerierung, Verschlüsselung, Entschlüsselung)
&lt;/h3>&lt;p>Lassen Sie uns den gesamten Kommunikationsfluss der RSA-Verschlüsselung anhand eines Mermaid-Sequenzdiagramms untersuchen.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant Alice["Alice (Empfänger)"]
participant Bob["Bob (Sender)"]
Alice->>Alice: "Generiere riesige Primzahlen p, q"
Alice->>Alice: "Berechne N = p * q, φ(N) = (p-1)(q-1)"
Alice->>Alice: "Berechne öffentlichen Schlüssel e und privaten Schlüssel d (e*d ≡ 1 mod φ(N))"
Alice->>Bob: "Sende öffentlichen Schlüssel (N, e)"
Note over Bob: "Bereite Klartext M vor (M &lt; N)"
Bob->>Bob: "Berechne Geheimtext C = M^e mod N"
Bob->>Alice: "Sende Geheimtext C"
Alice->>Alice: "Entschlüssele durch Berechnen des Klartextes M = C^d mod N"&lt;/div>
&lt;p>Im Folgenden erklären wir die mathematischen Schritte im Detail.&lt;/p>
&lt;h4 id="schritt-1-schlüsselgenerierung-arbeit-der-empfängerin-alice">Schritt 1: Schlüsselgenerierung (Arbeit der Empfängerin Alice)
&lt;/h4>&lt;ol>
&lt;li>Generiere zufällig zwei riesige Primzahlen $p$ und $q$ (hier wird der zuvor erwähnte Primzahltest verwendet).&lt;/li>
&lt;li>Berechne ihr Produkt $N = p \times q$. Dieses $N$ wird veröffentlicht.&lt;/li>
&lt;li>Berechne $\phi(N) = (p-1)(q-1)$ unter Verwendung der Eulerschen Phi-Funktion.&lt;/li>
&lt;li>Wähle eine ganze Zahl $e$ (öffentlicher Exponent), die teilerfremd zu $\phi(N)$ ist (oft wird $e = 65537$ verwendet).&lt;/li>
&lt;li>Berechne das modulare Inverse $d$ (privater Exponent) von $e$. Finde also $d$ so, dass Folgendes gilt:
$$ e \cdot d \equiv 1 \pmod{\phi(N)} $$
Für diese Berechnung wird der &lt;strong>erweiterte euklidische Algorithmus&lt;/strong> verwendet.&lt;/li>
&lt;/ol>
&lt;p>Der &lt;strong>öffentliche Schlüssel ist somit $(N, e)$&lt;/strong> und der &lt;strong>private Schlüssel ist $(N, d)$&lt;/strong>. ($p, q$ und $\phi(N)$ sollten sofort vernichtet oder streng geheim gehalten werden).&lt;/p>
&lt;h4 id="schritt-2-verschlüsselung-arbeit-des-senders-bob">Schritt 2: Verschlüsselung (Arbeit des Senders Bob)
&lt;/h4>&lt;p>Nehmen wir an, Bob möchte die Nachricht $M$ an Alice senden ($M$ ist eine numerische Darstellung von Zeichen, und $0 \le M &lt; N$).
Bob verwendet Alices öffentlichen Schlüssel $(N, e)$, um die folgende Berechnung durchzuführen und den Geheimtext $C$ zu erstellen:&lt;/p>
$$
C \equiv M^e \pmod N
$$
&lt;p>Dieser $C$ wird über das Netzwerk an Alice gesendet.&lt;/p>
&lt;h4 id="schritt-3-entschlüsselung-arbeit-der-empfängerin-alice">Schritt 3: Entschlüsselung (Arbeit der Empfängerin Alice)
&lt;/h4>&lt;p>Nach Erhalt des Geheimtextes $C$ führt Alice die folgende Berechnung unter Verwendung des privaten Schlüssels $d$ durch, den nur sie kennt:&lt;/p>
$$
M' \equiv C^d \pmod N
$$
&lt;p>Erstaunlicherweise stimmt das Ergebnis dieser Berechnung $M'$ perfekt mit der ursprünglichen Nachricht $M$ überein.&lt;/p>
&lt;h3 id="72-warum-kann-es-entschlüsselt-werden-mathematischer-beweis">7.2 Warum kann es entschlüsselt werden? (Mathematischer Beweis)
&lt;/h3>&lt;p>Hier zeigen der kleine Satz von Fermat (und der Satz von Euler) ihren wahren Wert. Warum kehrt $C^d \pmod N$ zu $M$ zurück?&lt;/p>
&lt;p>Lassen Sie uns die Entschlüsselungsformel erweitern.
Da $C \equiv M^e \pmod N$, haben wir:
&lt;/p>
$$ C^d \equiv (M^e)^d \equiv M^{ed} \pmod N $$
&lt;p>Im Schritt der Schlüsselgenerierung haben wir $d$ so gewählt, dass $e \cdot d \equiv 1 \pmod{\phi(N)}$. Das bedeutet, es gibt eine ganze Zahl $k$, sodass wir schreiben können:
&lt;/p>
$$ e \cdot d = 1 + k \cdot \phi(N) $$
&lt;p>Setzen wir dies in die obige Gleichung ein:
&lt;/p>
$$ M^{ed} = M^{1 + k \cdot \phi(N)} = M \cdot M^{k \cdot \phi(N)} = M \cdot (M^{\phi(N)})^k \pmod N $$
&lt;p>Hier kommt der &lt;strong>Satz von Euler&lt;/strong> ($M^{\phi(N)} \equiv 1 \pmod N$) ins Spiel. (&lt;em>Streng genommen müssen $M$ und $N$ teilerfremd sein, aber in RSA ist die Wahrscheinlichkeit, dass $M$ und $N$ nicht teilerfremd sind, astronomisch gering, und mithilfe des Chinesischen Restsatzes kann bewiesen werden, dass es auch gilt, wenn sie nicht teilerfremd sind&lt;/em>).&lt;/p>
&lt;p>Wenden wir den Satz von Euler an, da $M^{\phi(N)} \equiv 1$ ist:
&lt;/p>
$$ M \cdot (1)^k \equiv M \pmod N $$
&lt;p>Hervorragend, $M$ wurde wiederhergestellt! Die Eigenschaften von Zahlen, die von Fermat und Euler vor Hunderten von Jahren entdeckt wurden, garantieren perfekt die Vertraulichkeit der modernen digitalen Kommunikation.&lt;/p>
&lt;hr>
&lt;h2 id="8-spielzeug-implementierung-der-rsa-verschlüsselung-python">8. Spielzeug-Implementierung der RSA-Verschlüsselung (Python)
&lt;/h2>&lt;p>Da es schwer ist, ein Gefühl nur für die Theorie zu bekommen, verwenden wir Python, um den Prozess der RSA-Schlüsselgenerierung, Verschlüsselung und Entschlüsselung tatsächlich zu implementieren. Dies ist eine &amp;ldquo;Spielzeug-Implementierung&amp;rdquo; für Bildungszwecke, aber die verwendete Mathematik ist genau dieselbe wie bei der echten.&lt;/p>
&lt;p>Wir fügen auch den &amp;ldquo;erweiterten euklidischen Algorithmus&amp;rdquo; hinzu, um das modulare Inverse $d$ zu finden.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;span class="lnt">74
&lt;/span>&lt;span class="lnt">75
&lt;/span>&lt;span class="lnt">76
&lt;/span>&lt;span class="lnt">77
&lt;/span>&lt;span class="lnt">78
&lt;/span>&lt;span class="lnt">79
&lt;/span>&lt;span class="lnt">80
&lt;/span>&lt;span class="lnt">81
&lt;/span>&lt;span class="lnt">82
&lt;/span>&lt;span class="lnt">83
&lt;/span>&lt;span class="lnt">84
&lt;/span>&lt;span class="lnt">85
&lt;/span>&lt;span class="lnt">86
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">random&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Größten gemeinsamen Teiler finden&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">b&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">a&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Erweiterter euklidischer Algorithmus (findet x, y für ax + by = gcd(a,b))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Verwendet, um d für e*d ≡ 1 (mod φ(N)) zu finden&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">extended_gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">extended_gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">g&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">//&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">mod_inverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">extended_gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">g&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">Exception&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Inverses existiert nicht&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">phi&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Primzahl-Generierungsfunktion (Vereinfachte Version: generiert kleine Primzahlen)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">generate_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="kc">True&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">p&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">getrandbits&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Einfacher Test anstelle des zuvor erwähnten Fermat-Tests&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">p&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># RSA-Schlüsselgenerierung&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">generate_keypair&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">16&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">p&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">generate_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">q&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">generate_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Stellen Sie sicher, dass p und q nicht gleich sind&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">q&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">q&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">generate_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">q&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">phi&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">q&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Für e werden oft Primzahlen wie 65537 verwendet, aber hier wird es zufällig gewählt&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randrange&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">g&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randrange&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Berechnung des privaten Schlüssels d&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">d&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod_inverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Öffentlicher Schlüssel (e, n), Privater Schlüssel (d, n)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">((&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">encrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pk&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">plaintext&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pk&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Berechne plaintext^e mod n&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cipher&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">ord&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">char&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">char&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">plaintext&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">cipher&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">decrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sk&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ciphertext&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sk&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Berechne cipher^d mod n und konvertiere zurück in Zeichen&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">plain&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nb">chr&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">char&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">char&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">ciphertext&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">plain&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Ausführungsbeispiel&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;--- RSA-Verschlüsselung Spielzeug-Implementierung ---&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">public_key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">private_key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">generate_keypair&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">12&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># Verwendet 12-Bit-Primzahlen&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;Öffentlicher Schlüssel (e, n): &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">public_key&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Privater Schlüssel (d, n): &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">private_key&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Hello Math!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">Ursprüngliche Nachricht: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Verschlüsselung&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">encrypted_msg&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">encrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">public_key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Geheimtext: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">encrypted_msg&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Entschlüsselung&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">decrypted_msg&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">decrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">private_key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">encrypted_msg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Entschlüsselte Nachricht: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">decrypted_msg&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Wenn Sie diesen Code ausführen, können Sie sehen, wie ein Array von Zeichen in ein Array unvertrauter Zahlen (Geheimtext) umgewandelt wird, welches durch den privaten Schlüssel wunderschön in den ursprünglichen String wiederhergestellt wird.&lt;/p>
&lt;hr>
&lt;h2 id="9-fazit-die-kreuzung-von-mathematischer-schönheit-und-praktikabilität">9. Fazit: Die Kreuzung von mathematischer Schönheit und Praktikabilität
&lt;/h2>&lt;p>Als Pierre de Fermat im 17. Jahrhundert diesen &amp;ldquo;kleinen Satz&amp;rdquo; entdeckte, dachte niemand, dass er für irgendetwas nützlich sein würde. Fermat selbst betrieb zahlentheoretische Forschung aus reiner mathematischer Neugier.&lt;/p>
&lt;p>Etwa 300 Jahre später, in den 1970er Jahren, an den Anfängen von Computernetzwerken, feierte der Satz von Fermat jedoch ein dramatisches Comeback als unverzichtbare Verschlüsselungstechnologie zur Etablierung sicherer Kommunikationsprotokolle. Die Primzahltesttechnologie, die auf dem kleinen Satz von Fermat basiert, und die RSA-Verschlüsselung, die auf dem Satz von Euler basiert, stützen buchstäblich die moderne Internet-Infrastruktur.&lt;/p>
&lt;p>Die LINE-Nachrichten, die wir jeden Tag beiläufig senden, und unsere Einkäufe bei Amazon tanzen alle auf dieser einfachen und schönen Formel $a^{p-1} \equiv 1 \pmod p$. Egal wie abstrakt Mathematik ist, der kleine Satz von Fermat lehrt uns, dass immer die Zeit kommen wird, in der sie für die Menschheit nützlich sein wird.&lt;/p>
&lt;p>Beim Erlernen von Programmierung und Kryptographietheorie wird das Verständnis der zugrunde liegenden mathematischen Strukturen eine starke Waffe sein, um das Verhalten von Bibliotheken, die als Blackboxes bereitgestellt werden, tiefgreifend zu verstehen und sicherere Systeme zu entwerfen.&lt;/p></description></item><item><title>Die Riemannsche Vermutung und die Verteilung der Primzahlen: Die tiefe Verbindung zur modernen Kryptographie</title><link>http://kenji.blog/de/p/riemann-hypothesis-prime-distribution-cryptography/</link><pubDate>Fri, 11 Sep 2026 16:00:00 +0900</pubDate><guid>http://kenji.blog/de/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 Die Riemannsche Vermutung und die Verteilung der Primzahlen: Die tiefe Verbindung zur modernen Kryptographie" />&lt;h1 id="1-einleitung-das-geheimnis-des-universums-der-primzahlen-und-die-riemannsche-vermutung">1. Einleitung: Das Geheimnis des Universums der Primzahlen und die Riemannsche Vermutung
&lt;/h1>&lt;p>&amp;ldquo;Primzahlen&amp;rdquo; (Prime Numbers) sind natürliche Zahlen, die nur durch 1 und sich selbst teilbar sind, und werden auch als die &amp;ldquo;Atome&amp;rdquo; der Mathematik bezeichnet. Die Folge 2, 3, 5, 7, 11, 13&amp;hellip; scheint auf den ersten Blick unordentlich und zufällig aufzutreten. Seit der antike griechische Mathematiker Euklid bewiesen hat, dass &amp;ldquo;es unendlich viele Primzahlen gibt&amp;rdquo;, haben unzählige Mathematiker versucht, die verborgenen Gesetzmäßigkeiten in dieser Anordnung von Primzahlen zu entschlüsseln.&lt;/p>
&lt;p>Am nächsten an dieses Rätsel der Primzahlen kam die 1859 von dem deutschen Mathematiker Bernhard Riemann aufgestellte &lt;strong>&amp;ldquo;Riemannsche Vermutung&amp;rdquo; (Riemann Hypothesis)&lt;/strong> heran. Die Riemannsche Vermutung ist eines der wichtigsten und ungelösten Probleme der modernen Mathematik und als eines der Millennium-Probleme des Clay Mathematics Institute mit einem Preisgeld von einer Million Dollar dotiert.&lt;/p>
&lt;p>Auf den ersten Blick mag ein Problem der reinen Mathematik über die Verteilung von Primzahlen nichts mit unserem Alltag zu tun haben. Die Sicherheit des Internets, das die Infrastruktur der modernen Gesellschaft stützt, insbesondere &lt;strong>moderne Verschlüsselungstechnologien wie die RSA-Kryptographie und die Elliptische-Kurven-Kryptographie (ECC)&lt;/strong>, hängt jedoch stark von den Eigenschaften riesiger Primzahlen ab.&lt;/p>
&lt;p>In diesem Artikel begeben wir uns auf eine mathematische Reise von der Verteilung der Primzahlen über den Primzahlsatz und die Riemannsche Zeta-Funktion bis hin zum Kern der Riemannschen Vermutung. Wir werden extrem detailliert und tiefgreifend erklären, wie all dies mit der modernen Kryptographie verbunden ist und was mit der Welt passieren würde, wenn die Riemannsche Vermutung bewiesen werden sollte.&lt;/p>
&lt;hr>
&lt;h1 id="2-der-primzahlsatz-und-die-verteilung-der-primzahlen-die-entdeckung-von-gauss">2. Der Primzahlsatz und die Verteilung der Primzahlen: Die Entdeckung von Gauss
&lt;/h1>&lt;p>Um zu verstehen, wie Primzahlen verteilt sind, betrachteten Mathematiker die &lt;strong>Primzahlzählfunktion (Prime-counting function)&lt;/strong> $\pi(x)$, die angibt, &amp;ldquo;wie viele Primzahlen kleiner oder gleich einer bestimmten Zahl $x$ existieren&amp;rdquo;.&lt;/p>
&lt;p>Zum Beispiel:&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>Der 15-jährige geniale Mathematiker Carl Friedrich Gauss berechnete umfangreiche Primzahltabellen und fand heraus, dass die Häufigkeit des Auftretens von Primzahlen umgekehrt proportional zum natürlichen Logarithmus $\ln x$ abnimmt. Das heißt, er vermutete, dass die Wahrscheinlichkeit, eine Primzahl in der Nähe einer bestimmten Zahl $x$ zu finden, etwa $\frac{1}{\ln x}$ beträgt.&lt;/p>
&lt;p>Dies wird mit Hilfe eines Integrals als &lt;strong>Integrallogarithmus (Logarithmic integral)&lt;/strong> $\text{Li}(x)$ ausgedrückt:&lt;/p>
$$ \text{Li}(x) = \int_{2}^{x} \frac{dt}{\ln t} $$
&lt;p>Die Vermutung von Gauss wurde später 1896 von Jacques Hadamard und Charles-Jean de La Vallée Poussin unabhängig voneinander bewiesen und als &lt;strong>Primzahlsatz (Prime Number Theorem, PNT)&lt;/strong> etabliert.&lt;/p>
$$ \lim_{x \to \infty} \frac{\pi(x)}{\text{Li}(x)} = 1 $$
&lt;p>Oder näherungsweise wie folgt ausgedrückt:&lt;/p>
$$ \pi(x) \sim \frac{x}{\ln x} $$
&lt;p>Durch diesen Satz wurde klar, dass Primzahlen makroskopisch betrachtet eine sehr glatte und vorhersehbare Verteilung aufweisen. Mikroskopisch betrachtet gibt es jedoch immer einen &amp;ldquo;Fehler&amp;rdquo; oder eine &amp;ldquo;Schwankung&amp;rdquo; zwischen $\pi(x)$ und $\text{Li}(x)$. Die wahre Natur dieser Schwankung ist das größte Rätsel, das die Riemannsche Vermutung zu lösen versucht.&lt;/p>
&lt;hr>
&lt;h1 id="3-die-riemannsche-zeta-funktion-und-das-euler-produkt">3. Die Riemannsche Zeta-Funktion und das Euler-Produkt
&lt;/h1>&lt;p>Die stärkste Waffe bei der Analyse der Verteilung von Primzahlen ist die &lt;strong>Riemannsche Zeta-Funktion (Riemann Zeta Function)&lt;/strong>. Ursprünglich war es eine unendliche Reihe, die von Leonhard Euler für reelle Zahlen $s > 1$ definiert wurde.&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>Eine der größten Errungenschaften Eulers war der Beweis, dass diese unendliche Reihe als unendliches Produkt über alle Primzahlen $p$ dargestellt werden kann. Dies ist das &lt;strong>Euler-Produkt (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>Ein intuitives Verständnis des Beweises ist, dass wenn man jeden Term auf der rechten Seite als geometrische Reihe entwickelt und diese miteinander multipliziert, aufgrund des Fundamentalsatzes der Arithmetik (jede natürliche Zahl kann eindeutig als Produkt von Primzahlen dargestellt werden) die Summe der Kehrwerte der natürlichen Zahlen auf der linken Seite vollständig rekonstruiert wird.&lt;/p>
&lt;p>&lt;strong>Diese einzige Formel wurde zur Brücke zwischen der Analysis (unendliche Reihen, stetige Funktionen) und der Zahlentheorie (Primzahlen, diskrete Zahlen).&lt;/strong> Die Untersuchung der Zeta-Funktion ist gleichbedeutend mit der Untersuchung der Verteilung der Primzahlen.&lt;/p>
&lt;hr>
&lt;h1 id="4-analytische-fortsetzung-und-die-erweiterung-auf-die-komplexe-zahlenebene">4. Analytische Fortsetzung und die Erweiterung auf die komplexe Zahlenebene
&lt;/h1>&lt;p>Riemanns Genialität lag darin, dass er die Variable $s$ von $\zeta(s)$, die Euler nur für reelle Zahlen betrachtete, auf &lt;strong>komplexe Zahlen $s = \sigma + it$ ($\sigma$ ist der Realteil, $t$ ist der Imaginärteil)&lt;/strong> erweiterte.&lt;/p>
&lt;p>Die ursprüngliche unendliche Reihe konvergiert nur für $\sigma > 1$, aber Riemann nutzte eine Methode namens &amp;ldquo;analytische Fortsetzung (Analytic Continuation)&amp;rdquo;, um die Definition so zu erweitern, dass $\zeta(s)$ auf der gesamten komplexen Zahlenebene, mit Ausnahme des Pols bei $s = 1$, sinnvoll ist.&lt;/p>
&lt;p>Er leitete außerdem eine wunderschöne Funktionalgleichung (Functional equation) ab, die die Zeta-Funktion erfüllt.&lt;/p>
$$ \zeta(s) = 2^s \pi^{s-1} \sin\left(\frac{\pi s}{2}\right) \Gamma(1-s) \zeta(1-s) $$
&lt;p>Hierbei ist $\Gamma(x)$ die Gamma-Funktion. Durch diese Gleichung können wir die Eigenschaften der linken Halbebene aus den Eigenschaften der rechten Halbebene ableiten.&lt;/p>
&lt;h3 id="nullstellen-zeros-of-the-zeta-function">Nullstellen (Zeros of the Zeta Function)
&lt;/h3>&lt;p>Komplexe Zahlen $s$, für die der Wert der Zeta-Funktion 0 wird, nennt man &amp;ldquo;Nullstellen&amp;rdquo;.
Aus der Funktionalgleichung ergibt sich, dass für negative gerade Zahlen $s$ ($-2, -4, -6, \dots$) $\sin(\pi s / 2)$ zu 0 wird, also $\zeta(s) = 0$. Diese werden &lt;strong>triviale Nullstellen (Trivial zeros)&lt;/strong> genannt.&lt;/p>
&lt;p>Was jedoch für die Verteilung der Primzahlen wichtig ist, sind die anderen Nullstellen, nämlich die &lt;strong>nicht-trivialen Nullstellen (Non-trivial zeros)&lt;/strong>, die im &amp;ldquo;kritischen Streifen (Critical strip)&amp;rdquo; von $0 \le \sigma \le 1$ liegen.&lt;/p>
&lt;hr>
&lt;h1 id="5-der-kern-der-riemannschen-vermutung-und-die-explizite-formel">5. Der Kern der Riemannschen Vermutung und die explizite Formel
&lt;/h1>&lt;p>Riemann berechnete eine kleine Anzahl von Nullstellen und stellte eine erstaunliche Vermutung auf. Dies ist die &lt;strong>Riemannsche Vermutung&lt;/strong>.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Riemannsche Vermutung (Riemann Hypothesis)&lt;/strong>
Alle nicht-trivialen Nullstellen der Riemannschen Zeta-Funktion $\zeta(s)$ liegen auf der Geraden, deren Realteil $1/2$ ist ($\text{Re}(s) = 1/2$).&lt;/p>
&lt;/blockquote>
&lt;p>Diese Gerade, deren Realteil 1/2 ist, wird als &amp;ldquo;kritische Gerade (Critical line)&amp;rdquo; bezeichnet.&lt;/p>
&lt;div class="mermaid">graph TD
A["Riemannsche Zeta-Funktion ζ(s)"] --> B["Erweiterung auf die komplexe Ebene durch analytische Fortsetzung"]
B --> C["Triviale Nullstellen (s = -2, -4, -6 ...)"]
B --> D["Nicht-triviale Nullstellen (0 &lt;= Re(s) &lt;= 1)"]
D --> E["Riemannsche Vermutung"]
E --> F["Alle nicht-trivialen Nullstellen liegen auf Re(s) = 1/2"]
F --> G["Zum Beweis des Grenzwerts des Fehlerterms in der Primzahlverteilung"]&lt;/div>
&lt;p>Warum ist die Riemannsche Vermutung so wichtig? Weil die Nullstellen der Zeta-Funktion die Verteilung der Primzahlen &lt;strong>vollständig&lt;/strong> bestimmen.&lt;/p>
&lt;p>Riemann und der spätere Mathematiker von Mangoldt leiteten eine &amp;ldquo;explizite Formel (Explicit formula)&amp;rdquo; ab, die die Verteilung der Primzahlen genau beschreibt. Unter Verwendung der Tschebyschow-Funktion $\psi(x)$ lässt sie sich wie folgt ausdrücken:&lt;/p>
$$ \psi(x) = x - \sum_{\rho} \frac{x^\rho}{\rho} - \ln(2\pi) - \frac{1}{2}\ln(1 - x^{-2}) $$
&lt;p>Hierbei ist $\rho$ die Summe über alle nicht-trivialen Nullstellen der Zeta-Funktion.
Der Hauptterm ist $x$ (der dem Primzahlsatz entspricht), und durch Addition und Subtraktion von wellenartigen Termen, die von den Nullstellen $\rho$ abhängen, wird die genaue treppenförmige Verteilung der Primzahlen wiederhergestellt. Man kann sagen, dass die nicht-trivialen Nullstellen die &amp;ldquo;Frequenzen (Wellen)&amp;rdquo; der Primzahlverteilung darstellen.&lt;/p>
&lt;p>Wenn die Riemannsche Vermutung wahr ist und der Realteil aller nicht-trivialen Nullstellen $\rho$ genau $1/2$ beträgt, dann wird der Fehlerterm des Primzahlsatzes theoretisch auf den kleinstmöglichen Bereich beschränkt sein.&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>Das bedeutet: &lt;strong>Wenn die Riemannsche Vermutung wahr ist, wird bewiesen sein, dass Primzahlen auf die &amp;ldquo;regelmäßigste und schönste&amp;rdquo; Weise verteilt sind, die wir uns vorstellen können.&lt;/strong>&lt;/p>
&lt;hr>
&lt;h1 id="6-die-untrennbare-beziehung-zwischen-der-modernen-kryptographie-und-primzahlen">6. Die untrennbare Beziehung zwischen der modernen Kryptographie und Primzahlen
&lt;/h1>&lt;p>Bisher befanden wir uns in der Welt der tiefgründigen reinen Mathematik, aber diese Eigenschaften von Primzahlen stützen die moderne digitale Gesellschaft grundlegend. Der repräsentativste Vertreter dafür ist die Public-Key-Kryptographie wie die &lt;strong>RSA-Kryptographie&lt;/strong>.&lt;/p>
&lt;p>Die Sicherheit jeglicher Kommunikation, von Kreditkartenzahlungen im Internet über das Senden von Passwörtern bis hin zu digitalen Signaturen der Blockchain, hängt von &amp;ldquo;Primzahlen&amp;rdquo; ab.&lt;/p>
&lt;h3 id="funktionsweise-der-rsa-kryptographie">Funktionsweise der RSA-Kryptographie
&lt;/h3>&lt;p>Die Sicherheit der RSA-Kryptographie beruht auf der mathematischen Tatsache, dass &amp;ldquo;die Primfaktorzerlegung großer zusammengesetzter Zahlen sehr schwierig ist&amp;rdquo; (Primfaktorzerlegungsproblem).&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Schlüsselerzeugung (Key generation)&lt;/strong>:
Zwei riesige Primzahlen $p$ und $q$ (z.B. jeweils 2048 Bit) werden zufällig ausgewählt.
Sie werden miteinander multipliziert, um $N = p \times q$ zu berechnen. Dieses $N$ wird Teil des öffentlichen Schlüssels.
Unter Verwendung der Eulerschen Phi-Funktion $\phi(N) = (p-1)(q-1)$ wird der private Schlüssel $d$ generiert.&lt;/p>
$$ e \times d \equiv 1 \pmod{\phi(N)} $$
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Verschlüsselung und Entschlüsselung&lt;/strong>:
Der Klartext $M$ wird mit dem öffentlichen Schlüssel $e, N$ in einen Geheimtext $C$ umgewandelt.
&lt;/p>
$$ C \equiv M^e \pmod{N} $$
&lt;p>
Nur derjenige mit dem privaten Schlüssel $d$ kann ihn entschlüsseln.
&lt;/p>
$$ M \equiv C^d \pmod{N} $$
&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph LR
A["Klartext (Plaintext)"] --> B["Verschlüsselung mit öffentlichem Schlüssel (e, N)"]
B --> C["Geheimtext (Ciphertext)"]
C --> D["Entschlüsselung mit privatem Schlüssel (d)"]
D --> E["Ursprünglicher Klartext"]
F["Angreifer (Attacker)"] -- "Versucht die Primfaktorzerlegung von N" --> C
F -.-> G["Ohne p und q ist d unberechenbar"]&lt;/div>
&lt;p>Um die RSA-Kryptographie zu brechen, müssen aus dem riesigen $N$ die ursprünglichen Primzahlen $p$ und $q$ gefunden werden (Primfaktorzerlegung). Es wird geschätzt, dass selbst mit Supercomputern und der Verwendung derzeit gängiger Algorithmen (wie dem Zahlkörpersieb: GNFS) die Primfaktorzerlegung von Zahlen mit hunderten von Ziffern weitaus länger dauern würde als das Alter des Universums.&lt;/p>
&lt;hr>
&lt;h1 id="7-die-auswirkungen-der-riemannschen-vermutung-auf-die-kryptographie">7. Die Auswirkungen der Riemannschen Vermutung auf die Kryptographie
&lt;/h1>&lt;p>Wie kreuzen sich also die &amp;ldquo;Riemannsche Vermutung&amp;rdquo;, der Gipfel der reinen Mathematik, und die &amp;ldquo;Kryptographie&amp;rdquo;?&lt;/p>
&lt;h3 id="71-primzahlengenerierungsalgorithmen-primzahltest-und-die-erweiterte-riemannsche-vermutung-grh">7.1. Primzahlengenerierungsalgorithmen (Primzahltest) und die Erweiterte Riemannsche Vermutung (GRH)
&lt;/h3>&lt;p>Um die RSA-Kryptographie zu betreiben, müssen zuerst die riesigen Primzahlen $p$ und $q$ generiert werden. Es ist jedoch nicht einfach, zuverlässig und schnell zu bestimmen, &amp;ldquo;ob eine bestimmte Zahl eine Primzahl ist&amp;rdquo;.&lt;/p>
&lt;p>Gegenwärtig wird in der Praxis der &lt;strong>Miller-Rabin-Primzahltest (Miller-Rabin primality test)&lt;/strong>, ein probabilistischer Algorithmus, verwendet. Dieser Algorithmus ist schnell, birgt jedoch das Risiko von &amp;ldquo;Pseudoprimzahlen&amp;rdquo;, d.h., dass eine zusammengesetzte Zahl mit extrem geringer Wahrscheinlichkeit fälschlicherweise als Primzahl identifiziert wird.&lt;/p>
&lt;p>Wenn wir jedoch annehmen, dass die &lt;strong>&amp;ldquo;Erweiterte Riemannsche Vermutung&amp;rdquo; (Generalized Riemann Hypothesis, GRH)&lt;/strong>, die die Riemannsche Vermutung auf die Dirichletschen L-Funktionen erweitert, wahr ist, ändert sich die Situation dramatisch.
Wenn GRH wahr ist, wird eine obere Schranke für die Anzahl der Tests im Miller-Rabin-Verfahren mathematisch garantiert, und der probabilistische Algorithmus wird zu einem &lt;strong>&amp;ldquo;deterministischen Polynomialzeitalgorithmus&amp;rdquo; sublimiert&lt;/strong> (dies war eine wichtige Tatsache, die bereits vor der Entdeckung des AKS-Primzahltests bekannt war).&lt;/p>
&lt;p>Das heißt, die Riemannsche Vermutung (und ihre Erweiterung) spielt die Rolle einer direkten Garantie für die Generierung der Grundlage der Kryptographie: &amp;ldquo;Können riesige Primzahlen mit absoluter Zuverlässigkeit und hoher Geschwindigkeit generiert werden?&amp;rdquo;.&lt;/p>
&lt;h3 id="72-beziehung-zu-primfaktorzerlegungsalgorithmen">7.2. Beziehung zu Primfaktorzerlegungsalgorithmen
&lt;/h3>&lt;p>Bei der Bewertung der Komplexität von Algorithmen zur Entschlüsselung (wie dem Zahlkörpersieb) ist das Wissen über die Verteilung von Primzahlen ebenfalls unerlässlich. Viele Primfaktorzerlegungsalgorithmen basieren auf der Verteilung &amp;ldquo;glatter Zahlen (Smooth numbers: Zahlen, die nur kleine Primfaktoren haben)&amp;rdquo;.&lt;/p>
&lt;p>Um genau beurteilen zu können, wie oft glatte Zahlen auftreten, ist ein tiefes Verständnis der Primzahlverteilung erforderlich, und auch hier kommen Techniken der analytischen Zahlentheorie zum Einsatz, die direkt mit der Zeta-Funktion und der Riemannschen Vermutung verbunden sind. Wenn die Riemannsche Vermutung bewiesen ist und der Fehler in der Primzahlverteilung vollständig bestimmt ist, wird es möglich sein, die Leistungsgrenzen von Primfaktorzerlegungsalgorithmen genauer zu bestimmen.&lt;/p>
&lt;hr>
&lt;h1 id="8-wenn-die-riemannsche-vermutung-bewiesen-wird-wird-die-kryptographie-gebrochen">8. Wenn die Riemannsche Vermutung bewiesen wird, wird die Kryptographie gebrochen?
&lt;/h1>&lt;p>Wie eine urbane Legende wird oft erzählt: &amp;ldquo;Wenn die Riemannsche Vermutung gelöst ist, wird die RSA-Kryptographie in einem Augenblick zusammenbrechen&amp;rdquo;, aber &lt;strong>das ist mathematisch inkorrekt&lt;/strong>.&lt;/p>
&lt;p>Der Beweis der Riemannschen Vermutung selbst wird nicht sofort einen magischen Algorithmus hervorbringen, der die Primfaktorzerlegung drastisch beschleunigt. Die Riemannsche Vermutung ist nur ein Theorem über die &amp;ldquo;makroskopische Regelmäßigkeit der Verteilung&amp;rdquo; von Primzahlen und sagt uns nicht direkt, durch welche Primzahlen eine bestimmte Zahl $N$ teilbar ist (lokale Eigenschaften).&lt;/p>
&lt;p>Die Auswirkungen sind jedoch nicht null.
Es ist extrem wahrscheinlich, dass während des Prozesses des Beweises der Riemannschen Vermutung &lt;strong>&amp;ldquo;neue mathematische Werkzeuge&amp;rdquo; oder &amp;ldquo;unbekannte Analysemethoden&amp;rdquo; entdeckt werden&lt;/strong>. Die Geschichte zeigt, dass bei Beweisen wie dem Großen Fermatschen Satz oder der Poincaré-Vermutung neue Theorien entwickelt wurden, die die gesamte Mathematik maßgeblich vorangebracht haben.&lt;/p>
&lt;p>Sollten unbekannte Methoden der algebraischen Geometrie oder der nichtkommutativen Geometrie etabliert werden, die die Eigenschaften der Nullstellen der Riemannschen Zeta-Funktion vollständig manipulieren können, lässt sich nicht leugnen, dass dies zur Entdeckung eines bahnbrechenden Algorithmus zur Primfaktorzerlegung führen könnte (z.B. ein klassischer Algorithmus, der die Komplexität auf Polynomzeit reduziert). In diesem Sinne können Kryptographen ihre Augen niemals von den Entwicklungen rund um die Riemannsche Vermutung abwenden.&lt;/p>
&lt;h3 id="quantencomputer-und-shors-algorithmus">Quantencomputer und Shors Algorithmus
&lt;/h3>&lt;p>Eine direktere und realistischere Bedrohung für die Kryptographie ist nicht der Beweis der Riemannschen Vermutung, sondern &lt;strong>Quantencomputer&lt;/strong>. Der 1994 von Peter Shor veröffentlichte &amp;ldquo;Shor-Algorithmus&amp;rdquo; bewies, dass ein Quantencomputer mit ausreichender Leistung die Primfaktorzerlegung in Polynomzeit lösen kann. Dies würde die RSA-Kryptographie und die Elliptische-Kurven-Kryptographie grundlegend brechen.&lt;/p>
&lt;p>Derzeit wird weltweit der Übergang zur &amp;ldquo;Post-Quanten-Kryptographie (Post-Quantum Cryptography, PQC)&amp;rdquo; (wie gitterbasierte Kryptographie) vorangetrieben, die selbst von Quantencomputern nicht geknackt werden kann. Die von Primzahlen abhängige Kryptographie könnte in gewissem Sinne ihr goldenes Zeitalter beenden, aber der mathematische Wert der Primzahlen selbst wird niemals verloren gehen.&lt;/p>
&lt;hr>
&lt;h1 id="9-fazit-die-kreuzung-von-mathematischer-abstraktion-und-der-realen-gesellschaft">9. Fazit: Die Kreuzung von mathematischer Abstraktion und der realen Gesellschaft
&lt;/h1>&lt;div class="mermaid">graph TD
A["Erforschung der reinen Mathematik"] --> B["Aufklärung der Riemannschen Vermutung"]
B --> C["Vollständiges Verständnis der Primzahlverteilung"]
C --> D["Sprunghafte Entwicklung der Zahlentheorie und algebraischen Geometrie"]
D -.-> E["Möglichkeit neuer Primfaktorzerlegungsalgorithmen"]
E -.-> F["Aktualisierung der Sicherheitsbewertung von Kryptographie"]
A --> G["Angewandte Mathematik / Informatik"]
G --> H["Effizienzsteigerung bei Primzahltests und Schlüsselgenerierung"]
H --> F&lt;/div>
&lt;p>Die unersättliche Suche nach Primzahlen, die in der griechischen Antike begann, wurde von dem Genie Riemann in eine wunderschöne Sinfonie (die Nullstellen der Zeta-Funktion) auf der komplexen Ebene sublimiert. Erstaunlicherweise wird dieser reine Kristall der Mathematik Jahrhunderte später als der stärkste Schild zum Schutz der Sicherheit der Internetgesellschaft angewendet.&lt;/p>
&lt;p>Die Riemannsche Vermutung ist eine Existenz, die gleichzeitig die &amp;ldquo;abstrakte Schönheit&amp;rdquo; der Mathematik und ihre &amp;ldquo;erstaunliche Anwendbarkeit in der physischen Welt und der realen Gesellschaft&amp;rdquo; symbolisiert.&lt;/p>
&lt;p>Wenn dieser riesige mathematische Berg, dessen Gipfel noch niemand erreicht hat, eines Tages bezwungen wird, werden wir die Wahrheit des Universums der Primzahlen vollständig verstehen und eine neue Perspektive auf die Grundlagen der Informationsgesellschaft gewinnen. Das Studium der Kryptographie ist auch eine Reise, die die Geschichte der menschlichen Weisheit nachzeichnet.&lt;/p></description></item><item><title>Schneller Primzahltest-Algorithmus in C++ implementiert (Miller-Rabin-Methode usw.)</title><link>http://kenji.blog/de/p/cpp-fast-prime-testing-miller-rabin/</link><pubDate>Fri, 11 Sep 2026 14:00:00 +0900</pubDate><guid>http://kenji.blog/de/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 Schneller Primzahltest-Algorithmus in C++ implementiert (Miller-Rabin-Methode usw.)" />&lt;h1 id="einleitung-warum-brauchen-wir-schnelle-primzahltests">Einleitung: Warum brauchen wir schnelle Primzahltests?
&lt;/h1>&lt;p>In der Informatik, der Kryptographie und im Bereich der kompetitiven Programmierung ist die schnelle und genaue Bestimmung, &amp;ldquo;ob eine gegebene Zahl prim ist&amp;rdquo;, eine sehr wichtige und grundlegende Aufgabe. Zum Beispiel beruht die Sicherheit von Public-Key-Kryptosystemen wie RSA, die die Grundlage der heutigen Internetsicherheit bilden, auf der Erzeugung riesiger Primzahlen und der Schwierigkeit ihrer Multiplikation (bzw. der Schwierigkeit der Primfaktorzerlegung). Daher ist es keine Übertreibung zu sagen, dass die Technologie zur sofortigen Identifizierung riesiger Primzahlen das Rückgrat unserer digitalen Gesellschaft bildet.&lt;/p>
&lt;p>Auch beim kompetitiven Programmieren (wie AtCoder oder Codeforces) sind Primzahltests ein häufiges Thema. Wenn für riesige Eingaben mit Beschränkungen wie $N \le 10^{18}$ Zehntausende von Primzahltests in weniger als 1 Sekunde durchgeführt werden müssen, werden traditionelle, naive Algorithmen das Zeitlimit (Time Limit Exceeded: TLE) niemals einhalten.&lt;/p>
&lt;p>In diesem Artikel werden wir von naiven Primzahltests über den &amp;ldquo;Fermat-Test&amp;rdquo;, einen probabilistischen Algorithmus, bis hin zum &amp;ldquo;Miller-Rabin-Primzahltest&amp;rdquo;, einem Hochgeschwindigkeitsalgorithmus auf praktisch höchstem Niveau, der die Schwächen des Fermat-Tests überwindet, alles ausführlich erklären – vom mathematischen Hintergrund bis hin zu einer hochgradig optimierten Implementierung in C++. Insbesondere für 64-Bit-Ganzzahlen ($N &lt; 2^{64}$) werden wir nicht nur auf probabilistische Tests eingehen, sondern auch &amp;ldquo;100% sichere Primzahltests (deterministische Tests)&amp;rdquo; detailliert beschreiben und einen C++-Quellcode bereitstellen, der direkt in der Praxis verwendet werden kann.&lt;/p>
&lt;hr>
&lt;h1 id="1-grundlagen-der-primzahltests-und-probedivision-trial-division">1. Grundlagen der Primzahltests und Probedivision (Trial Division)
&lt;/h1>&lt;p>Eine Primzahl (Prime number) ist eine natürliche Zahl größer als 1, die außer 1 und sich selbst keine positiven Teiler hat. Folgt man strikt der Definition einer Primzahl, kann man feststellen, ob eine ganze Zahl $N$ eine Primzahl ist, indem man $N$ durch alle ganzen Zahlen von $2$ bis $N-1$ dividiert. Wenn sie durch keine dieser Zahlen teilbar ist, ist sie prim, andernfalls ist sie eine zusammengesetzte Zahl (keine Primzahl).&lt;/p>
&lt;p>Diese Methode hat jedoch eine Zeitkomplexität von $O(N)$. Wenn $N$ eine riesige Zahl wie $10^{18}$ ist, würde selbst ein moderner Computer enorm viel Zeit für die Berechnung benötigen.&lt;/p>
&lt;h2 id="optimierung-der-probedivision-suche-bis-sqrtn">Optimierung der Probedivision: Suche bis $\sqrt{N}$
&lt;/h2>&lt;p>Wenn eine zusammengesetzte Zahl $N$ als $a \times b = N$ (mit $a \le b$) dargestellt wird, gilt immer $a \le \sqrt{N}$. Daher ist es nicht notwendig, die Schleife für den Primzahltest bis $N-1$ laufen zu lassen; es reicht aus, bis $\sqrt{N}$ zu prüfen.&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">// Primzahltest durch Probedivision (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">// Nur ungerade Zahlen ab 3 prüfen
&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>Die Zeitkomplexität dieses Algorithmus beträgt $O(\sqrt{N})$. Für $N \le 10^{12}$ kann die Berechnung im Bruchteil einer Sekunde durchgeführt werden. Bei $N \approx 10^{18}$ beträgt die Anzahl der Schleifendurchläufe jedoch etwa $10^9$, was selbst in C++ Hunderte von Millisekunden bis zu mehreren Sekunden dauert und somit für mehrfache Tests ungeeignet ist.&lt;/p>
&lt;hr>
&lt;h1 id="2-fermat-test-der-beginn-der-probabilistischen-primzahltests">2. Fermat-Test: Der Beginn der probabilistischen Primzahltests
&lt;/h1>&lt;p>Um die Grenzen der Probedivision zu überwinden, wurden &amp;ldquo;probabilistische Algorithmen (Probabilistic Algorithm)&amp;rdquo; entwickelt, die zahlentheoretische Theoreme nutzen. Ein typisches Beispiel ist der &amp;ldquo;Fermat-Primzahltest (Fermat Primality Test)&amp;rdquo;, der den kleinen Fermatschen Satz anwendet.&lt;/p>
&lt;h2 id="kleiner-fermatscher-satz-fermats-little-theorem">Kleiner Fermatscher Satz (Fermat&amp;rsquo;s Little Theorem)
&lt;/h2>&lt;p>Dieser von Pierre de Fermat entdeckte Satz besagt Folgendes:&lt;/p>
&lt;blockquote>
&lt;p>Für jede Primzahl $p$ und jede beliebige ganze Zahl $a$, die teilerfremd zu $p$ ist (kein Vielfaches von $p$), gilt die folgende Kongruenz:
&lt;/p>
$$ a^{p-1} \equiv 1 \pmod p $$
&lt;/blockquote>
&lt;p>Die Kontraposition dieses Satzes besagt: &amp;ldquo;Wenn für eine ganze Zahl $N$ und eine zu $N$ teilerfremde ganze Zahl $a$ gilt $a^{N-1} \not\equiv 1 \pmod N$, dann ist $N$ definitiv eine zusammengesetzte Zahl.&amp;rdquo; Der Fermat-Test nutzt diese Eigenschaft, indem er für die zu testende Zahl $N$ eine zufällige Basis (base) $a$ wählt und überprüft, ob $a^{N-1} \pmod N$ den Wert $1$ ergibt.&lt;/p>
&lt;h2 id="schnelle-modulare-exponentiation-binäre-exponentiation">Schnelle modulare Exponentiation (Binäre Exponentiation)
&lt;/h2>&lt;p>Um den Fermat-Test durchzuführen, müssen wir die riesige Potenz $a^{N-1} \pmod N$ schnell berechnen. Hierfür wird die &amp;ldquo;Binäre Exponentiation (Modular Exponentiation / Binary Exponentiation)&amp;rdquo; verwendet. Die Zeitkomplexität beträgt $O(\log N)$ und ist damit extrem schnell.&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">// Berechnung von a^b mod m mittels binärer Exponentiation
&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>Hier verwenden wir zur Vermeidung von Überläufen &lt;code>__int128_t&lt;/code> (eine 128-Bit-Ganzzahl), eine Erweiterung von GCC/Clang, um Zwischenprodukte zu speichern.&lt;/li>
&lt;/ul>
&lt;h2 id="pseudoprimzahlen-und-carmichael-zahlen-carmichael-numbers">Pseudoprimzahlen und Carmichael-Zahlen (Carmichael Numbers)
&lt;/h2>&lt;p>Der Fermat-Test ist sehr mächtig, hat jedoch eine fatale Schwäche. Es gibt Zahlen $N$, die zusammengesetzt sind, für die aber dennoch $a^{N-1} \equiv 1 \pmod N$ für alle $a$ (die zu $N$ teilerfremd sind) gilt.&lt;/p>
&lt;p>Solche Zahlen werden &amp;ldquo;absolute Pseudoprimzahlen&amp;rdquo; oder &amp;ldquo;Carmichael-Zahlen&amp;rdquo; genannt. Die kleinste Carmichael-Zahl ist $561 = 3 \times 11 \times 17$.
Aufgrund der Existenz von Carmichael-Zahlen kann der Fermat-Test allein keine 100%ige Sicherheit (deterministischer Test) bieten. Egal wie viele verschiedene $a$ man probiert, Zahlen wie $561$ werden immer so tun, als wären sie Primzahlen.&lt;/p>
&lt;hr>
&lt;h1 id="3-miller-rabin-primzahltest-miller-rabin-primality-test">3. Miller-Rabin-Primzahltest (Miller-Rabin Primality Test)
&lt;/h1>&lt;p>Die Schwäche des Fermat-Tests (die Existenz von Carmichael-Zahlen) wurde von Gary L. Miller und Michael O. Rabin mit dem &amp;ldquo;Miller-Rabin-Primzahltest&amp;rdquo; brillant überwunden.
Heute wird er am häufigsten als praktischer, schneller Primzahltest-Algorithmus in internen Bibliotheken verschiedener Programmiersprachen und bei der Schlüsselgenerierung in Kryptosystemen verwendet.&lt;/p>
&lt;h2 id="mathematisches-prinzip">Mathematisches Prinzip
&lt;/h2>&lt;p>Der Miller-Rabin-Algorithmus nutzt zusätzlich zum kleinen Fermatschen Satz die Eigenschaft, dass &amp;ldquo;in einem Restklassenkörper modulo einer Primzahl ($\mathbb{Z}/p\mathbb{Z}$) die einzigen Lösungen von $x^2 \equiv 1 \pmod p$ die Werte $x \equiv 1$ oder $x \equiv -1$ sind&amp;rdquo; (bei einer zusammengesetzten Zahl als Modul können auch andere nicht-triviale Quadratwurzeln existieren).&lt;/p>
&lt;p>Zieht man $1$ von einer zu testenden ungeraden Zahl $N$ ab, ist $N-1$ immer gerade. Daher teilen wir $N-1$ so oft wie möglich durch $2$ und schreiben es in der folgenden Form:
&lt;/p>
$$ N-1 = d \cdot 2^s $$
&lt;p>
(Wobei $d$ ungerade ist und $s \ge 1$)&lt;/p>
&lt;p>Für eine beliebige Basis $a$ ($1 &lt; a &lt; N-1$) prüfen wir gemäß dem kleinen Fermatschen Satz, ob $a^{N-1} \equiv 1 \pmod N$ gilt, führen diese Berechnung jedoch schrittweise durch.
Konkret wiederholen wir die Quadrierung in der Reihenfolge $a^d, a^{d \cdot 2}, a^{d \cdot 4}, \ldots, a^{d \cdot 2^s}$.&lt;/p>
&lt;p>Die Bedingung dafür, dass der Miller-Rabin-Test $N$ als &amp;ldquo;prim (oder mit hoher Wahrscheinlichkeit prim)&amp;rdquo; einstuft, ist, dass &lt;strong>eine&lt;/strong> der folgenden Aussagen wahr ist:&lt;/p>
&lt;ol>
&lt;li>$a^d \equiv 1 \pmod N$&lt;/li>
&lt;li>Es gibt ein $r$ ($0 \le r &lt; s$), für das gilt: $a^{d \cdot 2^r} \equiv -1 \pmod N$.
&lt;ul>
&lt;li>In C++ Modulo-Arithmetik wird $-1 \pmod N$ als $N-1$ dargestellt.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>Wenn $N$ eine Primzahl ist, ist diese Bedingung für jedes beliebige $a$ immer erfüllt. Umgekehrt ist mathematisch bewiesen, dass, wenn $N$ eine zusammengesetzte Zahl ist und ein zufälliges $a$ gewählt wird, die Wahrscheinlichkeit, dass diese Bedingung erfüllt ist (die Wahrscheinlichkeit, getäuscht zu werden), höchstens $\frac{1}{4}$ beträgt.
Führt man $k$ unabhängige Tests durch, sinkt die Wahrscheinlichkeit eines falschen Ergebnisses auf höchstens $\left(\frac{1}{4}\right)^k$, was für die Praxis als null betrachtet werden kann. Es gibt keine &amp;ldquo;absolut täuschenden&amp;rdquo; Zahlen wie Carmichael-Zahlen mehr.&lt;/p>
&lt;h2 id="ablauf-des-miller-rabin-algorithmus-mermaid-flussdiagramm">Ablauf des Miller-Rabin-Algorithmus (Mermaid-Flussdiagramm)
&lt;/h2>&lt;p>Das folgende Diagramm zeigt den logischen Ablauf eines einzelnen Miller-Rabin-Primzahltests (für eine Basis $a$).&lt;/p>
&lt;div class="mermaid">graph TD
Start["Teststart (Eingabe: N, a)"] --> CalcDS["Berechne ungerades d und s für N-1 = d * 2^s"]
CalcDS --> CalcX["Berechne x = a^d mod N"]
CalcX --> CheckX1{"x == 1 oder x == N-1 ?"}
CheckX1 -- "Yes" --> ReturnTrue["Möglicherweise prim (Probably Prime)"]
CheckX1 -- "No" --> LoopStart["Schleifenstart von r = 1 bis s-1"]
LoopStart --> LoopCondition{"r &lt; s ?"}
LoopCondition -- "No" --> ReturnFalse["Definitiv zusammengesetzt (Composite)"]
LoopCondition -- "Yes" --> SquareX["Berechne x = (x * x) mod N"]
SquareX --> CheckXMinus1{"x == N - 1 ?"}
CheckXMinus1 -- "Yes" --> ReturnTrue
CheckXMinus1 -- "No" --> CheckXOne{"x == 1 ?"}
CheckXOne -- "Yes" --> ReturnFalse
CheckXOne -- "No" --> LoopNext["Erhöhe r um 1 und weiter"]
LoopNext --> LoopCondition&lt;/div>
&lt;hr>
&lt;h1 id="4-deterministischer-test-für-64-bit-ganzzahlen">4. Deterministischer Test für 64-Bit-Ganzzahlen
&lt;/h1>&lt;p>Der Miller-Rabin-Primzahltest ist ursprünglich ein &amp;ldquo;probabilistischer&amp;rdquo; Algorithmus, aber wenn die Obergrenze von $N$ feststeht, kann man &amp;ldquo;100% deterministisch&amp;rdquo; auf eine Primzahl testen, indem man bestimmte Mengen von $a$ (Basen) ausprobiert.
Dies wird als &lt;strong>Deterministischer Miller-Rabin-Test (Deterministic Miller-Rabin Test)&lt;/strong> bezeichnet.&lt;/p>
&lt;p>Durch Forschungen von Jim Sinclair und anderen wurde herausgefunden, dass für alle ganzen Zahlen $N &lt; 2^{64}$ (ca. $1.8 \times 10^{19}$) ein vollständig deterministischer Test möglich ist, indem man die folgenden $7$ Primzahlen als Basis $a$ wählt und testet.&lt;/p>
&lt;p>&lt;strong>Liste der zu testenden Basen $a$:&lt;/strong>
&lt;code>{2, 325, 9375, 28178, 450775, 9780504, 1795265022}&lt;/code>&lt;/p>
&lt;p>Alternativ kann man eine andere bekannte Menge von $12$ Primzahlen verwenden, um Zahlen bis $N &lt; 2^{64}$ perfekt zu testen.
&lt;code>{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}&lt;/code>&lt;/p>
&lt;p>Um die Einfachheit und Zuverlässigkeit des Algorithmus zu erhöhen, werden wir diesmal die Methode mit den $12$ Primzahlen (oder die optimierteren $7$ Basen) übernehmen. Bei der C++-Implementierung optimieren wir den Prozess, indem wir die Anzahl der Tests basierend auf Größenbereichen durch Verzweigungen minimieren.&lt;/p>
&lt;hr>
&lt;h1 id="5-hochgradig-optimierte-implementierung-in-c-highly-optimized-c-implementation">5. Hochgradig optimierte Implementierung in C++ (Highly Optimized C++ Implementation)
&lt;/h1>&lt;p>Nun fassen wir die mathematische Theorie und den Entwurf des Algorithmus zusammen und präsentieren den Implementierungscode für eine der stärksten Miller-Rabin-Primzahltest-Funktionen im modernen C++.&lt;/p>
&lt;h2 id="punkte-zur-implementierung">Punkte zur Implementierung
&lt;/h2>&lt;ol>
&lt;li>
&lt;p>&lt;strong>Vermeidung von Überläufen bei der 64-Bit-Ganzzahl-Multiplikation:&lt;/strong>
Wenn $N \approx 10^{18}$, kann $x \times x$ bei der Modulo-Multiplikation bis zu $10^{36}$ erreichen und den Maximalwert einer regulären 64-Bit-Ganzzahl (&lt;code>uint64_t&lt;/code> oder &lt;code>long long&lt;/code>) von $1.8 \times 10^{19}$ leicht überlaufen lassen.
Um dieses Problem zu lösen, verwenden wir &lt;code>__int128_t&lt;/code> (oder &lt;code>unsigned __int128&lt;/code>), einen Erweiterungstyp von GCC und Clang, führen die Berechnung mit 128-Bit-Genauigkeit durch und wenden dann Modulo an. So sind schnelle modulare Multiplikationen ohne komplexe Algorithmen möglich.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Auswahl deterministischer Basen:&lt;/strong>
Ist der Wert von $N$ klein, optimieren wir dies, sodass nur wenige Basen getestet werden müssen.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h2 id="vollständiger-c-quellcode">Vollständiger C++ Quellcode
&lt;/h2>&lt;p>Hier ist der fertige, praxistaugliche Quellcode. Dieser Code kann für Umgebungen wie kompetitives Programmieren direkt kopiert und verwendet werden.&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">// Schnelle Berechnung von (a * b) mod m mit 128-Bit-Ganzzahlen
&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">// Berechnung von (base^exp) mod m mittels binärer Exponentiation
&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">// Deterministischer Miller-Rabin-Primzahltest für 64-Bit-Ganzzahlen
&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">// Vorabprüfung von Randwerten und kleinen Primzahlen
&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">// Zerlegung in die Form 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 der für den Test verwendeten Basen (bases)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// Optimierung zur Minimierung der Anzahl der zu testenden Basen je nach Größe von 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 Basen, die für alle Zahlen N &amp;lt; 2^64 deterministisch sind
&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">// Test für jede Basis durchführen
&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">// Ist a ein Vielfaches von n, ist der Test nicht anwendbar, aber n keine Primzahl
&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">// Erste Bedingung erfüllt, zur nächsten Basis
&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">// Schleife s-1 mal ausführen (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">// Zweite Bedingung erfüllt, möglicherweise prim
&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">// Wenn keine Bedingung erfüllt ist, ist sie definitiv zusammengesetzt
&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">// Wenn alle Basen die Bedingungen erfüllen, ist die Zahl definitiv eine Primzahl
&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">// Testbeispiele
&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">// Bekannte Primzahl
&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">// Bekannte Primzahl
&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">// Primzahl im Bereich von 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">// Zusammengesetzte Zahl (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">// Carmichael-Zahl (zusammengesetzt)
&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">// Eine der größten Primzahlen nahe 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-zeitkomplexität-des-algorithmus-und-leistungsbewertung">6. Zeitkomplexität des Algorithmus und Leistungsbewertung
&lt;/h1>&lt;p>Lassen Sie uns die Leistung des implementierten Algorithmus analysieren.&lt;/p>
&lt;h2 id="zeitkomplexität-time-complexity">Zeitkomplexität (Time Complexity)
&lt;/h2>&lt;ul>
&lt;li>&lt;strong>Probedivision:&lt;/strong> $O(\sqrt{N})$&lt;/li>
&lt;li>&lt;strong>Fermat-Test:&lt;/strong> Exponentiation $O(\log N) \times k$ (wobei $k$ die Anzahl der Versuche ist)&lt;/li>
&lt;li>&lt;strong>Miller-Rabin-Test:&lt;/strong> Exponentiation und Schleife $O(\log N) \times k$&lt;/li>
&lt;/ul>
&lt;p>In einer 64-Bit-Umgebung ($N \le 2^{64}$) prüft die oben beschriebene deterministische Miller-Rabin-Methode maximal $7$ Basen. Daher kann $k \le 7$ als Konstante betrachtet werden, und die gesamte Zeitkomplexität ist streng genommen $O(\log N)$.
Selbst im größten Fall ($N \approx 10^{19}$) passt die Anzahl der Ausführungsschritte in höchstens $7 \times 64 = 448$ elementare Operationen, und die Ausführungszeit beträgt wenige Mikrosekunden ($10^{-6}$ Sekunden) oder weniger. Im Vergleich zur Zeitkomplexität der Probedivision von $O(\sqrt{N})$ (Schleifendurchläufe $\approx 4 \times 10^9$) wurde eine &lt;strong>Beschleunigung um das Millionenfache&lt;/strong> erreicht.&lt;/p>
&lt;h2 id="weitere-optimierung-montgomery-multiplikation-montgomery-multiplication">Weitere Optimierung: Montgomery-Multiplikation (Montgomery Multiplication)
&lt;/h2>&lt;p>Die Implementierung in diesem Artikel verwendet den 128-Bit-Erweiterungstyp &lt;code>__int128_t&lt;/code> für die Division (Modulo-Operation &lt;code>%&lt;/code>). Selbst auf modernen CPUs ist die Ganzzahldivision (DIV-Befehl) ein teurer Befehl, der dutzende von Zyklen erfordert, weit mehr als Addition oder Multiplikation.&lt;/p>
&lt;p>Bibliotheksersteller und wettbewerbsorientierte Programmierer, die nach extremer Optimierung streben, verwenden oft eine Technik namens &lt;strong>Montgomery-Multiplikation (Montgomery Multiplication)&lt;/strong>. Die Montgomery-Multiplikation ist ein verblüffender Algorithmus, der Zahlen in einen speziellen &amp;ldquo;Montgomery-Raum&amp;rdquo; abbildet und so hochgradig kostspielige Modulo-Operationen (Division) durch &amp;ldquo;nur Bitverschiebungen und Multiplikationen&amp;rdquo; ersetzt.
Durch die Integration dieser Technik in die modulare Multiplikation des Miller-Rabin-Tests kann die Ausführungsgeschwindigkeit weiter verdoppelt oder verdreifacht werden. Da dies ein sehr tiefes Thema ist, werde ich es in einem separaten Artikel ausführlich behandeln.&lt;/p>
&lt;hr>
&lt;h1 id="7-zusammenfassung">7. Zusammenfassung
&lt;/h1>&lt;p>In diesem Artikel haben wir von den Grundlagen der Primzahltests bis hin zu fortgeschrittenen Themen alles behandelt.
Fassen wir die wichtigsten Punkte zusammen:&lt;/p>
&lt;ol>
&lt;li>Die &lt;strong>Probedivision&lt;/strong> ist zuverlässig, hat aber eine Zeitkomplexität von $O(\sqrt{N})$, was sie für $N > 10^{12}$ unpraktisch macht.&lt;/li>
&lt;li>Der &lt;strong>Fermat-Test&lt;/strong> ist mit $O(\log N)$ sehr schnell, hat aber die fatale Schwäche, von absoluten Pseudoprimzahlen wie Carmichael-Zahlen getäuscht zu werden.&lt;/li>
&lt;li>Der &lt;strong>Miller-Rabin-Primzahltest&lt;/strong> ist ein praktischer, extrem starker Algorithmus, der die Schwäche des Fermat-Tests beseitigt.&lt;/li>
&lt;li>Bei der C++ Implementierung kann man den Erweiterungstyp &lt;code>__int128_t&lt;/code> nutzen, um Überläufe bei der Multiplikation von 64-Bit-Ganzzahlen sicher zu handhaben.&lt;/li>
&lt;li>Im Bereich der 64-Bit-Ganzzahlen ($N &lt; 2^{64}$) können Primzahltests &lt;strong>deterministisch (100% genau)&lt;/strong> durchgeführt werden, anstatt nur probabilistisch, indem $7$ oder $12$ spezifische Primzahlen als Basis gewählt werden.&lt;/li>
&lt;/ol>
&lt;p>Schnelle Primzahltests sind eine unverzichtbare Technologie beim Rechnen mit riesigen Zahlen. Der hier vorgestellte C++-Quellcode für den Miller-Rabin-Test ist robust und kann direkt in der Praxis eingesetzt werden. Bitte probieren Sie ihn in Ihren eigenen Projekten oder bei Algorithmen-Wettbewerben aus!&lt;/p>
&lt;div class="mermaid">graph LR
TrialDivision["Probedivision (O(√N))"] --> Fermat["Fermat-Test (O(log N), hat Schwächen)"]
Fermat --> MillerRabin["Miller-Rabin-Test (O(log N), deterministisch möglich)"]
MillerRabin --> Montgomery["+ Montgomery-Multiplikation (Schneller um einen konstanten Faktor)"]
style MillerRabin fill:#f9f,stroke:#333,stroke-width:2px&lt;/div>
&lt;p>Die Welt der Algorithmen, in der sich Programmierung und Mathematik kreuzen, ist unglaublich schön und tiefgründig. Ich hoffe, dieser Artikel hilft Ihnen beim weiteren Lernen.&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>【Mathematik-Erklärung】Wie RSA-Verschlüsselung funktioniert, verständlich für Schüler erklärt</title><link>http://kenji.blog/de/p/rsa-encryption-math-explained-for-beginners/</link><pubDate>Fri, 11 Sep 2026 13:00:00 +0900</pubDate><guid>http://kenji.blog/de/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 【Mathematik-Erklärung】Wie RSA-Verschlüsselung funktioniert, verständlich für Schüler erklärt" />&lt;p>Eine der Technologien, die die Sicherheit der Internetgesellschaft grundlegend unterstützt, ist die „RSA-Verschlüsselung“. Viele der Kommunikationen, die wir jeden Tag beiläufig nutzen, wie Kreditkartenzahlungen beim Online-Shopping, der Austausch mit Freunden auf sozialen Netzwerken und das Senden und Empfangen vertraulicher Unternehmensinformationen, werden durch diese RSA-Verschlüsselung und ihre Nachfolgetechnologien geschützt.&lt;/p>
&lt;p>Wenn man jedoch das Wort „Verschlüsselung“ hört, stellt man sich vielleicht komplexe Chiffriermaschinen wie in Spionagefilmen vor oder extrem fortgeschrittene Mathematik, die nur einige wenige Genies verstehen können. Es stimmt zwar, dass die moderne Kryptographie auf fortgeschrittener Mathematik basiert, aber &lt;strong>die grundlegende Funktionsweise der RSA-Verschlüsselung kann mit dem Wissen aus der Schulmathematik (Eigenschaften von ganzen Zahlen, Primzahlen, Kongruenzen usw.) gut verstanden werden&lt;/strong>.&lt;/p>
&lt;p>In diesem Artikel erklären wir ausgehend vom Wissen der Schulmathematik Schritt für Schritt, nach welchen mathematischen Prinzipien die RSA-Verschlüsselung funktioniert und warum sie so schwer zu knacken ist. Wir werden es anhand konkreter Beispiele sorgfältig erklären, so dass auch diejenigen es verstehen können, die in Mathematik vielleicht nicht so stark sind.&lt;/p>
&lt;hr>
&lt;h2 id="1-symmetrische-verschlüsselung-und-asymmetrische-verschlüsselung-public-key-verschlüsselung">1. Symmetrische Verschlüsselung und asymmetrische Verschlüsselung (Public-Key-Verschlüsselung)
&lt;/h2>&lt;p>Bevor wir uns mit den mathematischen Mechanismen der RSA-Verschlüsselung befassen, lassen Sie uns zunächst die Grundkonzepte der Kryptographie klären. Verschlüsselungsverfahren lassen sich grob in zwei Arten unterteilen: die „symmetrische Verschlüsselung“ und die „asymmetrische Verschlüsselung“ (Public-Key-Kryptographie).&lt;/p>
&lt;h3 id="11-die-grenzen-der-symmetrischen-verschlüsselung">1.1 Die Grenzen der symmetrischen Verschlüsselung
&lt;/h3>&lt;p>Viele der seit langem verwendeten Verschlüsselungen sind sogenannte „symmetrische Verschlüsselungsverfahren“. Bei dieser Methode wird &lt;strong>für die „Verschlüsselung“ (die Umwandlung einer Nachricht in einen geheimen Geheimtext) und die „Entschlüsselung“ (die Wiederherstellung der ursprünglichen Nachricht aus dem Geheimtext) derselbe Schlüssel verwendet&lt;/strong>.&lt;/p>
&lt;p>Nehmen wir zum Beispiel an, Alice möchte Bob einen geheimen Brief schicken. Alice legt den Brief in eine Kiste und verschließt diese mit einem Vorhängeschloss (dem symmetrischen Schlüssel). Damit Bob diese Kiste öffnen kann, muss er denselben Schlüssel besitzen, den auch Alice benutzt hat.&lt;/p>
&lt;p>Dieses System hat ein großes Problem: das „Schlüsselaustauschproblem“. Wenn Alice und Bob, die weit voneinander entfernt sind, zum ersten Mal kommunizieren, wie können sie dann einen Schlüssel teilen, ohne abgehört zu werden? Wenn der Schlüssel auf dem Postweg von einem Dritten gestohlen wird, ist die gesamte nachfolgende verschlüsselte Kommunikation für diesen einsehbar.&lt;/p>
&lt;h3 id="12-die-bahnbrechende-erfindung-der-asymmetrischen-verschlüsselung">1.2 Die bahnbrechende Erfindung der „asymmetrischen Verschlüsselung“
&lt;/h3>&lt;p>Um dieses Schlüsselaustauschproblem zu lösen, wurde die „asymmetrische Verschlüsselung“ erfunden. Die RSA-Verschlüsselung ist eine Form davon.&lt;/p>
&lt;p>Bei der asymmetrischen Verschlüsselung werden &lt;strong>zwei unterschiedliche Schlüssel verwendet: ein „Schlüssel zum Verschlüsseln (öffentlicher Schlüssel)“ und ein „Schlüssel zum Entschlüsseln (privater Schlüssel)“&lt;/strong>.&lt;/p>
&lt;ol>
&lt;li>Der Empfänger Bob erstellt ein Paar aus „öffentlichem Schlüssel“ und „privatem Schlüssel“.&lt;/li>
&lt;li>Bob veröffentlicht den „öffentlichen Schlüssel“ für die ganze Welt (es spielt keine Rolle, wer ihn bekommt).&lt;/li>
&lt;li>Die Senderin Alice verschlüsselt ihre Nachricht mit Bobs „öffentlichem Schlüssel“ und sendet sie ab.&lt;/li>
&lt;li>Die verschlüsselte Nachricht kann nur mit dem „privaten Schlüssel“, den nur Bob besitzt, entschlüsselt werden.&lt;/li>
&lt;/ol>
&lt;p>Um dies mit einem Vorhängeschloss zu vergleichen: Bob stellt viele „offene Vorhängeschlösser (öffentliche Schlüssel)“ her und verteilt sie in der ganzen Welt. Alice legt eine Nachricht für Bob in eine Kiste und verschließt sie mit einem gefundenen Vorhängeschloss von Bob. Sobald das Vorhängeschloss geschlossen ist, kann es nur noch mit dem „Generalschlüssel (privater Schlüssel)“ geöffnet werden, den Bob besitzt. Selbst wenn jemand unterwegs die Kiste stiehlt, kann er sie ohne den Generalschlüssel nicht öffnen.&lt;/p>
&lt;div class="mermaid">graph TD
A["Alice (Senderin)"] --> B["Klartext (Nachricht)"]
B --> C["Verschlüsselungsprozess"]
D["Bobs öffentlicher Schlüssel (für jeden zugänglich)"] --> C
C --> E["Versand über das Internet: Geheimtext"]
E --> F["Entschlüsselungsprozess"]
G["Bobs privater Schlüssel (nur Bob hat ihn)"] --> F
F --> H["Wiederhergestellter Klartext (Nachricht)"]
H --> I["Bob (Empfänger)"]&lt;/div>
&lt;p>Um dieses revolutionäre System zu realisieren, ist eine Art &lt;strong>„Einwegfunktion (ein mathematisches Einbahnstraßen-Rätsel)“&lt;/strong> erforderlich, die es erlaubt, „mit dem öffentlichen Schlüssel leicht zu verschlüsseln, aber ohne den privaten Schlüssel absolut nicht zu entschlüsseln“. Als Bestandteil dieses Rätsels richtete man die Aufmerksamkeit auf etwas, das wir gut kennen: „Primzahlen“.&lt;/p>
&lt;hr>
&lt;h2 id="2-mathematische-grundlagen-der-rsa-verschlüsselung-teil-1-primzahlen-und-primfaktorzerlegung">2. Mathematische Grundlagen der RSA-Verschlüsselung Teil 1: Primzahlen und Primfaktorzerlegung
&lt;/h2>&lt;p>Die Sicherheit der RSA-Verschlüsselung basiert auf der mathematischen Tatsache, dass &lt;strong>„die Primfaktorzerlegung riesiger Zahlen extrem schwierig ist“&lt;/strong>.&lt;/p>
&lt;h3 id="21-was-sind-primzahlen">2.1 Was sind Primzahlen?
&lt;/h3>&lt;p>Eine Primzahl ist „eine natürliche Zahl größer als 1, die nur durch 1 und durch sich selbst teilbar ist“.
Beispiel: $2, 3, 5, 7, 11, 13, 17, 19, 23...$&lt;/p>
&lt;p>Primzahlen sind wie die „Atome“ aller ganzen Zahlen. Jede natürliche Zahl kann in eine Multiplikation von Primzahlen zerlegt werden. Dies nennt man &lt;strong>Primfaktorzerlegung&lt;/strong>. Dass sich eine Zahl, abgesehen von der Reihenfolge der Faktoren, auf genau eine Weise in Primfaktoren zerlegen lässt (wie z. B. $60 = 2^2 \times 3 \times 5$), ist als der „Fundamentalsatz der Arithmetik“ bekannt.&lt;/p>
&lt;h3 id="22-die-schwierigkeit-der-primfaktorzerlegung-einwegfunktion">2.2 Die Schwierigkeit der Primfaktorzerlegung (Einwegfunktion)
&lt;/h3>&lt;p>Wichtig ist hier die Asymmetrie: &lt;strong>„Multiplizieren ist einfach, aber die Primfaktorzerlegung ist schwierig.“&lt;/strong>&lt;/p>
&lt;p>Versuchen Sie beispielsweise, die Multiplikation der folgenden zwei Primzahlen im Kopf zu berechnen:
$11 \times 13 = ?$
Das ist einfach. Die Antwort ist $143$.&lt;/p>
&lt;p>Aber wie steht es mit der nächsten Zahl?
Bitte zerlegen Sie $323$ in ihre Primfaktoren.
Wie sieht es aus? Das dürfte ein wenig Zeit in Anspruch nehmen. (Die Antwort ist $17 \times 19$).&lt;/p>
&lt;p>Wenn die Zahlen klein sind, kann ein Mensch sie irgendwie noch berechnen, aber wenn die Zahlen größer werden, wird die Berechnung selbst für Computer explosiv schwierig. Die derzeit vorherrschende RSA-Verschlüsselung verwendet eine Zahl $N = p \times q$, die das Produkt aus zwei unfassbar riesigen Primzahlen $p$ und $q$ von 2048 Bit (etwa 600 Dezimalstellen) ist.&lt;/p>
&lt;p>Wenn zwei riesige Primzahlen $p$ und $q$ gegeben sind, ist die Berechnung von $N$ für einen Computer eine Sache von Millisekunden. Wenn man jedoch nur $N$ hat und die ursprünglichen $p$ und $q$ finden möchte, würde dies so lange dauern, dass selbst der derzeit schnellste Supercomputer das Problem in Billionen von Jahren nicht lösen könnte.&lt;/p>
&lt;p>Diese &lt;strong>„Asymmetrie der Berechnung (in eine Richtung einfach, in die andere extrem schwer)“&lt;/strong> bildet die Grundlage für die Beziehung zwischen dem öffentlichen und dem privaten Schlüssel.&lt;/p>
&lt;hr>
&lt;h2 id="3-mathematische-grundlagen-der-rsa-verschlüsselung-teil-2-kongruenzen-modulo-arithmetik">3. Mathematische Grundlagen der RSA-Verschlüsselung Teil 2: Kongruenzen (Modulo-Arithmetik)
&lt;/h2>&lt;p>Die Berechnungen bei der RSA-Verschlüsselung erfolgen nicht wie bei der gewöhnlichen Addition oder Multiplikation, bei der die Zahlen unendlich groß werden, sondern in einer Welt der „Reste“, die entstehen, wenn man durch eine bestimmte Zahl teilt. Dies wird als &lt;strong>Kongruenz (Modulo-Arithmetik)&lt;/strong> bezeichnet.&lt;/p>
&lt;h3 id="31-die-mathematik-der-uhr">3.1 Die Mathematik der Uhr
&lt;/h3>&lt;p>Die Modulo-Arithmetik wird oft mit der „Mathematik der Uhr“ verglichen. Angenommen, es ist jetzt 10 Uhr, wie spät ist es in 5 Stunden? $10 + 5 = 15$ Uhr, aber auf einer normalen 12-Stunden-Uhr würden wir „3 Uhr“ sagen. Das liegt daran, dass der Rest von 15 geteilt durch 12 gleich 3 ist.&lt;/p>
&lt;p>In der Welt der Mathematik wird dies wie folgt geschrieben:
&lt;/p>
$$ 15 \equiv 3 \pmod{12} $$
&lt;p>
Man liest dies als: „15 und 3 sind kongruent modulo 12 (sie haben denselben Rest, wenn man sie durch 12 teilt).“&lt;/p>
&lt;h3 id="32-grundlegende-eigenschaften-von-kongruenzen">3.2 Grundlegende Eigenschaften von Kongruenzen
&lt;/h3>&lt;p>Kongruenzen haben sehr nützliche Eigenschaften, die denen einer Gleichung ($=$) sehr ähnlich sind. Sei das Modul (die Zahl, durch die geteilt wird) $N$.
Wenn $a \equiv b \pmod N$ und $c \equiv d \pmod N$, dann gilt Folgendes:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Addition:&lt;/strong> $a + c \equiv b + d \pmod N$&lt;/li>
&lt;li>&lt;strong>Subtraktion:&lt;/strong> $a - c \equiv b - d \pmod N$&lt;/li>
&lt;li>&lt;strong>Multiplikation:&lt;/strong> $a \times c \equiv b \times d \pmod N$&lt;/li>
&lt;li>&lt;strong>Potenzieren:&lt;/strong> $a^k \equiv b^k \pmod N$ (wobei $k$ eine natürliche Zahl ist)&lt;/li>
&lt;/ol>
&lt;p>Besonders wichtig ist die Eigenschaft des „Potenzierens“. Das bedeutet: &lt;strong>„Die Potenz eines Restes ist kongruent zum Rest der Potenz.“&lt;/strong>
Angenommen, wir wollen den Rest ermitteln, wenn $7^{100}$ durch $5$ geteilt wird. Es wäre mühsam, $7$ ernsthaft 100 Mal mit sich selbst zu multiplizieren und dann durch $5$ zu teilen. Wenn wir jedoch die Eigenschaften von Kongruenzen nutzen, wissen wir, dass $7 \equiv 2 \pmod 5$ ist, also gilt $7^{100} \equiv 2^{100} \pmod 5$. Dadurch lässt sich die Berechnung drastisch vereinfachen. Da in der Welt der Kryptographie mit sehr großen Potenzen gerechnet wird, ist diese Eigenschaft unverzichtbar.&lt;/p>
&lt;hr>
&lt;h2 id="4-mathematische-grundlagen-der-rsa-verschlüsselung-teil-3-eulersche-phi-funktion-und-der-satz-von-euler">4. Mathematische Grundlagen der RSA-Verschlüsselung Teil 3: Eulersche Phi-Funktion und der Satz von Euler
&lt;/h2>&lt;p>Hier beginnt nun die magische Mathematik, die den Kern der RSA-Verschlüsselung ausmacht. Hier kommt der „Satz von Euler“ ins Spiel, der eine Verallgemeinerung des „kleinen fermatschen Satzes“ ist.&lt;/p>
&lt;h3 id="41-die-eulersche-totient-funktion-phin">4.1 Die Eulersche Totient-Funktion $\phi(N)$
&lt;/h3>&lt;p>Die Eulersche Totient-Funktion (auch $\phi$-Funktion genannt) gibt für eine natürliche Zahl $N$ &lt;strong>„die Anzahl der natürlichen Zahlen von 1 bis $N$, die teilerfremd zu $N$ sind (deren größter gemeinsamer Teiler 1 ist)“&lt;/strong>, zurück.&lt;/p>
&lt;p>Schauen wir uns einige Beispiele an.&lt;/p>
&lt;ul>
&lt;li>$\phi(5)$: Unter 1, 2, 3, 4 und 5 sind 1, 2, 3 und 4 teilerfremd zu 5 (also 4 Zahlen). Daher ist $\phi(5) = 4$.&lt;/li>
&lt;li>$\phi(6)$: Unter 1, 2, 3, 4, 5 und 6 sind 1 und 5 teilerfremd zu 6 (also 2 Zahlen). Daher ist $\phi(6) = 2$.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>[Spezielle Eigenschaft bei Primzahlen]&lt;/strong>
Wenn $p$ eine Primzahl ist, sind alle Zahlen von 1 bis $p-1$ teilerfremd zu $p$. Daher gilt:
&lt;/p>
$$ \phi(p) = p - 1 $$
&lt;p>&lt;strong>[Spezielle Eigenschaft beim Produkt von Primzahlen]&lt;/strong>
Für zwei verschiedene Primzahlen $p$ und $q$ und $N = p \times q$ kann $\phi(N)$ einfach durch folgende Berechnung ermittelt werden:
&lt;/p>
$$ \phi(N) = \phi(p) \times \phi(q) = (p - 1)(q - 1) $$
&lt;p>
Diese Eigenschaft fungiert als „geheime Hintertür (Trapdoor)“ der RSA-Verschlüsselung. Wer $p$ und $q$ kennt (der Ersteller des Schlüssels), kann $\phi(N)$ augenblicklich berechnen, aber ein Dritter, der nur $N$ kennt, kann $\phi(N)$ nicht bestimmen, ohne $N$ vorher in seine Primfaktoren zu zerlegen.&lt;/p>
&lt;h3 id="42-der-satz-von-euler">4.2 Der Satz von Euler
&lt;/h3>&lt;p>Leonhard Euler bewies mit Hilfe dieser Funktion $\phi(N)$ den folgenden schönen Satz.&lt;/p>
&lt;p>&lt;strong>Der Satz von Euler:&lt;/strong>
Wenn eine ganze Zahl $a$ und $N$ teilerfremd sind, gilt die folgende Kongruenz:
&lt;/p>
$$ a^{\phi(N)} \equiv 1 \pmod N $$
&lt;p>Das ist die bemerkenswerte Eigenschaft, dass „wenn man eine bestimmte Zahl $a$ insgesamt $\phi(N)$ Mal mit sich selbst multipliziert und durch $N$ teilt, der Rest immer $1$ ist“. (Wenn $N$ eine Primzahl $p$ ist, ergibt sich $a^{p-1} \equiv 1 \pmod p$, was als der kleine fermatsche Satz bekannt ist).&lt;/p>
&lt;p>Lassen Sie uns diesen Satz von Euler umformen. Wir multiplizieren beide Seiten noch einmal mit $a$.
&lt;/p>
$$ a^{\phi(N) + 1} \equiv a \pmod N $$
&lt;p>Darüber hinaus ergibt $a^{k \cdot \phi(N)}$ für eine beliebige ganze Zahl $k$ ebenfalls $1^k = 1$, sodass die folgende Gleichung gilt:
&lt;/p>
$$ a^{k \cdot \phi(N) + 1} \equiv a \pmod N $$
&lt;p>Genau diese Gleichung ist das Grundprinzip, das die Magie der RSA-Verschlüsselung – &lt;strong>„nach dem Verschlüsseln und Entschlüsseln erhält man wieder das Original“&lt;/strong> – möglich macht.&lt;/p>
&lt;hr>
&lt;h2 id="5-der-algorithmus-der-rsa-verschlüsselung-schritte-zur-schlüsselerzeugung-verschlüsselung-und-entschlüsselung">5. Der Algorithmus der RSA-Verschlüsselung: Schritte zur Schlüsselerzeugung, Verschlüsselung und Entschlüsselung
&lt;/h2>&lt;p>Da wir nun über das Grundlagenwissen verfügen, schauen wir uns endlich die konkreten Schritte der RSA-Verschlüsselung an. Die RSA-Verschlüsselung ist grob in drei Phasen unterteilt: „1. Schlüsselerzeugung“, „2. Verschlüsselung“ und „3. Entschlüsselung“.&lt;/p>
&lt;div class="mermaid">flowchart TD
A1["1. Wähle Primzahlen p, q"] --> A2["Berechne N = p × q"]
A1 --> A3["Berechne φ(N) = (p-1)(q-1)"]
A3 --> A4["Wähle ein e, das zu φ(N) teilerfremd ist"]
A3 --> A5["Berechne d, sodass e × d ≡ 1 (mod φ(N))"]
A2 --> A6["Öffentlicher Schlüssel (N, e)"]
A4 --> A6
A5 --> A7["Privater Schlüssel d"]
B1["2. Klartext-Nachricht M"] --> B2["Berechne C ≡ M^e (mod N)"]
A6 -.-> B2
B2 --> B3["Sende Geheimtext C"]
B3 --> C1["3. Empfangener Geheimtext C"]
C1 --> C2["Berechne M ≡ C^d (mod N)"]
A7 -.-> C2
C2 --> C3["Erhalte ursprüngliche Klartext-Nachricht M"]&lt;/div>
&lt;h3 id="51-schlüsselerzeugung-key-generation">5.1 Schlüsselerzeugung (Key Generation)
&lt;/h3>&lt;p>Bob, der Empfänger, generiert für sich selbst einen „öffentlichen Schlüssel“ und einen „privaten Schlüssel“.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Wahl der Primzahlen:&lt;/strong> Es werden zwei große Primzahlen $p$ und $q$ zufällig gewählt.&lt;/li>
&lt;li>&lt;strong>Berechnung des Moduls $N$:&lt;/strong> Es wird $N = p \times q$ berechnet. Dieses $N$ wird veröffentlicht.&lt;/li>
&lt;li>&lt;strong>Berechnung von $\phi(N)$:&lt;/strong> Die Eulersche Funktion $\phi(N) = (p - 1)(q - 1)$ wird berechnet. Diese Zahl ist Bobs Geheimnis.&lt;/li>
&lt;li>&lt;strong>Wahl des öffentlichen Schlüssels $e$:&lt;/strong> Es wird eine ganze Zahl $e$ gewählt, für die $1 &lt; e &lt; \phi(N)$ gilt und die teilerfremd zu $\phi(N)$ ist.&lt;/li>
&lt;li>&lt;strong>Berechnung des privaten Schlüssels $d$:&lt;/strong> Es wird eine ganze Zahl $d$ gefunden, die folgende Bedingung erfüllt:
$$ e \times d \equiv 1 \pmod{\phi(N)} $$
Das bedeutet: „Eine Zahl $d$, bei der $e \times d$ geteilt durch $\phi(N)$ einen Rest von $1$ ergibt.“&lt;/li>
&lt;/ol>
&lt;p>Damit sind die Schlüssel vorbereitet.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Öffentlicher Schlüssel:&lt;/strong> Das Paar $(N, e)$. Es wird für die ganze Welt veröffentlicht.&lt;/li>
&lt;li>&lt;strong>Privater Schlüssel:&lt;/strong> $d$. Er wird absolut niemandem verraten.&lt;/li>
&lt;/ul>
&lt;h3 id="52-verschlüsselung-encryption">5.2 Verschlüsselung (Encryption)
&lt;/h3>&lt;p>Angenommen, Alice möchte Bob eine geheime Nachricht $M$ senden. ($M$ ist ein in Zahlen umgewandelter Text, wobei $0 \le M &lt; N$ gilt). Alice berechnet mithilfe von Bobs öffentlichem Schlüssel $(N, e)$ Folgendes:&lt;/p>
$$ C \equiv M^e \pmod N $$
&lt;p>Sie berechnet „den Rest $C$, der entsteht, wenn man die Nachricht $M$ mit $e$ potenziert und durch $N$ teilt“. Dieses $C$ ist der Geheimtext.&lt;/p>
&lt;h3 id="53-entschlüsselung-decryption">5.3 Entschlüsselung (Decryption)
&lt;/h3>&lt;p>Bob empfängt den Geheimtext $C$. Bob rechnet mit seinem privaten Schlüssel $d$ wie folgt:&lt;/p>
$$ M \equiv C^d \pmod N $$
&lt;p>Wenn man „den Rest berechnet, der entsteht, wenn der Geheimtext $C$ mit $d$ potenziert und durch $N$ geteilt wird“, wird erstaunlicherweise die ursprüngliche Nachricht $M$ wiederhergestellt!&lt;/p>
&lt;hr>
&lt;h2 id="6-warum-erhält-man-durch-entschlüsselung-das-original-zurück-mathematischer-beweis">6. Warum erhält man durch Entschlüsselung das Original zurück? (Mathematischer Beweis)
&lt;/h2>&lt;p>Vielleicht fragen Sie sich: „Wie kann es sein, dass $C$ hoch $d$ uns einfach unser ursprüngliches $M$ zurückgibt?“ Hier kommt nun der zuvor erwähnte „Satz von Euler“ ins Spiel.&lt;/p>
&lt;p>Setzen wir die Formel für die Verschlüsselung, $C = M^e$, in die Berechnungsformel für die Entschlüsselung, $C^d \pmod N$, ein.
&lt;/p>
$$ C^d \equiv (M^e)^d \equiv M^{ed} \pmod N $$
&lt;p>Erinnern wir uns nun an Schritt 5 der Schlüsselerzeugung. Als Bob $d$ generierte, wählte er es so, dass $e \times d \equiv 1 \pmod{\phi(N)}$ gilt. Das bedeutet, dass „$ed$ ein Vielfaches von $\phi(N)$ plus $1$ ist“. Mit einer ganzen Zahl $k$ lässt sich dies wie folgt schreiben:
&lt;/p>
$$ ed = k \cdot \phi(N) + 1 $$
&lt;p>Wir setzen dies in den Exponenten ein und zerlegen ihn mithilfe der Potenzgesetze.
&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>Wenn wir hier annehmen, dass die Nachricht $M$ und $N$ teilerfremd sind, gilt nach dem &lt;strong>Satz von Euler&lt;/strong> $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>Folglich ergibt sich auf wunderbare Weise diese Gleichung:
&lt;/p>
$$ C^d \equiv M \pmod N $$
&lt;p>Da Alice $d$ nicht kennt und auch ein Abhörer $d$ nicht kennt, ist Bob mit seinem $d$ der Einzige, der $M$ aus $C$ extrahieren kann.&lt;/p>
&lt;hr>
&lt;h2 id="7-ein-konkretes-beispiel-rsa-mit-kleinen-primzahlen-per-hand-ausprobieren">7. Ein konkretes Beispiel: RSA mit kleinen Primzahlen per Hand ausprobieren
&lt;/h2>&lt;p>Lassen Sie uns tatsächlich eine verschlüsselte Kommunikation von Alice an Bob unter Verwendung kleiner Zahlen (Primzahlen) durchführen.&lt;/p>
&lt;p>&lt;strong>[Bobs Schlüsselerzeugungsphase]&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>Er wählt zwei Primzahlen: $p=11$, $q=13$.&lt;/li>
&lt;li>Er berechnet $N = 11 \times 13 = 143$.&lt;/li>
&lt;li>Er berechnet $\phi(N) = (11 - 1) \times (13 - 1) = 10 \times 12 = 120$.&lt;/li>
&lt;li>Er wählt einen öffentlichen Schlüssel $e$, der teilerfremd zu $\phi(N)=120$ ist. Hier wählen wir $e=7$.&lt;/li>
&lt;li>Er ermittelt den privaten Schlüssel $d$. Er sucht ein $d$, für das $7 \times d \equiv 1 \pmod{120}$ gilt.
In der Gleichung $7d = 120k + 1$ ergibt sich für $k=6$ die Zahl $721$, und $721 \div 7 = 103$.
Daher ist $d = 103$.&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>Öffentlicher Schlüssel: $(N=143, e=7)$&lt;/li>
&lt;li>Privater Schlüssel: $d=103$&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>[Alices Verschlüsselungsphase]&lt;/strong>
Nehmen wir an, sie möchte die Nachricht $M = 9$ senden.
Formel: $C \equiv 9^7 \pmod{143}$
$9^7 = 4.782.969$. Teilt man dies durch 143, erhält man $33447$ mit dem Rest $48$.
Der Geheimtext $C$ ist also $48$.&lt;/p>
&lt;p>&lt;strong>[Bobs Entschlüsselungsphase]&lt;/strong>
Bob empfängt den Geheimtext $C = 48$ und entschlüsselt ihn mit dem privaten Schlüssel $d = 103$.
Formel: $M \equiv 48^{103} \pmod{143}$
Wenn man &lt;code>(48 ** 103) % 143&lt;/code> in einen Computer eingibt, ist das großartige Ergebnis tatsächlich „&lt;strong>9&lt;/strong>“! Er hat die ursprüngliche Nachricht sicher erhalten.&lt;/p>
&lt;hr>
&lt;h2 id="8-wie-man-den-privaten-schlüssel-d-findet-der-erweiterte-euklidische-algorithmus">8. Wie man den privaten Schlüssel $d$ findet: Der erweiterte euklidische Algorithmus
&lt;/h2>&lt;p>Im per Hand berechneten Beispiel haben wir $k$ durch Ausprobieren gesucht, um $d=103$ zu finden, aber wenn die Zahlen Hunderte von Ziffern haben, ist diese Methode unmöglich. In echten Programmen wird ein Algorithmus namens &lt;strong>„erweiterter euklidischer Algorithmus“&lt;/strong> verwendet.&lt;/p>
&lt;p>Die Lösung von $7d \equiv 1 \pmod{120}$ ist gleichbedeutend mit dem Finden der ganzen Zahlen $d$ und $y$, die $7d + 120y = 1$ erfüllen. Durch die Rückwärtsrechnung des euklidischen Algorithmus lässt sich dies maschinell ermitteln.&lt;/p>
&lt;ol>
&lt;li>$120 \div 7 = 17$ Rest $1$&lt;/li>
&lt;li>Durch Umformen ergibt sich: $1 = 120 - 17 \times 7$&lt;/li>
&lt;li>Das heißt: $-17 \times 7 \equiv 1 \pmod{120}$&lt;/li>
&lt;/ol>
&lt;p>$-17$ bedeutet in der Welt von Modulo $120$ dasselbe wie $120 - 17 = 103$. So lässt sich $d = 103$ augenblicklich ermitteln. Diese Methode erlaubt sehr schnelle Berechnungen, egal wie riesig die Zahlen sind.&lt;/p>
&lt;hr>
&lt;h2 id="9-ein-weiteres-gesicht-der-rsa-verschlüsselung-digitale-signaturen">9. Ein weiteres Gesicht der RSA-Verschlüsselung: Digitale Signaturen
&lt;/h2>&lt;p>Das Tolle an der RSA-Verschlüsselung ist, dass sie auch als &lt;strong>„digitale Signatur“&lt;/strong> verwendet werden kann, indem man die Rollen des öffentlichen und privaten Schlüssels vertauscht.&lt;/p>
&lt;p>Während bei der Verschlüsselung das Prinzip „Verschlüsseln mit dem öffentlichen Schlüssel $\Rightarrow$ Entschlüsseln mit dem privaten Schlüssel“ galt,
ist der Ablauf bei der digitalen Signatur „Verschlüsseln mit dem privaten Schlüssel $\Rightarrow$ Entschlüsseln mit dem öffentlichen Schlüssel“.&lt;/p>
&lt;div class="mermaid">flowchart TD
A1["1. Alice erstellt Signatur mit privatem Schlüssel"] --> A2["S ≡ M^d (mod N)"]
A2 --> A3["Sende Nachricht M und Signatur S"]
A3 --> B1["2. Bob verifiziert Signatur mit öffentlichem Schlüssel"]
B1 --> B2["Berechne M' ≡ S^e (mod N)"]
B2 --> B3["Prüfe, ob M' und M übereinstimmen"]&lt;/div>
&lt;p>Alice wandelt die Nachricht mit ihrem eigenen privaten Schlüssel $d$ um (das ist die Signatur $S$) und sendet sie an Bob. Bob führt mit Alices öffentlichem Schlüssel $e$ die Verifizierungsberechnung durch. Wenn das Ergebnis der Berechnung mit der ursprünglichen Nachricht übereinstimmt, beweist dies gleichzeitig, dass „die Daten nur mit Alices privatem Schlüssel erstellt werden konnten“ und dass „die Nachricht unterwegs nicht manipuliert wurde“.&lt;/p>
&lt;hr>
&lt;h2 id="10-die-rsa-verschlüsselung-durch-programmierung-erfahren">10. Die RSA-Verschlüsselung durch Programmierung erfahren
&lt;/h2>&lt;p>Potenzberechnungen, die per Hand extrem mühsam sind, lassen sich in Python sehr einfach implementieren. Im Folgenden finden Sie einen Python-Code, mit dem Sie die Kernlogik der RSA-Verschlüsselung erleben können.&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;Den größten gemeinsamen Teiler finden&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;Den privaten Schlüssel d finden (nutzt die eingebaute Funktion ab 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. Schlüsselerzeugung&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;Öffentlicher Schlüssel: (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">), Privater Schlüssel: 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. Verschlüsselung&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;Geheimtext: &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. Entschlüsselung&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;Entschlüsselte Nachricht: &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>Die Python-Funktion &lt;code>pow(base, exp, mod)&lt;/code> verwendet intern einen schnellen Algorithmus, der sich „binäre Exponentiation (Square-and-Multiply)“ nennt. Dadurch wird die Berechnung auch bei Zahlen mit Hunderten von Ziffern in einem Augenblick abgeschlossen.&lt;/p>
&lt;hr>
&lt;h2 id="11-zusammenfassung-und-zukünftige-kryptographietechnologien">11. Zusammenfassung und zukünftige Kryptographietechnologien
&lt;/h2>&lt;p>Basierend auf dem Wissen der Schulmathematik haben wir die Funktionsweise der RSA-Verschlüsselung aufgedeckt.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Die Schwierigkeit der Primfaktorzerlegung:&lt;/strong> $p \times q = N$ ist einfach, aber es ist sehr schwer, $p$ und $q$ aus $N$ zu finden.&lt;/li>
&lt;li>&lt;strong>Kongruenzen und der Satz von Euler:&lt;/strong> Das Gesetz $a^{\phi(N)} \equiv 1 \pmod N$ vervollständigt die magische Trapdoor, bei der man „durch Potenzieren mit einer bestimmten Zahl zum Ursprung zurückkehrt“.&lt;/li>
&lt;li>&lt;strong>Öffentlicher und privater Schlüssel:&lt;/strong> Jeder kann verschlüsseln, aber nur der rechtmäßige Empfänger kann entschlüsseln.&lt;/li>
&lt;/ol>
&lt;p>Das $N$ der heute verwendeten RSA-Verschlüsselung hat mehr als 600 Ziffern. Selbst wenn alle Supercomputer der Welt zusammenarbeiten würden, würde die Primfaktorzerlegung länger dauern als das Alter des Universums. Wenn jedoch in Zukunft die derzeit in Entwicklung befindlichen „Quantencomputer“ in die Praxis umgesetzt werden, besteht die Möglichkeit, dass diese Primfaktorzerlegung durch den „Shor-Algorithmus“ augenblicklich geknackt wird. Aus diesem Grund wird derzeit weltweit mit Hochdruck an der Entwicklung der „Post-Quanten-Kryptographie“ gearbeitet, die selbst von Quantencomputern nicht entschlüsselt werden kann.&lt;/p>
&lt;p>Fortgeschrittene Mathematik, die oft als „nutzlos“ abgetan wird, schützt in Wirklichkeit unseren Alltag grundlegend. Die RSA-Verschlüsselung ist das beste Lehrmaterial, um uns diese Tiefe und Schönheit der Mathematik zu zeigen. Ich hoffe, dass Sie durch diesen Artikel ein wenig von der Faszination für Kryptographie und Mathematik spüren konnten.&lt;/p></description></item><item><title>Was ist die vollständig homomorphe Verschlüsselung (FHE)? Der Schlüssel zur Sicherheit der nächsten Generation</title><link>http://kenji.blog/de/p/fully-homomorphic-encryption-fhe-explained/</link><pubDate>Fri, 11 Sep 2026 11:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/fully-homomorphic-encryption-fhe-explained/</guid><description>&lt;img src="http://kenji.blog/p/fully-homomorphic-encryption-fhe-explained/img/eyecatch.jpg" alt="Featured image of post Was ist die vollständig homomorphe Verschlüsselung (FHE)? Der Schlüssel zur Sicherheit der nächsten Generation" />&lt;p>Während Cloud-Computing und KI-Technologien als Grundlage unserer Gesellschaft fest etabliert sind, ist der Kompromiss zwischen &amp;ldquo;Datenschutz&amp;rdquo; und &amp;ldquo;Datennutzung&amp;rdquo; zu einer der wichtigsten Herausforderungen geworden. Es gibt eine wachsende Nachfrage danach, dass KI hochsensible Daten wie medizinische Daten, Finanzinformationen und persönliche biometrische Daten in der Cloud analysiert. Dennoch zögern viele Unternehmen aus Sicherheitsbedenken, Daten nach außen zu senden.&lt;/p>
&lt;p>Herkömmliche Verschlüsselungstechnologien (wie AES und RSA) eignen sich hervorragend zum Schutz von gespeicherten Daten (Data at Rest) oder Daten, die über ein Netzwerk übertragen werden (Data in Transit). &lt;strong>Wenn der Server jedoch Verarbeitungen (Berechnungen) wie Suchen oder maschinelles Lernen an den Daten durchführt (Data in Use), müssen die Daten zuerst entschlüsselt und wieder in Klartext umgewandelt werden.&lt;/strong> Wenn der Server in diesem Moment der Entschlüsselung gehackt wird oder ein böswilliger interner Administrator die Daten einsieht, führt dies direkt zu einem Informationsleck.&lt;/p>
&lt;p>Die &lt;strong>vollständig homomorphe Verschlüsselung (Fully Homomorphic Encryption: FHE)&lt;/strong> ist eine Traumtechnologie, die diese fundamentale Schwäche der &amp;ldquo;Entschlüsselung während der Verarbeitung&amp;rdquo; überwindet. Mit FHE ist es möglich, Berechnungen an Daten durchzuführen, während sie verschlüsselt bleiben, ohne sie jemals zu entschlüsseln, und nur das verschlüsselte Ergebnis an den Client zurückzusenden.&lt;/p>
&lt;p>In diesem Artikel werden wir FHE, den Schlüssel zur Sicherheit der nächsten Generation, detailliert untersuchen – von seinen Konzepten und seiner Geschichte über den bahnbrechenden Durchbruch von Craig Gentry, die mathematischen Grundlagen (wie Ring-LWE), die größte Herausforderung des &amp;ldquo;Rauschens&amp;rdquo; und deren Lösung (Bootstrapping) bis hin zu den neuesten Implementierungsbibliotheken.&lt;/p>
&lt;hr>
&lt;h2 id="1-was-ist-homomorphe-verschlüsselung-grundkonzepte">1. Was ist homomorphe Verschlüsselung? Grundkonzepte
&lt;/h2>&lt;p>&amp;ldquo;Homomorph&amp;rdquo; ist ein Begriff aus der Algebra, der sich auf die Eigenschaft bezieht, dass zwischen Mengen mit einer bestimmten Struktur Abbildungen vorgenommen werden können, während die Struktur der Operationen erhalten bleibt. In der Kryptographie bedeutet die &amp;ldquo;homomorphe&amp;rdquo; Eigenschaft, dass &lt;strong>Operationen im Klartextraum den Operationen im Geheimtextraum entsprechen&lt;/strong>.&lt;/p>
&lt;p>Ausgedrückt in einer einfachen Formel: Sei $E(\cdot)$ die Verschlüsselungsfunktion und $D(\cdot)$ die Entschlüsselungsfunktion für die Klartexte $m_1$ und $m_2$. Wenn wir die Operation auf dem Klartext (wie Addition oder Multiplikation) als $\circ$ und die Operation auf dem Geheimtext als $\diamond$ bezeichnen, gilt die folgende Beziehung:&lt;/p>
$$ D(E(m_1) \diamond E(m_2)) = m_1 \circ m_2 $$
&lt;p>Das bedeutet, wenn wir das Ergebnis einer Operation $\diamond$ auf die Geheimtexte $E(m_1)$ und $E(m_2)$ entschlüsseln, stimmt es mit dem Ergebnis der Operation $\circ$ auf die ursprünglichen Klartexte überein.&lt;/p>
&lt;h3 id="datenfluss-im-cloud-computing">Datenfluss im Cloud Computing
&lt;/h3>&lt;p>Die Architektur der Cloud-Verarbeitung mit FHE unterscheidet sich völlig von herkömmlichen Methoden. Das folgende Diagramm zeigt den Ablauf einer sicheren Datenverarbeitung unter Verwendung von FHE.&lt;/p>
&lt;div class="mermaid">graph TD
A["Client (hält privaten Schlüssel)"] -->|1. Klartext x verschlüsseln: E(x)| B["Cloud-Server (nur verschlüsselte Daten)"]
B -->|2. Funktion f auf Geheimtext anwenden: E(f(x))| B
B -->|3. Berechnetes Geheimtextergebnis E(y)| A
A -->|4. Mit privatem Schlüssel entschlüsseln: y = f(x)| A
style A fill:#d4edda,stroke:#28a745
style B fill:#f8d7da,stroke:#dc3545&lt;/div>
&lt;p>Der Server empfängt die verschlüsselten Daten $E(x)$, aber da er den privaten Schlüssel nicht besitzt, kann er unmöglich den Inhalt der Daten kennen. Durch Ausnutzung der Eigenschaften von FHE kann er jedoch eine Funktion $f$ (zum Beispiel ein maschinelles Lern-Inferenzmodell) auf den Geheimtext anwenden und $E(f(x))$ erzeugen. Der Client empfängt dies und entschlüsselt es mit seinem eigenen privaten Schlüssel, um das gewünschte Ergebnis $y = f(x)$ zu erhalten.&lt;/p>
&lt;hr>
&lt;h2 id="2-die-evolutionsgeschichte-der-homomorphen-verschlüsselung-phe-she-fhe">2. Die Evolutionsgeschichte der homomorphen Verschlüsselung: PHE, SHE, FHE
&lt;/h2>&lt;p>Die homomorphe Verschlüsselung hat ihre aktuelle &amp;ldquo;vollständige&amp;rdquo; Form nicht auf einmal erreicht. Sie wird je nach Art und Anzahl der durchführbaren Operationen grob in drei Phasen eingeteilt.&lt;/p>
&lt;h3 id="partially-homomorphic-encryption-phe-partiell-homomorphe-verschlüsselung">Partially Homomorphic Encryption (PHE: Partiell homomorphe Verschlüsselung)
&lt;/h3>&lt;p>PHE ist ein Verschlüsselungsschema, das es erlaubt, &lt;strong>entweder&lt;/strong> Addition oder Multiplikation unbegrenzt durchzuführen. Tatsächlich existieren Verschlüsselungen mit dieser Eigenschaft schon seit langer Zeit.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>RSA-Verschlüsselung (Homomorphismus bezüglich Multiplikation)&lt;/strong>
Die RSA-Verschlüsselung hatte unbeabsichtigt eine multiplikative homomorphe Eigenschaft. Seien $m_1, m_2$ Klartexte und $(e, N)$ der öffentliche Schlüssel:
$$ E(m_1) = m_1^e \pmod N $$
$$ E(m_2) = m_2^e \pmod N $$
Wenn wir diese multiplizieren:
$$ E(m_1) \times E(m_2) = (m_1 \cdot m_2)^e \pmod N = E(m_1 \times m_2) $$
Auf diese Weise entspricht die Multiplikation von Geheimtexten der Multiplikation von Klartexten.&lt;/li>
&lt;li>&lt;strong>Paillier-Verschlüsselung (Homomorphismus bezüglich Addition)&lt;/strong>
Die 1999 erfundene Paillier-Verschlüsselung besitzt eine additive homomorphe Eigenschaft. Sie wird in der Praxis für elektronische Wahlen (Zählen von verschlüsselten Stimmen und Entschlüsseln nur des Endergebnisses) verwendet.&lt;/li>
&lt;/ul>
&lt;h3 id="somewhat-homomorphic-encryption-she-etwas-homomorphe-verschlüsselung">Somewhat Homomorphic Encryption (SHE: Etwas homomorphe Verschlüsselung)
&lt;/h3>&lt;p>Dieses Schema kann &lt;strong>sowohl&lt;/strong> Addition als auch Multiplikation ausführen, aber es gibt &lt;strong>eine Grenze für die Anzahl der Operationen (die Tiefe der Schaltung)&lt;/strong>, die durchgeführt werden können. Aufgrund der Ansammlung von &amp;ldquo;Rauschen&amp;rdquo;, das später erläutert wird, wird die Entschlüsselung nach einer bestimmten Anzahl von Multiplikationen unmöglich. Die BGN (Boneh-Goh-Nissim)-Verschlüsselung von 2005 ist ein solches Beispiel, aber sie hatte Einschränkungen bei der Durchführung komplexer praktischer Berechnungen (wie Deep Learning).&lt;/p>
&lt;h3 id="fully-homomorphic-encryption-fhe-vollständig-homomorphe-verschlüsselung">Fully Homomorphic Encryption (FHE: Vollständig homomorphe Verschlüsselung)
&lt;/h3>&lt;p>Ein Verschlüsselungsschema, das sowohl Addition als auch Multiplikation &lt;strong>unbegrenzt oft&lt;/strong> ausführen kann. Ähnlich der Turing-Vollständigkeit in der Informationstheorie bedeutet dies: Wenn Addition (entspricht XOR) und Multiplikation (entspricht AND) unendlich oft kombiniert werden können, kann theoretisch jede berechenbare Funktion oder jeder Algorithmus in einem verschlüsselten Zustand ausgeführt werden.&lt;/p>
&lt;p>FHE wurde lange Zeit als der &amp;ldquo;Heilige Gral der Kryptographie&amp;rdquo; bezeichnet und man hielt es sogar für unmöglich, dies zu erreichen. Im Jahr 2009 schlug &lt;strong>Craig Gentry&lt;/strong>, der damals Doktorand an der Stanford University war, jedoch das erste FHE-Schema vor, das ideale Gitter (Ideal Lattices) nutzte und die Welt schockierte.&lt;/p>
&lt;hr>
&lt;h2 id="3-mathematische-grundlagen-von-fhe-das-lwe-problem-und-ring-lwe">3. Mathematische Grundlagen von FHE: Das LWE-Problem und Ring-LWE
&lt;/h2>&lt;p>Viele der heutigen Mainstream-FHE-Schemata basieren auf dem &lt;strong>LWE (Learning With Errors)-Problem&lt;/strong>, einer mathematischen Herausforderung der &amp;ldquo;gitterbasierten Kryptographie&amp;rdquo; (Lattice-based Cryptography), die auch als Post-Quanten-Kryptographie (Post-Quantum Cryptography) bekannt ist.&lt;/p>
&lt;h3 id="intuitives-verständnis-des-lwe-problems">Intuitives Verständnis des LWE-Problems
&lt;/h3>&lt;p>Das Lösen von linearen Gleichungssystemen ist mit Methoden wie der Gaußschen Elimination einfach.&lt;/p>
$$ \begin{cases} 3s_1 + 4s_2 + 2s_3 \equiv 12 \pmod{17} \\ 1s_1 + 9s_2 + 5s_3 \equiv 8 \pmod{17} \\ \vdots \end{cases} $$
&lt;p>Was passiert jedoch, wenn wir den Ergebnissen dieser Gleichungen einen sehr kleinen &amp;ldquo;zufälligen Fehler (Rauschen)&amp;rdquo; $e$ hinzufügen?&lt;/p>
$$ \begin{cases} 3s_1 + 4s_2 + 2s_3 + e_1 \equiv 13 \pmod{17} \\ 1s_1 + 9s_2 + 5s_3 + e_2 \equiv 7 \pmod{17} \\ \vdots \end{cases} $$
&lt;p>Nur durch Hinzufügen dieses Fehlers $e$ verwandelt sich das Problem, den geheimen Variablenvektor $\vec{s}$ zu finden, in ein NP-schweres Problem, das selbst mit aktuellen Supercomputern oder Quantencomputern schwer zu knacken ist. Dies ist das LWE-Problem.&lt;/p>
&lt;h3 id="das-ring-lwe-problem-rlwe">Das Ring-LWE-Problem (RLWE)
&lt;/h3>&lt;p>Das Standard-LWE-Problem beinhaltet Matrixoperationen, was zu dem Problem führt, dass die Schlüsselgrößen sehr groß sind (manchmal in der Größenordnung von Gigabyte) und die Berechnungseffizienz gering ist. Um dies zu lösen, wurde das &lt;strong>Ring-LWE (RLWE)-Problem&lt;/strong> eingeführt, welches Operationen über Polynomringen verwendet.&lt;/p>
&lt;p>In RLWE gehören die Elemente zum Polynomring $R_q = \mathbb{Z}_q[x] / (x^N + 1)$ (wobei $N$ eine Zweierpotenz und $q$ eine Primzahl als Modul ist).
Wenn der private Schlüssel ein Polynom $s(x)$, $a(x)$ ein zufälliges Polynom und $e(x)$ ein kleines Rauschpolynom ist, ist der öffentliche Schlüssel das folgende Paar:&lt;/p>
$$ (a(x), b(x)) \quad \text{where} \quad b(x) = -a(x) \cdot s(x) + e(x) \pmod q $$
&lt;p>Während der Verschlüsselung werden die Eigenschaften dieser Polynome genutzt, um den Klartext $m(x)$ zu kodieren und den Geheimtext zu erzeugen.&lt;/p>
&lt;hr>
&lt;h2 id="4-das-größte-hindernis-rauschen-und-gentrys-bootstrapping">4. Das größte Hindernis &amp;ldquo;Rauschen&amp;rdquo; und Gentrys Bootstrapping
&lt;/h2>&lt;p>Das wichtigste Konzept für das Verständnis von FHE ist das &lt;strong>&amp;ldquo;Rauschmanagement&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;p>In LWE/RLWE-basierter Kryptographie wird absichtlich ein kleines &amp;ldquo;Rauschen (Fehler)&amp;rdquo; eingeschlossen, um die Sicherheit zu gewährleisten.
Der Prozess der Entschlüsselung des Geheimtextes $c$ eines Klartextes $m$ wird grob durch die folgende Formel ausgedrückt:&lt;/p>
$$ D(c) = (c \cdot s) \pmod q = m + \text{noise} $$
&lt;p>Bei der Entschlüsselung wird dieses &lt;code>noise&lt;/code> durch Prozesse wie Rundung entfernt, um den richtigen Klartext $m$ zu erhalten. Wenn Sie jedoch homomorphe Operationen (insbesondere Multiplikation) zwischen Geheimtexten durchführen, wird dieses Rauschen dramatisch verstärkt.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Homomorphe Addition&lt;/strong>: Rauschen nimmt additiv zu ($e_1 + e_2$). Dies ist eine relativ langsame Zunahme.&lt;/li>
&lt;li>&lt;strong>Mathematischer Ausdruck der homomorphen Eigenschaft für homomorphe Addition&lt;/strong>:
$$ E(m_1) \oplus E(m_2) = E(m_1 + m_2) $$&lt;/li>
&lt;li>&lt;strong>Homomorphe Multiplikation&lt;/strong>: Rauschen explodiert multiplikativ (weil es Ausdrücke wie $e_1 \times e_2$ enthält). Nach nur wenigen Multiplikationen überschreitet das Rauschen den Schwellenwert $q/2$, was eine korrekte Rundung unmöglich macht und die Entschlüsselung fehlschlägt.&lt;/li>
&lt;li>&lt;strong>Mathematischer Ausdruck der homomorphen Eigenschaft für homomorphe Multiplikation&lt;/strong>:
$$ E(m_1) \otimes E(m_2) = E(m_1 \times m_2) $$&lt;/li>
&lt;/ul>
&lt;p>Aus diesem Grund war FHE lange Zeit nicht realisierbar und blieb auf SHE (mit einer begrenzten Anzahl von Operationen) beschränkt.&lt;/p>
&lt;h3 id="die-magie-des-bootstrapping">Die Magie des Bootstrapping
&lt;/h3>&lt;p>Craig Gentrys genialer Beitrag war die Erfindung einer Rauschreduzierungstechnik namens &lt;strong>&amp;ldquo;Bootstrapping&amp;rdquo;&lt;/strong>. Dies war ein Paradigmenwechsel in der Kryptographie.&lt;/p>
&lt;p>Intuitiv ist es die Operation: &amp;ldquo;Bevor der Geheimtext mit Rauschen bedeckt und zerstört wird, &amp;rsquo;entschlüsseln&amp;rsquo; wir ihn im verschlüsselten Zustand, bereinigen ihn und legen ihn in einen neuen Geheimtext.&amp;rdquo;&lt;/p>
&lt;ol>
&lt;li>Angenommen, wir haben einen Geheimtext $C_{noisy}$ mit hohem Rauschen.&lt;/li>
&lt;li>Der Client übergibt im Voraus an den Server seinen privaten Schlüssel $sk$, der &amp;ldquo;mit dem öffentlichen Schlüssel verschlüsselt&amp;rdquo; ist, nämlich $E_{pk}(sk)$ (dies wird als Bootstrapping-Schlüssel bezeichnet).&lt;/li>
&lt;li>Der Server führt homomorph eine &lt;strong>Entschlüsselungsschaltung (Decryption Circuit)&lt;/strong> auf $C_{noisy}$ aus.&lt;/li>
&lt;li>Insbesondere führt er eine &amp;ldquo;Entschlüsselung innerhalb des verschlüsselten Raums&amp;rdquo; durch, indem er $E_{pk}(sk)$ auf $E_{pk}(C_{noisy})$ anwendet.&lt;/li>
&lt;li>Da diese Entschlüsselungsschaltung selbst eine homomorphe Operation ist, erzeugt sie neues Rauschen, aber das Rauschen des ausgegebenen neuen Geheimtextes $C_{fresh}$ wird auf ein bestimmtes &amp;ldquo;festes Niveau&amp;rdquo; zurückgesetzt.&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph LR
A["Geheimtext mit hohem Rauschen C_noisy"] --> B["Homomorphe Entschlüsselungsschaltung (Eval_Dec)"]
C["Verschlüsselter privater Schlüssel E(sk)"] --> B
B --> D["Geheimtext mit geringem Rauschen C_fresh"]
style B fill:#ffeeba,stroke:#ffc107&lt;/div>
&lt;p>Durch die regelmäßige Ausführung dieses Bootstrappings während der Berechnung ist es theoretisch möglich, eine Schaltung unendlicher Tiefe zu berechnen (Erreichen von FHE). Die frühe Methode von Gentry hatte jedoch einen so hohen Rechenaufwand, dass ein einziger Bootstrapping-Prozess zig Minuten bis Stunden in Anspruch nahm.&lt;/p>
&lt;hr>
&lt;h2 id="5-fhe-generationen-und-die-evolution-der-wichtigsten-schemata">5. FHE-Generationen und die Evolution der wichtigsten Schemata
&lt;/h2>&lt;p>Um FHE in die Praxis umzusetzen, haben Kryptographen auf der ganzen Welt darum gewetteifert, die Algorithmen zu verbessern. Gegenwärtig wird FHE hauptsächlich in vier Generationen/Familien eingeteilt.&lt;/p>
&lt;h3 id="zweite-generation-exakte-berechnung-von-ganzzahlen-bgv-bfv">Zweite Generation: Exakte Berechnung von Ganzzahlen (BGV, BFV)
&lt;/h3>&lt;p>Die &lt;strong>BGV (Brakerski-Gentry-Vaikuntanathan)&lt;/strong> und &lt;strong>BFV (Brakerski/Fan-Vercauteren)&lt;/strong> Schemata tauchten in den Jahren 2011-2012 auf. Diese basieren auf RLWE und eignen sich gut für modulare Arithmetik (exakte Berechnungen) mit ganzen Zahlen.
Sie unterstützen Batching-Technologien wie SIMD (Single Instruction, Multiple Data), die es ermöglichen, Tausende von Datensteckplätzen in einen einzigen riesigen Polynom-Geheimtext zu packen und sie alle auf einmal parallel zu berechnen.&lt;/p>
&lt;h3 id="dritte-generation-beschleunigung-des-bootstrapping-gsw-fhew-tfhe">Dritte Generation: Beschleunigung des Bootstrapping (GSW, FHEW, TFHE)
&lt;/h3>&lt;p>Das &lt;strong>GSW (Gentry-Sahai-Waters)&lt;/strong> Schema von 2013 vereinfachte die Struktur von FHE. Dies wurde weiterentwickelt zu einem der heutigen Mainstream-Schemata, &lt;strong>TFHE (Fast Fully Homomorphic Encryption over the Torus)&lt;/strong>.
Das Besondere an TFHE ist, dass sein Bootstrapping extrem schnell (im Millisekundenbereich) ist. Es ist stark bei Operationen auf Gatterebene (Logikschaltungen wie AND, XOR) und hat eine relativ kleine Geheimtextgröße, wodurch es sich zur schnellen Auswertung beliebiger Logikschaltungen eignet.&lt;/p>
&lt;h3 id="vierte-generation-spezialisierung-auf-näherungsberechnungen-und-maschinelles-lernen-ckks">Vierte Generation: Spezialisierung auf Näherungsberechnungen und maschinelles Lernen (CKKS)
&lt;/h3>&lt;p>Das 2017 von Cheon et al. vorgeschlagene &lt;strong>CKKS (Cheon-Kim-Kim-Song)&lt;/strong> Schema ist die definitive Technologie für den Schutz der Privatsphäre in der heutigen KI und beim maschinellen Lernen.
Während sich bisherige FHE auf &amp;ldquo;exakte Ganzzahlberechnungen&amp;rdquo; konzentrierten, unterstützt CKKS &lt;strong>&amp;ldquo;Näherungsberechnungen von Fließkommazahlen&amp;rdquo;&lt;/strong> im verschlüsselten Zustand. Es zeigt eine überwältigende Leistung bei Berechnungen mit reellen Zahlen, bei denen kleine Fehler toleriert werden, wie z.B. das Training und die Inferenz von neuronalen Netzen.&lt;/p>
&lt;p>Die folgende Tabelle fasst zusammen, wie Sie ein Schema basierend auf Ihrem Zweck auswählen.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Schema-Name&lt;/th>
&lt;th style="text-align:left">Bevorzugter Datentyp&lt;/th>
&lt;th style="text-align:left">Empfohlene Anwendungsfälle&lt;/th>
&lt;th style="text-align:left">Merkmale&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>BFV / BGV&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Ganzzahlen (Integer)&lt;/td>
&lt;td style="text-align:left">Genaue statistische Berechnungen, Aggregation von Finanzdaten, DB-Suche&lt;/td>
&lt;td style="text-align:left">Hoher Durchsatz durch SIMD-Batching&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>CKKS&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Reelle Zahlen (Real/Complex)&lt;/td>
&lt;td style="text-align:left">Maschinelles Lernen (DNN, logistische Regression), Signalverarbeitung&lt;/td>
&lt;td style="text-align:left">Beschleunigung durch Näherungsberechnungen, Reskalierung&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>TFHE&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Boolesche Werte (Boolean)&lt;/td>
&lt;td style="text-align:left">Beliebige Logikschaltungen, String-Suche, Auswertung nichtlinearer Funktionen&lt;/td>
&lt;td style="text-align:left">Ultraschnelles Bootstrapping (Millisekundenbereich)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="6-praxis-fhe-bibliotheken-und-konzeptioneller-code">6. Praxis: FHE-Bibliotheken und konzeptioneller Code
&lt;/h2>&lt;p>Heutzutage gibt es viele Open-Source-Bibliotheken, mit denen man FHE nutzen kann, ohne fundierte Kenntnisse der Kryptographie zu besitzen.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Microsoft SEAL (Simple Encrypted Arithmetic Library)&lt;/strong>: Eine C++-Bibliothek, die BFV, BGV und CKKS unterstützt. Einer der Industriestandards. Die Python-Anbindung &lt;strong>TenSEAL&lt;/strong> ist bei KI-Ingenieuren sehr beliebt.&lt;/li>
&lt;li>&lt;strong>Zama (Concrete)&lt;/strong>: Ein Framework basierend auf TFHE. Es kann in Rust/Python geschrieben werden und bietet die Funktion (Concrete ML), bestehende PyTorch-Modelle zu kompilieren und auf FHE auszuführen.&lt;/li>
&lt;li>&lt;strong>OpenFHE&lt;/strong>: Der Nachfolger von PALISADE, eine umfassende C++-Bibliothek, die alle gängigen Schemata unterstützt.&lt;/li>
&lt;/ul>
&lt;h3 id="beispiel-für-fhe-programmierung-in-python-tenseal">Beispiel für FHE-Programmierung in Python (TenSEAL)
&lt;/h3>&lt;p>Hier ist ein konzeptionelles Python-Codebeispiel unter Verwendung des CKKS-Schemas, das Vektoren aus reellen Zahlen addiert und multipliziert, während sie verschlüsselt bleiben.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">tenseal&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">ts&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. Kontext-Setup (inklusive Schlüsselerzeugung)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Verwendung des CKKS-Schemas, Polynomgrad auf 8192 gesetzt&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">context&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">context&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">SCHEME_TYPE&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CKKS&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">poly_modulus_degree&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">8192&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">coeff_mod_bit_sizes&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">60&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">40&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">40&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">60&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">context&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">generate_galois_keys&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">context&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">global_scale&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="mi">40&lt;/span> &lt;span class="c1"># Skalierungsfaktor für reelle Zahlen&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. Client-Seite: Daten verschlüsseln&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">vector1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mf">1.5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">2.5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">3.5&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">vector2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mf">2.0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">3.0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">4.0&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Klartext-Vektoren in Geheimtexte umwandeln (wird normalerweise auf der Client-Seite ausgeführt)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">enc_v1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ckks_vector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">context&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">vector1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">enc_v2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ckks_vector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">context&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">vector2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. Server-Seite: Operationen in verschlüsseltem Zustand (Schutz von Data in Use)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Der Server kennt den Klartext nicht, kann aber Addition und Multiplikation ausführen&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">enc_add&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">enc_v1&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">enc_v2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">enc_mul&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">enc_v1&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">enc_v2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 4. Client-Seite: Ergebnisse entschlüsseln&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Nur der Client mit dem privaten Schlüssel kann das Ergebnis sehen&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">res_add&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">enc_add&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decrypt&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">res_mul&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">enc_mul&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decrypt&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Entschlüsseltes Additionsergebnis: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">res_add&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Beispielausgabe: [3.5000001, 5.5000001, 7.5000002] (enthält aufgrund der Näherungsberechnung einen winzigen Fehler)&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;Entschlüsseltes Multiplikationsergebnis: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">res_mul&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Beispielausgabe: [3.0000002, 7.5000005, 14.0000003]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Wie aus dem obigen Code ersichtlich ist, können Sie Berechnungen zwischen Geheimtexten intuitiv schreiben, indem Sie Standard-Python-Operatoren wie in &lt;code>enc_v1 + enc_v2&lt;/code> überladen. Auf der Serverseite werden Vektoroperationen abgeschlossen, ohne den Inhalt der Vektoren zu kennen.&lt;/p>
&lt;hr>
&lt;h2 id="7-herausforderungen-von-fhe-leistung-und-hardware-beschleunigung">7. Herausforderungen von FHE: Leistung und Hardware-Beschleunigung
&lt;/h2>&lt;p>Während FHE theoretisch perfekte Sicherheit bietet, ist die größte Herausforderung bei seiner praktischen Anwendung der &lt;strong>&amp;ldquo;Leistungs-Overhead&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Rechenaufwand&lt;/strong>: Im Vergleich zu Berechnungen mit Klartexten sind Berechnungen mit Geheimtexten auf CPUs Tausende bis Zehntausende Male langsamer. Polynommultiplikation und Bootstrapping erfordern massive Mengen an FFT- (Fast Fourier Transform) oder NTT- (Number Theoretic Transform) Berechnungen.&lt;/li>
&lt;li>&lt;strong>Datenexpansion (Ciphertext Expansion)&lt;/strong>: Ein paar Byte Klartext können im verschlüsselten Zustand zu mehreren Megabyte werden. Dies übt großen Druck auf die Speicherbandbreite und die Netzwerkbandbreite aus.&lt;/li>
&lt;/ol>
&lt;h3 id="ansätze-für-hardware-lösungen">Ansätze für Hardware-Lösungen
&lt;/h3>&lt;p>Um diesen Overhead zu überwinden, treibt man weltweit die Entwicklung von FHE-spezifischen Hardware-Beschleunigern (ASIC, FPGA, GPU-Unterstützung) voran.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>GPU-Beschleunigung&lt;/strong>: Die Bemühungen schreiten voran, um NTT-Berechnungen und Bootstrapping mit leistungsstarken GPUs wie denen von NVIDIA zu parallelisieren, was eine zigfache Beschleunigung gegenüber Softwareimplementierungen meldet (z. B. 100x.ai, Zamas TFHE-rs CUDA-Backend).&lt;/li>
&lt;li>&lt;strong>DARPA DPRIVE-Projekt&lt;/strong>: Die US-amerikanische Defense Advanced Research Projects Agency (DARPA) fördert &amp;ldquo;DPRIVE (Data Protection in Virtual Environments)&amp;rdquo;, ein Projekt zur Entwicklung dedizierter Hardware, um die Berechnungsgeschwindigkeit von FHE auf ein Niveau anzuheben, das dem der Klartextverarbeitung entspricht (innerhalb des 10-fachen Overheads). Unternehmen wie Intel, Microsoft und Intellectual Ventures sind daran beteiligt.&lt;/li>
&lt;li>&lt;strong>Aufkommen der FPU (FHE Processing Unit)&lt;/strong>: Start-ups wie Cornami und Optalysys haben mit der Entwicklung von FHE-spezifischen Chips begonnen, die optisches Computing oder spezielle Siliziumarchitekturen nutzen.&lt;/li>
&lt;/ul>
&lt;p>In naher Zukunft wird es möglicherweise eine Zeit geben, in der &amp;ldquo;FPUs&amp;rdquo; standardmäßig in Servern und Cloud-Infrastrukturen installiert sind, ähnlich wie NPUs (Neural Processing Units) in der KI.&lt;/p>
&lt;hr>
&lt;h2 id="8-erwartete-anwendungsfälle">8. Erwartete Anwendungsfälle
&lt;/h2>&lt;p>Da FHE mittlerweile praktische Geschwindigkeiten erreicht, werden bahnbrechende Innovationen in den folgenden Bereichen erwartet.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Schutz der Privatsphäre in der medizinischen und genomischen Analyse&lt;/strong>:
Indem die von mehreren Krankenhäusern gehaltenen Patientenakten und DNA-Daten mit FHE verschlüsselt und von der Cloud-KI trainiert werden, können hochpräzise Krebsdiagnosemodelle und die Entwicklung neuer Medikamente durchgeführt werden, ohne gegen Datenschutzgesetze (wie HIPAA oder DSGVO) zu verstoßen.&lt;/li>
&lt;li>&lt;strong>Betrugserkennung und Anti-Geldwäsche (AML) für Finanzinstitute&lt;/strong>:
Konkurrierende Banken können gegenseitig ihre Daten in verschlüsselter Form abgleichen, um riesige illegale Überweisungsnetzwerke zu erkennen (Cross-Bank-Analyse), ohne Kundenkontoinformationen oder Transaktionshistorien preiszugeben.&lt;/li>
&lt;li>&lt;strong>Sichere KI-Inferenz-API (MaaS: Model as a Service)&lt;/strong>:
Benutzer verschlüsseln ihre eigene Stimme, Gesichtsbilder oder Prompts und senden sie an einen KI-Dienst (z.B. ein LLM wie ChatGPT). Der KI-Anbieter generiert Antworten, ohne die Eingabe des Benutzers jemals zu kennen, und gibt sie als Geheimtext zurück. Dies beseitigt vollständig die Sorge, dass &amp;ldquo;die KI persönliche Informationen lernt oder einsehen kann&amp;rdquo;.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="9-fazit-die-zukunft-der-kryptographie-geht-hin-zu-unsichtbaren-berechnungen">9. Fazit: Die Zukunft der Kryptographie geht hin zu &amp;ldquo;unsichtbaren Berechnungen&amp;rdquo;
&lt;/h2>&lt;p>Genauso wie die Erfindung der Public-Key-Kryptographie (RSA) in den 1970er Jahren die sichere Kommunikation (wie HTTPS) über das Internet ermöglichte, ist die Erfindung von FHE durch Craig Gentry einer der wichtigsten Meilensteine in der Geschichte der Kryptographie.&lt;/p>
&lt;p>Heute verlässt die vollständig homomorphe Verschlüsselung (FHE) die Forschungslabors und tritt in ein Stadium ein, in dem Microsoft, IBM, Intel, Google und viele Start-ups um die Kommerzialisierung wetteifern. Herausforderungen hinsichtlich der Rechenkosten und der Datengröße bestehen weiterhin, aber durch die Verfeinerung von Algorithmen und die Entwicklung von Hardware-Beschleunigern wird die Leistung in einem Tempo verbessert, das das Mooresche Gesetz übertrifft.&lt;/p>
&lt;p>In wenigen Jahren wird es nichts Besonderes mehr sein, &amp;ldquo;zu rechnen, während die Daten verschlüsselt bleiben&amp;rdquo;, sondern es wird eine Standard-Best-Practice für den Datenschutz bei Cloud-Diensten werden. FHE ist der Schlüssel zur Sicherheit der nächsten Generation und realisiert die &lt;strong>ultimative Balance zwischen Datenschutz und Datennutzung&lt;/strong> in unserer datengesteuerten Gesellschaft.&lt;/p></description></item><item><title>Mathematische Grundlagen der Elliptischen-Kurven-Kryptographie (ECC) und ihre Implementierung in C++</title><link>http://kenji.blog/de/p/elliptic-curve-cryptography-math-cpp/</link><pubDate>Fri, 11 Sep 2026 10:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/elliptic-curve-cryptography-math-cpp/</guid><description>&lt;img src="http://kenji.blog/p/elliptic-curve-cryptography-math-cpp/img/eyecatch.jpg" alt="Featured image of post Mathematische Grundlagen der Elliptischen-Kurven-Kryptographie (ECC) und ihre Implementierung in C++" />&lt;h1 id="mathematische-grundlagen-der-elliptischen-kurven-kryptographie-ecc-und-ihre-implementierung-in-c">Mathematische Grundlagen der Elliptischen-Kurven-Kryptographie (ECC) und ihre Implementierung in C++
&lt;/h1>&lt;p>In der modernen Kryptographie spielt die &lt;strong>Elliptische-Kurven-Kryptographie (Elliptic Curve Cryptography: ECC)&lt;/strong> eine äußerst wichtige Rolle. Von unserer täglichen Internetkommunikation (HTTPS/TLS) über die Secure Enclaves von Smartphones, Serverauthentifizierung via SSH, passwortlose Authentifizierung wie FIDO bis hin zu Krypto-Assets wie Bitcoin und Ethereum – man kann ohne Übertreibung sagen, dass die Vertrauensbasis unserer modernen digitalen Gesellschaft durch ECC gestützt wird.&lt;/p>
&lt;p>In diesem Artikel werden wir ausführlich erläutern, wie diese elliptische Kurven-Kryptographie funktioniert. Wir beginnen mit der schönen, aber komplexen mathematischen Theorie dahinter (algebraische Geometrie über endlichen Körpern), gehen dann zur tatsächlichen Implementierung in C++ über und behandeln schließlich sichere Codierungstechniken zur Verhinderung von Seitenkanalangriffen (Timing-Angriffen) – alles in einem überwältigenden Detailreichtum.&lt;/p>
&lt;hr>
&lt;h2 id="1-warum-elliptische-kurven-kryptographie-vergleich-mit-rsa">1. Warum Elliptische-Kurven-Kryptographie? (Vergleich mit RSA)
&lt;/h2>&lt;p>Lange Zeit war &lt;strong>RSA&lt;/strong> das Synonym für Public-Key-Kryptographie. Die Sicherheit von RSA basiert auf der &amp;ldquo;Schwierigkeit der Primfaktorzerlegung riesiger zusammengesetzter Zahlen&amp;rdquo;. Mit der steigenden Rechenleistung von Computern wurde es jedoch notwendig, die Schlüssellänge von RSA (die Bitlänge des Moduls) kontinuierlich zu erhöhen, um die Sicherheit aufrechtzuerhalten. Heutzutage wird eine Schlüssellänge von mindestens 2048 Bit empfohlen, für noch mehr Sicherheit sogar 3072 oder 4096 Bit.&lt;/p>
&lt;p>Im Gegensatz dazu basiert die Elliptische-Kurven-Kryptographie (ECC) auf einer anderen mathematischen Schwierigkeit: dem &lt;strong>&amp;ldquo;Diskreten Logarithmusproblem auf elliptischen Kurven (ECDLP)&amp;rdquo;&lt;/strong>. Bis heute wurde kein effizienter Algorithmus (wie z. B. ein Subexponentialzeit-Algorithmus) zur Lösung des ECDLP gefunden, und selbst die effizientesten bekannten Angriffsmethoden benötigen exponentielle Zeit.&lt;/p>
&lt;p>Aufgrund dieser Eigenschaft hat ECC den entscheidenden Vorteil, &lt;strong>dass es mit sehr kurzen Schlüssellängen die gleiche Sicherheitsstärke wie RSA erreichen kann&lt;/strong>.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:center">Sicherheitsstärke (Bit)&lt;/th>
&lt;th style="text-align:center">RSA-Schlüssellänge (Bit)&lt;/th>
&lt;th style="text-align:center">ECC-Schlüssellänge (Bit)&lt;/th>
&lt;th style="text-align:center">Längenverhältnis&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:center">80&lt;/td>
&lt;td style="text-align:center">1024&lt;/td>
&lt;td style="text-align:center">160&lt;/td>
&lt;td style="text-align:center">1:6&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">112&lt;/td>
&lt;td style="text-align:center">2048&lt;/td>
&lt;td style="text-align:center">224&lt;/td>
&lt;td style="text-align:center">1:9&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">128&lt;/td>
&lt;td style="text-align:center">3072&lt;/td>
&lt;td style="text-align:center">256&lt;/td>
&lt;td style="text-align:center">1:12&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">192&lt;/td>
&lt;td style="text-align:center">7680&lt;/td>
&lt;td style="text-align:center">384&lt;/td>
&lt;td style="text-align:center">1:20&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">256&lt;/td>
&lt;td style="text-align:center">15360&lt;/td>
&lt;td style="text-align:center">512&lt;/td>
&lt;td style="text-align:center">1:30&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Wie die obige Tabelle zeigt, benötigt RSA für eine Sicherheitsstärke von 128 Bit (die aktuelle Standardstärke) einen 3072-Bit-Schlüssel, während ECC mit nur 256 Bit auskommt. Dies ermöglicht eine Reduzierung des Rechenaufwands, einen geringeren Speicherverbrauch und die Einsparung von Netzwerkbandbreite. Dadurch ist ECC besonders in ressourcenbeschränkten Umgebungen wie IoT-Geräten und Smartcards überlegen.&lt;/p>
&lt;hr>
&lt;h2 id="2-mathematische-vorbereitung-gruppentheorie-und-endliche-körper">2. Mathematische Vorbereitung: Gruppentheorie und endliche Körper
&lt;/h2>&lt;p>Um die Elliptische-Kurven-Kryptographie wirklich zu verstehen, ist es notwendig, die grundlegenden Konzepte der abstrakten Algebra (Gruppen- und Körpertheorie) zu beherrschen. Hier fassen wir das Vorwissen zur Konstruktion von ECC kurz zusammen.&lt;/p>
&lt;h3 id="21-gruppen-group-und-abelsche-gruppen">2.1. Gruppen (Group) und abelsche Gruppen
&lt;/h3>&lt;p>Eine &lt;strong>Gruppe (Group)&lt;/strong> ist ein Paar $(G, +)$, bestehend aus einer Menge $G$ und einer binären Operation auf dieser Menge (hier als Addition $+$ bezeichnet), das die folgenden vier Axiome erfüllt:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Abgeschlossenheit (Closure)&lt;/strong>: Für beliebige $a, b \in G$ gilt $a + b \in G$.&lt;/li>
&lt;li>&lt;strong>Assoziativgesetz (Associativity)&lt;/strong>: Für beliebige $a, b, c \in G$ gilt $(a + b) + c = a + (b + c)$.&lt;/li>
&lt;li>&lt;strong>Existenz eines neutralen Elements (Identity element)&lt;/strong>: Es existiert ein Element $e \in G$, sodass für jedes $a \in G$ gilt: $a + e = e + a = a$. Bei additiven Gruppen wird dieses neutrale Element meist als $0$ oder $\mathcal{O}$ geschrieben.&lt;/li>
&lt;li>&lt;strong>Existenz inverser Elemente (Inverse element)&lt;/strong>: Zu jedem $a \in G$ existiert ein Element $b \in G$, sodass $a + b = b + a = e$. Dieses $b$ wird als $-a$ bezeichnet.&lt;/li>
&lt;/ol>
&lt;p>Eine Gruppe, in der die Reihenfolge der Operanden das Ergebnis nicht verändert, d. h. die folgende Bedingung erfüllt ist, wird als &lt;strong>abelsche Gruppe (kommutative Gruppe)&lt;/strong> bezeichnet:&lt;/p>
&lt;ol start="5">
&lt;li>&lt;strong>Kommutativgesetz (Commutativity)&lt;/strong>: Für beliebige $a, b \in G$ gilt $a + b = b + a$.&lt;/li>
&lt;/ol>
&lt;p>Die Menge der Punkte auf einer elliptischen Kurve bildet eine solche &lt;strong>abelsche Gruppe&lt;/strong>, wenn wir eine spezifische Additionsregel definieren.&lt;/p>
&lt;h3 id="22-endliche-körper-finite-field">2.2. Endliche Körper (Finite Field)
&lt;/h3>&lt;p>In der Kryptographietheorie verwenden wir keine Körper mit kontinuierlichen und unendlich vielen Elementen wie die reellen oder komplexen Zahlen, sondern &lt;strong>endliche Körper (Finite Fields)&lt;/strong> oder Galois-Körper (Galois Fields), deren Elementanzahl endlich ist.&lt;/p>
&lt;p>Der grundlegendste endliche Körper ist der &lt;strong>Primkörper $\mathbb{F}_p$&lt;/strong> unter Verwendung einer Primzahl $p$. Dies ist die Menge der ganzen Zahlen $\{0, 1, 2, \dots, p-1\}$ versehen mit den vier Grundrechenarten (Addition, Subtraktion, Multiplikation, Division) modulo $p$ (dem Rest bei Division durch $p$).&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Addition&lt;/strong>: $(a + b) \pmod p$&lt;/li>
&lt;li>&lt;strong>Subtraktion&lt;/strong>: $(a - b) \pmod p$&lt;/li>
&lt;li>&lt;strong>Multiplikation&lt;/strong>: $(a \times b) \pmod p$&lt;/li>
&lt;li>&lt;strong>Division&lt;/strong>: $a \times b^{-1} \pmod p$ (wobei $b^{-1}$ das multiplikative Inverse von $b$ modulo $p$ ist)&lt;/li>
&lt;/ul>
&lt;p>Die Berechnung des &lt;strong>multiplikativen Inversen (Modular Multiplicative Inverse)&lt;/strong> ist in der kryptographischen Implementierung extrem wichtig. Um ein $b^{-1}$ zu finden, das $b \times b^{-1} \equiv 1 \pmod p$ erfüllt, werden hauptsächlich die folgenden zwei Algorithmen verwendet:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Erweiterter euklidischer Algorithmus (Extended Euclidean Algorithm)&lt;/strong>: Er ist schnell, aber je nach Implementierung ist die Ausführungszeit vom Eingabewert abhängig, was das Risiko von Timing-Angriffen birgt.&lt;/li>
&lt;li>&lt;strong>Kleiner fermatscher Satz (Fermat&amp;rsquo;s Little Theorem)&lt;/strong>: Wenn $p$ eine Primzahl ist und $b \neq 0$, gilt $b^{p-1} \equiv 1 \pmod p$. Teilt man beide Seiten durch $b$, erhält man $b^{p-2} \equiv b^{-1} \pmod p$. Das heißt, durch Berechnung von $b$ hoch $p-2$ erhält man das Inverse. Da modulare Potenzierung leicht in konstanter Zeit (Constant-Time) implementiert werden kann, wird dies bei kryptographischen Implementierungen bevorzugt.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="3-die-gleichung-und-geometrie-der-elliptischen-kurve">3. Die Gleichung und Geometrie der elliptischen Kurve
&lt;/h2>&lt;h3 id="31-die-weierstraß-normalform">3.1. Die Weierstraß-Normalform
&lt;/h3>&lt;p>Eine &lt;strong>elliptische Kurve (Elliptic Curve)&lt;/strong> ist im Allgemeinen eine ebene Kurve, die durch die folgende Gleichung definiert wird, bekannt als &lt;strong>Weierstraß-Normalform (Weierstrass normal form)&lt;/strong>:&lt;/p>
$$ y^2 = x^3 + ax + b $$
&lt;p>Hierbei sind $a$ und $b$ Konstanten. Als Bedingung dafür, dass die Kurve keine Singularitäten (Selbstüberschneidungen oder Spitzen) aufweist (d. h. eine glatte Kurve ist), darf die folgende &lt;strong>Diskriminante (Discriminant) $\Delta$&lt;/strong> nicht null sein:&lt;/p>
$$ \Delta = -16(4a^3 + 27b^2) \neq 0 $$
&lt;p>Da Kurven mit Singularitäten die kryptographische Sicherheit beeinträchtigen, werden immer Koeffizienten $a, b$ gewählt, die diese Bedingung erfüllen.&lt;/p>
&lt;h3 id="32-der-punkt-im-unendlichen-point-at-infinity">3.2. Der Punkt im Unendlichen (Point at Infinity)
&lt;/h3>&lt;p>Um die elliptische Kurve mathematisch zu einer vollständigen Gruppe zu machen, führen wir neben den Punkten auf der Ebene einen virtuellen Punkt ein, den &lt;strong>&amp;ldquo;Punkt im Unendlichen&amp;rdquo; (Point at Infinity)&lt;/strong>. Dieser wird mit $\mathcal{O}$ bezeichnet.&lt;/p>
&lt;p>Der Punkt im Unendlichen $\mathcal{O}$ ist definiert als der Punkt, an dem sich alle vertikalen Linien in der unendlichen Ferne schneiden. In der Gruppentheorie fungiert dieser Punkt im Unendlichen $\mathcal{O}$ als &lt;strong>neutrales Element&lt;/strong> (die Null) der Addition.&lt;/p>
&lt;p>Das heißt, für jeden beliebigen Punkt $P$ auf der Kurve gilt:
&lt;/p>
$$ P + \mathcal{O} = \mathcal{O} + P = P $$
&lt;p>Zudem ist das Inverse $-P$ eines Punktes $P = (x, y)$ definiert als der an der x-Achse gespiegelte Punkt $(x, -y)$. Daher gilt:
&lt;/p>
$$ P + (-P) = \mathcal{O} $$
&lt;hr>
&lt;h2 id="4-gruppenoperationen-auf-elliptischen-kurven-punktaddition-und--verdopplung">4. Gruppenoperationen auf elliptischen Kurven (Punktaddition und -verdopplung)
&lt;/h2>&lt;p>Die Grundlage der Elliptischen-Kurven-Kryptographie ist die &lt;strong>&amp;ldquo;Addition&amp;rdquo;&lt;/strong> von Punkten auf der Kurve. Diese unterscheidet sich von der gewöhnlichen Addition von Ganzzahlen und wird basierend auf geometrischen Operationen definiert.&lt;/p>
&lt;h3 id="41-geometrische-addition-tangent-and-chord-method">4.1. Geometrische Addition (Tangent and Chord Method)
&lt;/h3>&lt;p>Das Verfahren, um zwei verschiedene Punkte $P$ und $Q$ auf der Kurve zu addieren, um einen neuen Punkt $R$ ($R = P + Q$) zu finden, ist wie folgt:&lt;/p>
&lt;ol>
&lt;li>Ziehe eine Gerade (Sekante) durch den Punkt $P$ und den Punkt $Q$.&lt;/li>
&lt;li>Diese Gerade schneidet die elliptische Kurve garantiert in einem dritten Punkt (nennen wir ihn $-R$). (※ Gemäß den Sätzen der algebraischen Geometrie)&lt;/li>
&lt;li>Der Punkt, den man erhält, wenn man den Schnittpunkt $-R$ an der x-Achse spiegelt (also das Vorzeichen der y-Koordinate umkehrt), ist der gesuchte Punkt $R$.&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph TD
Step1["Ziehe eine Gerade durch P(x1, y1) und Q(x2, y2)"] --> Step2["Finde den dritten Schnittpunkt -R mit der Kurve"]
Step2 --> Step3["Spiegele -R an der x-Achse, um R(x3, y3) zu erhalten"]
Step3 -.-> Result["Dies ist R = P + Q"]&lt;/div>
&lt;h3 id="42-punktverdopplung-point-doubling">4.2. Punktverdopplung (Point Doubling)
&lt;/h3>&lt;p>Wenn man denselben Punkt $P$ zu sich selbst addiert ($P + P = 2P$), kann man keine Gerade durch zwei Punkte ziehen. In diesem Fall zieht man &lt;strong>die Tangente an die Kurve im Punkt $P$&lt;/strong>.&lt;/p>
&lt;ol>
&lt;li>Ziehe die Tangente an die Kurve im Punkt $P$.&lt;/li>
&lt;li>Diese Tangente schneidet die Kurve in einem weiteren Punkt $-R$.&lt;/li>
&lt;li>Der an der x-Achse gespiegelte Schnittpunkt ist der gesuchte Punkt $R = 2P$.&lt;/li>
&lt;/ol>
&lt;h3 id="43-algebraische-berechnungsformeln">4.3. Algebraische Berechnungsformeln
&lt;/h3>&lt;p>Wir übersetzen die geometrischen Operationen in algebraische Formeln, die von einem Computer berechnet werden können.
Alle Operationen werden über dem &lt;strong>endlichen Körper $\mathbb{F}_p$ (modulo $p$)&lt;/strong> durchgeführt.&lt;/p>
&lt;p>Seien die Punkte $P = (x_1, y_1)$ und $Q = (x_2, y_2)$.
Zudem sei der berechnete Ergebnispunkt $R = P + Q = (x_3, y_3)$.&lt;/p>
&lt;p>Die Steigung der Geraden nennen wir $\lambda$ (Lambda).&lt;/p>
&lt;p>&lt;strong>[Fall 1: Wenn $P \neq Q$ (Punktaddition)]&lt;/strong>
Die Steigung $\lambda$ ist die Änderungsrate zwischen den beiden Punkten.
&lt;/p>
$$ \lambda \equiv \frac{y_2 - y_1}{x_2 - x_1} \pmod p $$
$$ \lambda \equiv (y_2 - y_1) \cdot (x_2 - x_1)^{-1} \pmod p $$
&lt;p>Mit diesem $\lambda$ können $x_3, y_3$ wie folgt berechnet werden:
&lt;/p>
$$ x_3 \equiv \lambda^2 - x_1 - x_2 \pmod p $$
$$ y_3 \equiv \lambda(x_1 - x_3) - y_1 \pmod p $$
&lt;p>&lt;strong>[Fall 2: Wenn $P = Q$ (Punktverdopplung)]&lt;/strong>
Die Steigung $\lambda$ ist die Steigung der Tangente, die durch Ableitung ermittelt wird. (Wir leiten $y^2 = x^3 + ax + b$ implizit ab)
&lt;/p>
$$ 2y \cdot y' = 3x^2 + a \implies y' = \frac{3x^2 + a}{2y} $$
&lt;p>
Daher gilt:
&lt;/p>
$$ \lambda \equiv (3x_1^2 + a) \cdot (2y_1)^{-1} \pmod p $$
&lt;p>Die Formeln für $x_3, y_3$ haben die gleiche Form wie bei der Addition, aber da $x_2 = x_1$, ergibt sich:
&lt;/p>
$$ x_3 \equiv \lambda^2 - 2x_1 \pmod p $$
$$ y_3 \equiv \lambda(x_1 - x_3) - y_1 \pmod p $$
&lt;blockquote>
&lt;p>[!IMPORTANT]
Diese Formeln enthalten &lt;strong>Divisionen (Berechnung des modularen Inversen)&lt;/strong> wie $(x_2 - x_1)^{-1}$ und $(2y_1)^{-1}$. Da die Berechnung des modularen Inversen sehr rechenintensiv ist, werden in tatsächlichen Implementierungen allgemein projektive Koordinatensysteme wie die &lt;strong>&amp;ldquo;Jacobi-Koordinaten (Jacobian Coordinates)&amp;rdquo;&lt;/strong> verwendet, die die Division verzögern.&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h2 id="5-skalarmultiplikation-und-das-diskrete-logarithmusproblem-ecdlp">5. Skalarmultiplikation und das Diskrete Logarithmusproblem (ECDLP)
&lt;/h2>&lt;p>Die rechenintensivste Operation in der Elliptischen-Kurven-Kryptographie, die gleichzeitig den Kern der Sicherheit bildet, ist die &lt;strong>Skalarmultiplikation (Scalar Multiplication)&lt;/strong>.&lt;/p>
&lt;h3 id="51-was-ist-skalarmultiplikation">5.1. Was ist Skalarmultiplikation?
&lt;/h3>&lt;p>Die Operation, einen Punkt $P$ $k$-mal zu addieren, wird als Skalarmultiplikation bezeichnet und als $kP$ geschrieben.
&lt;/p>
$$ kP = \underbrace{P + P + \dots + P}_{k\text{ Mal}} $$
&lt;p>Hierbei ist $k$ eine sehr große Ganzzahl (zum Beispiel eine 256-Bit-Ganzzahl).&lt;/p>
&lt;h3 id="52-diskretes-logarithmusproblem-auf-elliptischen-kurven-ecdlp">5.2. Diskretes Logarithmusproblem auf elliptischen Kurven (ECDLP)
&lt;/h3>&lt;p>Die Sicherheit der Elliptischen-Kurven-Kryptographie beruht auf der Schwierigkeit des folgenden Problems:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Diskretes Logarithmusproblem auf elliptischen Kurven (Elliptic Curve Discrete Logarithm Problem: ECDLP)&lt;/strong>
Gegeben sei ein bekannter Punkt $P$ (Basispunkt) und ein berechneter Punkt $Q$. Finde den Skalar $k$, der $Q = kP$ erfüllt.&lt;/p>
&lt;/blockquote>
&lt;p>Es ist mit dem unten beschriebenen Algorithmus einfach (in polynomieller Zeit machbar), $Q$ aus $k$ und $P$ zu berechnen (Vorwärtsrichtung), aber es ist praktisch unmöglich, $k$ aus $P$ und $Q$ zurückzurechnen (Rückwärtsrichtung), da es außer Brute-Force-Suchen keine effiziente Lösungsmethode gibt (Einwegfunktion).
In kryptographischen Protokollen entspricht &lt;strong>$k$ dem &amp;ldquo;privaten Schlüssel&amp;rdquo; und $Q$ dem &amp;ldquo;öffentlichen Schlüssel&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;h3 id="53-double-and-add-algorithmus">5.3. Double-and-Add-Algorithmus
&lt;/h3>&lt;p>Wenn $k$ eine riesige Zahl ist (z. B. $2^{256}$), würde die naive Addition von $P$ um $k$-mal das Ende der Lebensdauer des Universums überdauern. Daher wird die &lt;strong>Double-and-Add-Methode (binäre Methode)&lt;/strong> verwendet, um die Skalarmultiplikation schnell durchzuführen.&lt;/p>
&lt;p>Dies ist die elliptische Kurvenversion der &amp;ldquo;binären Exponentiation&amp;rdquo;, mit der die Potenzierung von Ganzzahlen schnell berechnet wird. Der Skalar $k$ wird binär dargestellt und vom höchstwertigen Bit an verarbeitet.&lt;/p>
&lt;ol>
&lt;li>Initialisiere den Punkt $R$, der das Ergebnis hält, mit $\mathcal{O}$.&lt;/li>
&lt;li>Wiederhole für jedes Bit von $k$, vom höchstwertigen bis zum niederwertigsten:
&lt;ul>
&lt;li>Verdopple $R$ (Point Doubling: $R = 2R$)&lt;/li>
&lt;li>Wenn das aktuelle Bit &lt;code>1&lt;/code> ist, addiere $P$ zu $R$ (Point Addition: $R = R + P$)&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>Durch diesen Algorithmus wird der Rechenaufwand drastisch von $O(k)$ auf $O(\log_2 k)$ reduziert, was die Berechnung in realistischer Zeit (im Millisekundenbereich) ermöglicht.&lt;/p>
&lt;hr>
&lt;h2 id="6-elliptic-curve-diffie-hellman-ecdh-schlüsselaustausch">6. Elliptic Curve Diffie-Hellman (ECDH) Schlüsselaustausch
&lt;/h2>&lt;p>Hier erklären wir den Mechanismus des &lt;strong>ECDH (Elliptic Curve Diffie-Hellman) Schlüsselaustauschprotokolls&lt;/strong>, welches das repräsentativste Anwendungsbeispiel für ECC ist. ECDH ist ein Mechanismus, mit dem Alice und Bob sicher einen gemeinsamen geheimen Schlüssel (Sitzungsschlüssel) über einen abhörbaren Kommunikationskanal generieren und austauschen können (dies ist der Kern des TLS-Handshakes).&lt;/p>
&lt;p>&lt;strong>[Vorab-Parameter (Domain Parameters)]&lt;/strong>
Beide Parteien haben sich im Voraus auf die zu verwendende elliptische Kurve $E$, die Primzahl $p$ und den Basispunkt $G$ geeinigt. (Beispiele sind NIST P-256 oder secp256k1)&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant Alice as "Alice"
participant Bob as "Bob"
Note over Alice,Bob: "Öffentliche Parameter: Kurve E, Basispunkt G, Primzahl p"
Alice->>Alice: "Generiere privaten Schlüssel d_A (zufällige Ganzzahl)"
Alice->>Alice: "Berechne öffentlichen Schlüssel Q_A = d_A * G"
Bob->>Bob: "Generiere privaten Schlüssel d_B (zufällige Ganzzahl)"
Bob->>Bob: "Berechne öffentlichen Schlüssel Q_B = d_B * G"
Alice->>Bob: "Sende öffentlichen Schlüssel Q_A (Klartext)"
Bob->>Alice: "Sende öffentlichen Schlüssel Q_B (Klartext)"
Alice->>Alice: "Berechne gemeinsames Geheimnis S = d_A * Q_B"
Bob->>Bob: "Berechne gemeinsames Geheimnis S = d_B * Q_A"
Note over Alice,Bob: "S = d_A * (d_B * G) = d_B * (d_A * G) = (d_A * d_B) * G"
Note over Alice,Bob: "Die berechneten Ergebnisse S von beiden stimmen exakt überein!"&lt;/div>
&lt;p>Ein Lauscher (Eve) kann $G$, $Q_A$ und $Q_B$, die über den Kommunikationsweg fließen, abfangen, aber aufgrund der Schwierigkeit des ECDLP kann er Alices privaten Schlüssel $d_A$ nicht aus $Q_A = d_A \cdot G$ ermitteln. Außerdem ergibt die Multiplikation von $Q_A$ und $Q_B$ nicht den gemeinsamen Schlüssel $S$, sodass der Lauscher $S$ nicht berechnen kann.&lt;/p>
&lt;hr>
&lt;h2 id="7-fallstricke-bei-der-implementierung-seitenkanalangriffe-und-gegenmaßnahmen">7. Fallstricke bei der Implementierung: Seitenkanalangriffe und Gegenmaßnahmen
&lt;/h2>&lt;p>Selbst ein theoretisch perfekter kryptographischer Algorithmus kann im Prozess seiner Implementierung als Programm Schwachstellen aufweisen. Das sind die sogenannten &lt;strong>&amp;ldquo;Seitenkanalangriffe&amp;rdquo; (Side-Channel Attacks)&lt;/strong>.&lt;/p>
&lt;h3 id="71-timing-angriffe-timing-attack">7.1. Timing-Angriffe (Timing Attack)
&lt;/h3>&lt;p>Schauen wir uns den zuvor erwähnten Double-and-Add-Algorithmus noch einmal an.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Pseudocode eines anfälligen Double-and-Add
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="n">R&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Infinity&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">255&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">--&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">R&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PointDoubling&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Wird immer ausgeführt
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">bit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">R&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PointAddition&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Wird nur ausgeführt, wenn das Bit 1 ist!
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Diese Implementierung hat einen fatalen Fehler. Da Point Addition ausgeführt wird, wenn das Bit &lt;code>1&lt;/code> ist, ist &lt;strong>die Berechnungszeit geringfügig länger&lt;/strong>, als wenn das Bit &lt;code>0&lt;/code> ist. Darüber hinaus ändern sich auch die Sprungvorhersage (Branch Prediction) des Prozessors und das Verhalten des Cache-Speichers.
Indem ein Angreifer diesen winzigen Unterschied in der Berechnungszeit (oder dem Stromverbrauch) tausendfach statistisch beobachtet, &lt;strong>kann er die Bitfolge des privaten Schlüssels $k$ Bit für Bit vollständig rekonstruieren&lt;/strong>. Das ist ein Timing-Angriff.&lt;/p>
&lt;h3 id="72-constant-time-implementierung-montgomery-ladder">7.2. Constant-Time-Implementierung: Montgomery Ladder
&lt;/h3>&lt;p>Um Timing-Angriffe zu verhindern, muss man einen Algorithmus wählen, bei dem &lt;strong>die Abfolge der ausgeführten Befehle und die Berechnungszeit unabhängig vom Bitwert des privaten Schlüssels immer konstant (Constant-Time) sind&lt;/strong>.&lt;/p>
&lt;p>Das typischste Beispiel dafür ist die &lt;strong>Montgomery Ladder (Montgomery-Leiter)&lt;/strong>.&lt;/p>
&lt;div class="mermaid">graph TD
Start["Initialisierung: R0 = O, R1 = P"] --> LoopStart["Für jedes Bit i (vom höchstwertigen)"]
LoopStart --> Cond{"Wert von k_i?"}
Cond -->|0| Branch0["R1 = R0 + R1&lt;br>R0 = 2 * R0"]
Cond -->|1| Branch1["R0 = R0 + R1&lt;br>R1 = 2 * R1"]
Branch0 --> LoopEnd["Zum nächsten Bit"]
Branch1 --> LoopEnd
LoopEnd --> LoopStart
LoopStart -.->|"Alle Bits abgeschlossen"| End["Ende: R0 ist das Ergebnis (kP)"]&lt;/div>
&lt;p>Das Schöne an der Montgomery Ladder ist, dass unabhängig davon, ob das Bit &lt;code>0&lt;/code> oder &lt;code>1&lt;/code> ist, &lt;strong>&amp;ldquo;immer genau eine Point Addition und eine Point Doubling&amp;rdquo;&lt;/strong> ausgeführt werden. Dadurch wird die Datenabhängigkeit der Berechnungszeit vollständig eliminiert.&lt;/p>
&lt;p>Wenn jedoch die Verzweigung (&lt;code>if (k_i == 0)&lt;/code>) selbst vorhanden ist, bleibt das Risiko bestehen, dass die Ausführungszeit durch Compileroptimierungen oder die Sprungvorhersage der CPU schwankt. Aus diesem Grund werden in tatsächlichen Constant-Time-Implementierungen bedingte Verzweigungen (&lt;code>if&lt;/code>-Anweisungen) vermieden und stattdessen &lt;strong>bedingtes Vertauschen (Conditional Swap) mit bitweisen Operationen&lt;/strong> verwendet.&lt;/p>
&lt;hr>
&lt;h2 id="8-implementierung-der-elliptischen-kurven-kryptographie-in-c">8. Implementierung der Elliptischen-Kurven-Kryptographie in C++
&lt;/h2>&lt;p>Von nun an werden wir die Theorie in C++-Code umsetzen. Praktische Krypto-Bibliotheken (wie OpenSSL oder libsodium) verwenden hochentwickelte Assembler-Optimierungen und Jacobi-Koordinaten, aber um das mathematische Verständnis zu vertiefen, zeigen wir hier das Gerüst einer &lt;strong>leicht verständlichen Constant-Time-Implementierung mit affinen Koordinaten&lt;/strong>.&lt;/p>
&lt;p>Wir gehen davon aus, dass wir &lt;code>boost::multiprecision::cpp_int&lt;/code> für die Berechnungen mit großen Zahlen verwenden.&lt;/p>
&lt;h3 id="81-modulo-arithmetik-und-inversen">8.1. Modulo-Arithmetik und Inversen
&lt;/h3>&lt;p>Zunächst definieren wir Hilfsfunktionen für Operationen auf endlichen Körpern. Wir implementieren die Inversen-Berechnung mit dem kleinen fermatschen Satz.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;stdexcept&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;boost/multiprecision/cpp_int.hpp&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="k">namespace&lt;/span> &lt;span class="n">boost&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">multiprecision&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Beispiel: Parameter und Primzahl p für secp256k1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">p&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">7&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Modulo-Operation, die einen positiven Rest zurückgibt
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nl">m&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">r&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Modulare Exponentiation (x^y mod m)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">powerMod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">exp&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">base&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">exp&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">exp&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">res&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">base&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">base&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exp&lt;/span> &lt;span class="o">/=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">res&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Modulares Inverses mit dem kleinen fermatschen Satz
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">modInverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Annahme, dass m eine Primzahl ist: n^(m-2) ≡ n^(-1) mod m
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">powerMod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="82-darstellung-von-punkten-und-gruppenoperationen-additionverdopplung">8.2. Darstellung von Punkten und Gruppenoperationen (Addition/Verdopplung)
&lt;/h3>&lt;p>Wir definieren eine &lt;code>Point&lt;/code>-Struktur, die den Punkt im Unendlichen durch ein Flag verwaltet, und implementieren die Additionsformeln.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">struct&lt;/span> &lt;span class="nc">Point&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="n">isInfinity&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Erzeugung des Punktes im Unendlichen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">isInfinity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">true&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Erzeugung eines normalen Punktes
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">isInfinity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">false&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Punktaddition auf der elliptischen Kurve (R = P + Q)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="nf">pointAdd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isInfinity&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isInfinity&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// P + (-P) = Punkt im Unendlichen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">lambda&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Point Doubling (Wenn P = Q)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// lambda = (3x^2 + a) / 2y
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">den&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">modInverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lambda&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">den&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Point Addition (Wenn P != Q)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// lambda = (y2 - y1) / (x2 - x1)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">den&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">modInverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lambda&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">den&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x3&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">lambda&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">lambda&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">y3&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">lambda&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">x3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y3&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="83-implementierung-des-constant-time-conditional-swap">8.3. Implementierung des Constant-Time Conditional Swap
&lt;/h3>&lt;p>Wenn der Inhalt von Variablen basierend auf dem Bitwert des privaten Schlüssels vertauscht wird, erfolgt das Vertauschen ausschließlich durch Bitoperationen (Maskierung) ohne die Verwendung von &lt;code>if&lt;/code>-Anweisungen. Dadurch wird der Ausführungspfad völlig konstant.&lt;/p>
&lt;blockquote>
&lt;p>[!TIP]
In der Praxis sind Klassen für Ganzzahlen mit mehrfacher Genauigkeit, die dynamisch allokiert werden (wie &lt;code>cpp_int&lt;/code>), nicht für Constant-Time-Verarbeitung geeignet. Das liegt daran, dass durch Speicherzuweisung und sich ändernde Array-Größen Timing-Informationen durchsickern. In praktischen Bibliotheken werden stattdessen feste Längen (z. B. ein Array mit 4 Elementen von uint64_t) verwendet, und Maskierungsoperationen auf Bitebene implementiert. Das Folgende ist ein konzeptionelles Beispiel.&lt;/p>
&lt;/blockquote>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Konzeptioneller Constant-Time Swap (ausgehend von Ganzzahlen fester Länge)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Wenn das Bit 1 ist, tausche P1 und P2; wenn es 0 ist, nicht.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">void&lt;/span> &lt;span class="nf">cswap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">bit&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// bit ist 0 oder 1. Die Maske ist alle Bits 1 (0xFF..), wenn bit=1, und alle Bits 0, wenn bit=0.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// (Hier wird zur Erklärung angenommen, dass w jedes Wort der BigInt-Klasse fester Länge ist)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="cm">/*
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> uint64_t mask = 0 - (uint64_t)bit;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> for (int i = 0; i &amp;lt; NUM_WORDS; i++) {
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> uint64_t dummy = mask &amp;amp; (P1.x.words[i] ^ P2.x.words[i]);
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> P1.x.words[i] ^= dummy;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> P2.x.words[i] ^= dummy;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> // Die y-Koordinate und das isInfinity-Flag werden auf ähnliche Weise verarbeitet
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ※ Ein vollständiger Constant-Time-Swap mit boost::multiprecision ist schwierig,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// daher beschränken wir uns hier auf die Simulation durch Verzweigung zum Verständnis der Logik.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">bit&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">P1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">P2&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="84-skalarmultiplikation-durch-montgomery-ladder">8.4. Skalarmultiplikation durch Montgomery Ladder
&lt;/h3>&lt;p>Wir kombinieren das zuvor beschriebene &lt;code>pointAdd&lt;/code> und &lt;code>cswap&lt;/code>, um eine sichere Skalarmultiplikation zu implementieren.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Skalarmultiplikation k * P (Montgomery Ladder Methode)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="nf">scalarMultiply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">k&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Point&lt;/span> &lt;span class="n">R0&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// Punkt im Unendlichen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Point&lt;/span> &lt;span class="n">R1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Hole die Bitlänge von k (256 Bit für secp256k1)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">numBits&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">256&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">numBits&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">--&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Hole den Wert des i-ten Bits (0 oder 1)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">bit&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">static_cast&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">uint8_t&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bit_test&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Wenn bit == 1, tausche R0 und R1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cswap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">bit&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Führe immer die gleichen Operationen aus (Point Addition und Point Doubling)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">R1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pointAdd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">R0&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pointAdd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Wenn bit == 1 war, tausche erneut, um den Zustand wiederherzustellen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cswap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">bit&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">R0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Durch diese Implementierungslogik wird – unabhängig davon, ob jedes Bit des Skalars $k$ eine &lt;code>0&lt;/code> oder &lt;code>1&lt;/code> ist – der in jeder Schleifeniteration ausgeführte Ablauf (&lt;code>cswap&lt;/code> $\to$ &lt;code>pointAdd&lt;/code> $\to$ &lt;code>pointAdd&lt;/code> $\to$ &lt;code>cswap&lt;/code>) völlig identisch. Dies verhindert effektiv das Durchsickern von Geheiminformationen durch Timing- oder Cache-Zugriffsmusterunterschiede.&lt;/p>
&lt;hr>
&lt;h2 id="9-zusammenfassung">9. Zusammenfassung
&lt;/h2>&lt;p>Die Elliptische-Kurven-Kryptographie (ECC) mag auf den ersten Blick seltsam erscheinen: &amp;ldquo;Warum wird aus einer geometrischen Operation wie dem Ziehen einer Gerade und dem Spiegeln eines Schnittpunkts eine Kryptographie?&amp;rdquo; Wenn man diese Operationen jedoch auf die diskrete Welt endlicher Körper abbildet, entsteht als Produkt der wundersamen Verschmelzung von Mathematik und Kryptographie eine hervorragende Einwegfunktion (das Diskrete Logarithmusproblem).&lt;/p>
&lt;p>Dieser Artikel hat die folgenden wichtigen Punkte behandelt:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Vorteile gegenüber RSA&lt;/strong>: Es bietet starke Sicherheit mit sehr kurzen Schlüssellängen und ist ideal für das moderne Mobile- und IoT-Zeitalter.&lt;/li>
&lt;li>&lt;strong>Grundlagen der Gruppentheorie und endlicher Körper&lt;/strong>: Die inneren mathematischen Strukturen, die das Fundament von ECC bilden.&lt;/li>
&lt;li>&lt;strong>Formeln für Addition und Verdopplung&lt;/strong>: Wie algebraische Gruppenoperationen mit der Weierstraß-Gleichung implementiert werden.&lt;/li>
&lt;li>&lt;strong>Bedrohung durch Seitenkanalangriffe&lt;/strong>: Wie bedingte Verzweigungen, die von den Bits eines privaten Schlüssels abhängen, fatale Schwachstellen schaffen.&lt;/li>
&lt;li>&lt;strong>Constant-Time-Implementierung&lt;/strong>: C++-Codierungstechniken, die Montgomery Ladder und Conditional Swap verwenden, um das Verhalten auf Hardwareebene zu homogenisieren und Angriffe zu verhindern.&lt;/li>
&lt;/ol>
&lt;p>In einer Produktionsumgebung eine eigene Krypto-Bibliothek zu schreiben, birgt ein extrem hohes Sicherheitsrisiko und wird daher nicht empfohlen (&amp;ldquo;Don&amp;rsquo;t roll your own crypto&amp;rdquo;). Die tiefgreifende Kenntnis der intern ablaufenden Algorithmen und mathematischen Hintergründe wird jedoch zu einer unschätzbaren und mächtigen Waffe für Ingenieure, die sicherere und leistungsfähigere Systeme entwerfen und betreiben wollen.&lt;/p>
&lt;p>Im nächsten Artikel werden wir noch tiefer auf den &lt;strong>ECDSA (Elliptic Curve Digital Signature Algorithm)&lt;/strong>, einen digitalen Signaturalgorithmus auf Basis elliptischer Kurven, sowie auf die in Bitcoin verwendeten &lt;strong>Schnorr-Signaturen&lt;/strong> eingehen.&lt;/p></description></item><item><title>Gibt es einen Algorithmus, der das GNFS (Allgemeines Zahlkörpersieb) übertrifft?</title><link>http://kenji.blog/de/p/beyond-gnfs-integer-factorization-algorithms/</link><pubDate>Fri, 11 Sep 2026 09:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/beyond-gnfs-integer-factorization-algorithms/</guid><description>&lt;img src="http://kenji.blog/p/beyond-gnfs-integer-factorization-algorithms/img/eyecatch.jpg" alt="Featured image of post Gibt es einen Algorithmus, der das GNFS (Allgemeines Zahlkörpersieb) übertrifft?" />&lt;h2 id="1-einführung-primfaktorzerlegung-und-die-grundlage-der-modernen-kryptographie">1. Einführung: Primfaktorzerlegung und die Grundlage der modernen Kryptographie
&lt;/h2>&lt;p>Die Sicherheit der Internetkommunikation in der modernen Gesellschaft hängt stark von der Sicherheit der RSA-Kryptographie ab, einem Public-Key-Kryptosystem. Die Sicherheit des RSA-Verfahrens basiert auf der mathematischen Annahme, dass es schwierig ist, riesige zusammengesetzte Zahlen in ihre Primfaktoren zu zerlegen. Wenn ein extrem effizienter Algorithmus zur Primfaktorzerlegung entdeckt würde, würde die Kommunikationsinfrastruktur der ganzen Welt von Grund auf zusammenbrechen.&lt;/p>
&lt;p>Derzeit ist das &lt;strong>Allgemeine Zahlkörpersieb (GNFS: General Number Field Sieve)&lt;/strong> der schnellste und stärkste Algorithmus zur Primfaktorzerlegung riesiger ganzen Zahlen auf klassischen Computern. Das GNFS entstand als Erweiterung des Speziellen Zahlkörpersiebs (SNFS), das Ende der 1980er Jahre vorgeschlagen wurde. Bis heute hat es Rekorde bei der Faktorisierung riesiger zusammengesetzter Zahlen wie RSA-768 und RSA-250 aufgestellt.&lt;/p>
&lt;p>Kryptographen und Mathematiker stellen sich jedoch stets folgende Fragen: &amp;ldquo;Gibt es einen klassischen Algorithmus, der das GNFS übertrifft?&amp;rdquo;, &amp;ldquo;Wo liegen die Grenzen klassischer Computer?&amp;rdquo; und &amp;ldquo;Wie werden Quantencomputer diese Situation überwinden?&amp;rdquo;.&lt;/p>
&lt;p>In diesem Artikel analysieren wir gründlich die tiefgründige mathematische Struktur hinter dem GNFS und führen detaillierte technische Analysen der Polynomauswahl, des Siebprozesses und des linearen Algebraschritts mithilfe der Block-Wiedemann-Methode durch. Darüber hinaus betrachten wir GNFS-Erweiterungsmethoden, wie die Coppersmith-Modifikation, und vergleichen sowie erklären wir die entscheidenden Unterschiede zwischen klassischen Algorithmen in subexponentieller Zeit (Sub-exponential time) und Quantenalgorithmen in polynomieller Zeit aus einer mathematischen Perspektive.&lt;/p>
&lt;hr>
&lt;h2 id="2-asymptotische-komplexität-und-l-notation-l-notation">2. Asymptotische Komplexität und L-Notation (L-notation)
&lt;/h2>&lt;p>Bei der Bewertung der Komplexität von Faktorisierungsalgorithmen wird anstelle der Standard-Polynomzeit-Notation (wie $O(n^k)$) die &lt;strong>L-Notation (L-notation)&lt;/strong> verwendet, um die subexponentielle Zeit relativ zur Anzahl der Stellen der Eingabe $n$ auszudrücken. Die L-Notation ist wie folgt definiert:&lt;/p>
$$
L_n[\alpha, c] = \exp \left( (c + o(1)) (\ln n)^\alpha (\ln \ln n)^{1-\alpha} \right)
$$
&lt;p>Hierbei ist $n$ die zu faktorisierende ganze Zahl und $\ln n$ der natürliche Logarithmus, der proportional zur Bitlänge von $n$ ist.&lt;/p>
&lt;ul>
&lt;li>Wenn $\alpha = 0$: $L_n[0, c] = \exp(c \ln \ln n) = (\ln n)^c$, was die &lt;strong>Polynomzeit (Polynomial time)&lt;/strong> bezogen auf die Bitlänge darstellt.&lt;/li>
&lt;li>Wenn $\alpha = 1$: $L_n[1, c] = \exp(c \ln n) = n^c$, was die &lt;strong>Exponentialzeit (Exponential time)&lt;/strong> bezogen auf die Bitlänge darstellt.&lt;/li>
&lt;li>Wenn $0 &lt; \alpha &lt; 1$: Es handelt sich um eine &lt;strong>subexponentielle Zeit (Sub-exponential time)&lt;/strong>, die zwischen der Polynomzeit und der Exponentialzeit liegt.&lt;/li>
&lt;/ul>
&lt;p>Die Geschichte der Entwicklung vergangener Faktorisierungsalgorithmen war auch eine Geschichte der allmählichen Verringerung dieses $\alpha$-Wertes.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Kettenbruchmethode (CFRAC) und Quadratisches Sieb mit mehreren Polynomen (MPQS)&lt;/strong>: Sie gehören zur Klasse $\alpha = 1/2$ und haben eine Komplexität von etwa $L_n[1/2, 1]$.&lt;/li>
&lt;li>&lt;strong>Allgemeines Zahlkörpersieb (GNFS)&lt;/strong>: Es erreicht $\alpha = 1/3$ und rühmt sich der Komplexität von $L_n[1/3, (64/9)^{1/3}]$, womit es der schnellste bekannte klassische Algorithmus ist.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="3-der-gesamte-gnfs-algorithmus-und-seine-mathematische-struktur">3. Der gesamte GNFS-Algorithmus und seine mathematische Struktur
&lt;/h2>&lt;p>Das GNFS besitzt eine äußerst komplexe und fortschrittliche mathematische Grundlage. Die grundlegende Idee ist eine Erweiterung des kleinen Fermatschen Satzes und des Quadratischen Siebs (QS): Durch das Finden eines nicht-trivialen Paares $(X, Y)$, das die Kongruenz $X^2 \equiv Y^2 \pmod n$ und $X \not\equiv \pm Y \pmod n$ erfüllt, leitet man den Faktor $\gcd(X-Y, n)$ von $n$ ab.&lt;/p>
&lt;p>Der Kern des GNFS liegt jedoch darin, dies nicht nur im Körper der rationalen Zahlen $\mathbb{Q}$ zu tun, sondern gleichzeitig &amp;ldquo;glatte Zahlen (Smooth numbers)&amp;rdquo; in einem Erweiterungskörper $\mathbb{Q}(\alpha)$, der als algebraischer Zahlkörper (Algebraic Number Field) bezeichnet wird, und im Körper der rationalen Zahlen zu suchen und durch einen Homomorphismus eine Kongruenzbeziehung herzustellen.&lt;/p>
&lt;p>Der GNFS-Prozess ist grob in fünf Phasen unterteilt.&lt;/p>
&lt;div class="mermaid">graph TD
A["Faktorisierungsproblem (Eingabe n)"] --> B["1. Polynomauswahl (Polynomial Selection)"]
B --> C["2. Siebphase (Sieving Phase)"]
C --> D["3. Filterphase (Filtering Phase)"]
D --> E["4. Lineare Algebra Phase (Linear Algebra Phase)"]
E --> F["5. Quadratwurzel Phase (Square Root Phase)"]
F --> G["Ausgabe der Primfaktoren p, q"]&lt;/div>
&lt;h3 id="31-phase-1-polynomauswahl-polynomial-selection">3.1 Phase 1: Polynomauswahl (Polynomial Selection)
&lt;/h3>&lt;p>Der Erfolg des GNFS hängt stark von der Auswahl geeigneter Polynome ab. Das Ziel ist es, zwei irreduzible Polynome, $f_1(x)$ (rationale Seite) und $f_2(x)$ (algebraische Seite), zu finden, die eine gemeinsame Wurzel $m$ haben. Das heißt, sie erfüllen:
$f_1(m) \equiv f_2(m) \equiv 0 \pmod n$&lt;/p>
&lt;p>Normalerweise wird für die rationale Seite ein lineares Polynom $f_1(x) = x - m$ gewählt, und für das Polynom der algebraischen Seite $f_2(x)$ wird ein normiertes Polynom vom Grad $d$ (typischerweise 5 oder 6) gewählt. Der klassischste Ansatz ist die &lt;strong>Base-$m$-Methode&lt;/strong>.
Man wählt eine ganze Zahl $m = \lfloor n^{1/(d+1)} \rfloor$, die nahe an der $1/(d+1)$-ten Potenz von $n$ liegt, und entwickelt $n$ im $m$-adischen System.
$n = c_d m^d + c_{d-1} m^{d-1} + \dots + c_1 m + c_0$
Dadurch erhält man das Polynom $f_2(x) = c_d x^d + c_{d-1} x^{d-1} + \dots + c_0$. Offensichtlich gilt $f_2(m) = n \equiv 0 \pmod n$.&lt;/p>
&lt;p>In modernen Implementierungen wird jedoch der &lt;strong>Kleinjung-Algorithmus&lt;/strong> verwendet. Dieser optimiert algebraische Eigenschaften (wie Murphys $E$-Wert und $\alpha$-Wert), während er verhindert, dass die Koeffizienten der Polynome extrem groß werden (Optimierung der Skewness), und sucht nach Polynomen, die bei der Siebverarbeitung leicht glatte Zahlen erzeugen. Allein in diesen Schritt werden enorme Rechenressourcen investiert.&lt;/p>
&lt;h3 id="32-phase-2-siebphase-sieving-phase">3.2 Phase 2: Siebphase (Sieving Phase)
&lt;/h3>&lt;p>Sobald die Polynome bestimmt sind, tritt der Algorithmus in die &amp;ldquo;Sieb&amp;rdquo;-Phase (Sieving) ein, die den höchsten Rechenaufwand aufweist. Hier suchen wir nach Paaren $(a, b)$. Dieses Paar ist teilerfremd, und es wird gefordert, dass die folgenden zwei Werte gleichzeitig &amp;ldquo;glatt&amp;rdquo; (Smooth) sind:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Norm auf der rationalen Seite&lt;/strong>: $F_1(a, b) = b \cdot f_1(a/b) = a - bm$&lt;/li>
&lt;li>&lt;strong>Norm auf der algebraischen Seite&lt;/strong>: $F_2(a, b) = b^d \cdot f_2(a/b)$&lt;/li>
&lt;/ol>
&lt;p>&amp;ldquo;Glatt&amp;rdquo; bedeutet, dass die Zahl nur in Primfaktoren zerlegbar ist, die unter einer angegebenen Schranke (Sieve bound) liegen. Man bereitet eine Primzahlenbasis (Factor base) für die rationale Seite und eine Primzahlenbasis für die algebraische Seite vor und findet glatte Zahlen effizient in einem riesigen Suchraum, ähnlich wie beim Sieb des Eratosthenes.
Heutzutage ist eine Methode namens &lt;strong>Gittersieb (Lattice Sieving)&lt;/strong> der Mainstream. Indem eine bestimmte Primzahl $q$ fixiert wird und nur $(a, b)$-Paare auf einem Teilgitter gesiebt werden, bei denen sowohl die rationale als auch die algebraische Seite ein Vielfaches von $q$ sind, wird eine extrem hohe Effizienz erreicht.&lt;/p>
&lt;h3 id="33-phase-3-filterphase-filtering-phase">3.3 Phase 3: Filterphase (Filtering Phase)
&lt;/h3>&lt;p>Die Anzahl der glatten Relationen (Gleichungen), die bei der Siebverarbeitung gefunden werden, geht in die Hunderte von Millionen oder Milliarden. Diese enthalten jedoch auch viele nutzlose Informationen.
Das Ziel der Filterung ist es, eine riesige dünnbesetzte Matrix (Sparse Matrix) zu konstruieren und gleichzeitig deren Dimension so gering wie möglich zu halten.&lt;/p>
&lt;p>Konkret werden die folgenden Operationen durchgeführt:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Singleton removal&lt;/strong>: Entfernen von Relationen, die einen Primfaktor enthalten, der nur einmal vorkommt.&lt;/li>
&lt;li>&lt;strong>Clique removal / Merging&lt;/strong>: Multiplizieren von Relationen, die Primfaktoren haben, die zweimal oder öfter vorkommen, um Variablen zu eliminieren und sie auf ein Gleichungssystem mit höherer Dichte, aber kleinerer Dimension zu reduzieren.&lt;/li>
&lt;/ul>
&lt;p>Dadurch wird eine Matrix mit Milliarden von Zeilen zu einer riesigen dünnbesetzten Matrix $\mathbf{A}$ (mit Elementen 0 und 1 über dem Körper $\mathbb{F}_2$) auf dem Niveau von zig Millionen Zeilen komprimiert.&lt;/p>
&lt;h3 id="34-phase-4-lineare-algebra-phase-linear-algebra-phase">3.4 Phase 4: Lineare Algebra Phase (Linear Algebra Phase)
&lt;/h3>&lt;p>Hier finden wir einen nicht-trivialen Lösungsvektor $\mathbf{x}$ der Gleichung $\mathbf{A} \mathbf{x} \equiv \mathbf{0} \pmod 2$. Das bedeutet, es handelt sich um das Problem, den linken Nullraum (Left Nullspace) einer riesigen dünnbesetzten Matrix zu finden.&lt;/p>
&lt;p>Da die Größe der Matrix extrem groß ist, ist sie mit der normalen Gaußschen Elimination ($O(N^3)$) unmöglich zu berechnen. Daher wird eine iterative Methode verwendet, die eine Art von Krylov-Unterraum-Verfahren ist. Historisch gesehen wurde die &lt;strong>Block-Lanczos-Methode (Block Lanczos)&lt;/strong> verwendet, aber in der heutigen verteilten Computerumgebung ist der &lt;strong>Block-Wiedemann-Algorithmus (Block Wiedemann Algorithm)&lt;/strong>, der den Kommunikations-Overhead drastisch reduzieren kann, der Mainstream.&lt;/p>
&lt;p>Die Block-Wiedemann-Methode berechnet das Minimalpolynom aus der Matrix $\mathbf{A}$ und Vektorfolgen und konstruiert die Basis des Nullraums mithilfe des Berlekamp-Massey-Algorithmus. Dieser Schritt ist sehr schwer zu parallelisieren und erfordert stark gekoppelte Kommunikationsnetzwerke von Supercomputern oder großen Clustern, was ihn zu einem der größten Engpässe des GNFS macht.&lt;/p>
&lt;h3 id="35-phase-5-quadratwurzel-phase-square-root-phase">3.5 Phase 5: Quadratwurzel Phase (Square Root Phase)
&lt;/h3>&lt;p>Aus der Lösung der linearen Algebra werden Produkte konstruiert, die auf der rationalen bzw. der algebraischen Seite zu &amp;ldquo;vollständigen Quadraten&amp;rdquo; werden.
Auf der rationalen Seite wird $\prod (a-bm)$ zum Quadrat $X^2$ einer ganzen Zahl $X$, und auf der algebraischen Seite wird das Produkt der entsprechenden Ideale zu einem vollständigen Quadrat $\gamma^2$ über dem algebraischen Zahlkörper.
Indem man dieses $\gamma$ über dem algebraischen Zahlkörper berechnet und den Homomorphismus zum Ring der rationalen ganzen Zahlen $\phi: \alpha \mapsto m \pmod n$ anwendet, erhält man die Kongruenz:
$X^2 \equiv \phi(\gamma)^2 \equiv Y^2 \pmod n$&lt;/p>
&lt;p>Für die Berechnung der Quadratwurzel über dem algebraischen Zahlkörper werden komplexe Algorithmen wie die &lt;strong>Montgomery-Methode (Montgomery&amp;rsquo;s Method)&lt;/strong> verwendet, was tiefe Kenntnisse der algebraischen Zahlentheorie erfordert. Schließlich wird $\gcd(X-Y, n)$ berechnet, und wenn ein nicht-trivialer Faktor erhalten wird, ist die Primfaktorzerlegung abgeschlossen.&lt;/p>
&lt;hr>
&lt;h2 id="4-gibt-es-einen-klassischen-algorithmus-der-das-gnfs-übertrifft">4. Gibt es einen klassischen Algorithmus, der das GNFS übertrifft?
&lt;/h2>&lt;p>Bisher wurde für die Primfaktorzerlegung allgemeiner ganzer Zahlen kein klassischer Algorithmus entdeckt, dessen asymptotische Komplexität unter $L_n[1/3, c]$ fällt. Es gibt jedoch einige Versuche und abgeleitete Algorithmen, um theoretische und praktische Grenzen zu durchbrechen.&lt;/p>
&lt;h3 id="41-vielfaches-zahlkörpersieb-mnfs-multiple-number-field-sieve">4.1 Vielfaches Zahlkörpersieb (MNFS: Multiple Number Field Sieve)
&lt;/h3>&lt;p>Als Ansatz zur Erweiterung des GNFS gibt es das &lt;strong>Vielfache Zahlkörpersieb (MNFS)&lt;/strong> von D. Coppersmith. Während das GNFS zwei Polynome (rationale und algebraische Seite) verwendet, verwendet das MNFS gleichzeitig mehrere verschiedene algebraische Polynome für ein einzelnes Polynom auf der rationalen Seite.&lt;/p>
$$ f_1(x), f_{2,1}(x), f_{2,2}(x), \dots, f_{2,V}(x) $$
&lt;p>Durch die Verwendung mehrerer algebraischer Körper kann die Wahrscheinlichkeit, dass die Zahl in jedem Siebschritt &amp;ldquo;in einem der algebraischen Körper glatt wird&amp;rdquo;, drastisch erhöht werden. Mit diesem Ansatz ist es Coppersmith gelungen, die Konstante $c$ in der Komplexität $L_n[1/3, c]$ leicht zu reduzieren.
Konkret wurde theoretisch gezeigt, dass, während die Konstante des GNFS $c = (64/9)^{1/3} \approx 1,923$ ist, die Optimierung des MNFS den Rechenaufwand auf etwa $c \approx 1,902$ reduzieren kann.
In der Praxis ist jedoch der Overhead durch die Verwaltung mehrerer Körper groß, und es hat nicht zu einem entscheidenden Durchbruch bei RSA-Modulen in praktischer Größe geführt.&lt;/p>
&lt;h3 id="42-sind-algorithmen-der-klasse-l_n14-möglich">4.2 Sind Algorithmen der Klasse $L_n[1/4]$ möglich?
&lt;/h3>&lt;p>Ein Thema, das unter Mathematikern seit vielen Jahren hinsichtlich der Grenzen klassischer Algorithmen zur Primfaktorzerlegung diskutiert wird, ist die Frage: &amp;ldquo;Gibt es einen Algorithmus mit dem Exponenten $\alpha = 1/4$?&amp;rdquo;.
Das derzeitige GNFS und seine Ableitungen sind stark an den Rahmen der &amp;ldquo;Suche nach Glätte&amp;rdquo; durch Sieben gebunden, und es wird weithin angenommen, dass $\alpha = 1/3$ die Grenze innerhalb dieses Paradigmas ist. Auch aus der Analyse der Verteilungswahrscheinlichkeit glatter ganzer Zahlen unter Verwendung der Dickman-Funktion (Dickman function) geht man davon aus, dass die Wand von $O(L_n[1/3])$ mit der aktuellen Kombination aus algebraischer Körperkonstruktion und Sieben durch keine Optimierung überwunden werden kann.&lt;/p>
&lt;p>Sollte es $L_n[1/4]$ oder gar einen klassischen Polynomzeitalgorithmus geben, müsste dieser auf einer völlig neuen mathematischen Struktur beruhen, die derzeit niemand vorhersehen kann und die sich vom &amp;ldquo;glattheitsbasierten&amp;rdquo; Ansatz wie dem GNFS völlig unterscheidet (zum Beispiel ein fortgeschrittenerer algebraisch-geometrischer Ansatz wie der Schoof-Algorithmus für elliptische Kurvenkryptographie). Derzeit gibt es jedoch keine derartigen Anzeichen.&lt;/p>
&lt;hr>
&lt;h2 id="5-durchbruch-durch-quantencomputer-shors-algorithmus">5. Durchbruch durch Quantencomputer: Shors Algorithmus
&lt;/h2>&lt;p>Während klassische Computer an der $L_n[1/3]$-Wand stehen, zerschmetterte der 1994 von Peter Shor vorgestellte &lt;strong>Shor-Algorithmus (Shor&amp;rsquo;s Algorithm)&lt;/strong> diese Wand, indem er das Berechnungsmodell grundlegend veränderte.&lt;/p>
&lt;h3 id="51-der-schock-der-quantenmechanischen-polynomzeit">5.1 Der Schock der quantenmechanischen Polynomzeit
&lt;/h3>&lt;p>Shors Algorithmus reduziert das Faktorisierungsproblem auf ein &amp;ldquo;Ordnungsfindungsproblem (Order Finding Problem)&amp;rdquo;. Es geht darum, die Periode (Ordnung) $r$ der Funktion $f(x) = a^x \pmod n$ für eine bestimmte ganze Zahl $a$ zu finden.
Während ein klassischer Computer exponentielle Zeit benötigt, um diese Periode zu finden, können durch die Verwendung der &lt;strong>Quanten-Phasenschätzung (QPE: Quantum Phase Estimation)&lt;/strong> und der &lt;strong>Quanten-Fourier-Transformation (QFT: Quantum Fourier Transform)&lt;/strong> auf einem Quantencomputer alle Zustände in Überlagerung (Superposition) parallel bewertet und die Periode $r$ mit hoher Wahrscheinlichkeit extrahiert werden.&lt;/p>
&lt;p>In Bezug auf die Komplexität ist die Ausführungszeit von Shors Algorithmus eine &lt;strong>quantenmechanische Polynomzeit&lt;/strong>, konkret:
&lt;/p>
$$ O((\log n)^3) $$
&lt;p>
Unter Berücksichtigung kürzlich optimierter Schaltungsimplementierungen kann dies auf $O((\log n)^2 \log \log n)$ reduziert werden.&lt;/p>
&lt;div class="mermaid">graph LR
A["Klassischer Algorithmus (GNFS)"] -->|Grenze| B["Subexponentielle Zeit L_n[1/3]"]
C["Quantenalgorithmus (Shor)"] -->|Durchbruch| D["Polynomzeit O((log n)^3)"]
B --> E["Fortgesetzte Nutzung von RSA (Längere Schlüssel)"]
D --> F["Vollständiger Zusammenbruch von RSA"]&lt;/div>
&lt;h3 id="52-klassische-subexponentielle-zeit-vs-quantenmechanische-polynomzeit">5.2 Klassische subexponentielle Zeit vs Quantenmechanische Polynomzeit
&lt;/h3>&lt;p>Der Unterschied zwischen diesen beiden Komplexitätsklassen hat entscheidende Auswirkungen auf die reale kryptographische Sicherheit.&lt;/p>
&lt;p>Betrachten wir beispielsweise den Fall der Faktorisierung von RSA-2048 (eine zusammengesetzte Zahl mit 2048 Bit).&lt;/p>
&lt;ul>
&lt;li>&lt;strong>GNFS (Klassisch)&lt;/strong>: Setzt man $n \approx 2^{2048}$ in $L_n[1/3, 1.923]$ ein, so benötigt man etwa $2^{112}$ Operationen. Dies ist eine astronomische Rechenmenge, die länger als die Lebensdauer des Universums dauern würde, selbst wenn man alle aktuellen Rechenressourcen der Erde bündeln würde.&lt;/li>
&lt;li>&lt;strong>Shor-Algorithmus (Quanten)&lt;/strong>: Bei einem $O((\log n)^3)$-Algorithmus sind nur etwa $2048^3 \approx 8,5 \times 10^9$ logische Gatteroperationen erforderlich. Dies bedeutet, dass die Berechnung in nur wenigen Stunden bis Tagen abgeschlossen sein könnte, sofern die entsprechende Hardware (ein universeller Quantencomputer mit Millionen von physischen Qubits und Fehlerkorrekturfähigkeiten) vorhanden ist.&lt;/li>
&lt;/ul>
&lt;p>Der Paradigmenwechsel von einer subexponentiellen Funktion mit einem &amp;ldquo;Exponenten $\alpha=1/3$&amp;rdquo; zur &amp;ldquo;Polynomzeit&amp;rdquo; macht die traditionelle kryptographische Strategie, die Sicherheit durch Erhöhung der Schlüssellänge zu gewährleisten, völlig wirkungslos.&lt;/p>
&lt;hr>
&lt;h2 id="6-zusammenfassung-ausblick-auf-die-nächste-generation">6. Zusammenfassung: Ausblick auf die nächste Generation
&lt;/h2>&lt;p>Der aktuelle Konsens der wissenschaftlichen Gemeinschaft zur Frage &amp;ldquo;Gibt es einen klassischen Algorithmus, der das GNFS übertrifft?&amp;rdquo; lautet wie folgt:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Praktische Verbesserungen werden fortgesetzt, aber es gibt keinen asymptotischen Sprung&lt;/strong>: Versuche, den konstanten Term $c$ des GNFS zu verbessern, wie MNFS, Optimierung der Polynomauswahl und Parallelisierung der Block-Wiedemann-Methode, werden fortgesetzt. Es gilt jedoch als äußerst unwahrscheinlich, dass ein klassischer Algorithmus entdeckt wird, der $\alpha = 1/3$ unterschreitet.&lt;/li>
&lt;li>&lt;strong>Die Sicherheit von RSA auf klassischen Computern bleibt stark&lt;/strong>: Der Rechenaufwand für das GNFS bleibt enorm, und RSA-2048 und RSA-4096 werden auf Jahrzehnte hinaus sicher gegen Angriffe klassischer Computer bleiben.&lt;/li>
&lt;li>&lt;strong>Die wahre Bedrohung ist der Quantenalgorithmus&lt;/strong>: Die Wand der Berechnungskomplexität wurde durch Shors Algorithmus überwunden, der auf den Prinzipien der Quantenmechanik beruht. Infolgedessen ist die Welt gezwungen, auf Post-Quanten-Kryptographie (PQC: Post-Quantum Cryptography) umzusteigen. Der Übergang zu neuen mathematischen Problemen wie gitterbasierter Kryptographie und Hash-basierter Kryptographie, die auch für Quantencomputer als schwer zu knacken (nicht in Polynomzeit lösbar) gelten, ist die aktuelle Spitze der Kryptographie.&lt;/li>
&lt;/ol>
&lt;p>Das Allgemeine Zahlkörpersieb (GNFS) ist einer der &amp;ldquo;höchsten Punkte&amp;rdquo;, den die Menschheit erreicht hat, indem sie die Grenzen der klassischen Mathematik und des Algorithmus-Designs herausgefordert hat. Das Verständnis der tiefgreifenden mathematischen Struktur des GNFS ist nicht nur das Erlernen der Geschichte der Kryptoanalyse, sondern auch eine intellektuelle Reise, um die Schönheit der Berechnungskomplexitätstheorie und der algebraischen Zahlentheorie zu erfahren. Bis zu dem Tag, an dem Quantencomputer in die Praxis umgesetzt werden, wird das GNFS seinen Thron als stärkster Algorithmus zur Primfaktorzerlegung behalten.&lt;/p></description></item><item><title>Schors Algorithmus mit Python simuliert</title><link>http://kenji.blog/de/p/shors-algorithm-simulation-python/</link><pubDate>Fri, 11 Sep 2026 08:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/shors-algorithm-simulation-python/</guid><description>&lt;img src="http://kenji.blog/p/shors-algorithm-simulation-python/img/eyecatch.jpg" alt="Featured image of post Schors Algorithmus mit Python simuliert" />&lt;h1 id="1-einführung-die-kryptographische-krise-durch-quantencomputer">1. Einführung: Die kryptographische Krise durch Quantencomputer
&lt;/h1>&lt;p>Ein Großteil der Sicherheit in der modernen Internetgesellschaft hängt von &lt;strong>Public-Key-Kryptographie&lt;/strong> (insbesondere RSA-Verschlüsselung) ab. Wenn wir beim Online-Shopping Kreditkarteninformationen senden oder hochsensible Daten austauschen, wird der Inhalt dieser Kommunikation stark durch RSA-Kryptographie geschützt.&lt;/p>
&lt;p>Die Sicherheit der RSA-Verschlüsselung beruht auf der mathematischen Tatsache, dass &amp;ldquo;&lt;strong>die Primfaktorzerlegung riesiger ganzer Zahlen für klassische Computer (die PCs und Supercomputer, die wir normalerweise verwenden) extrem schwierig ist&lt;/strong>&amp;rdquo;. Der 1994 von Peter Shor vorgestellte &amp;ldquo;&lt;strong>Shor-Algorithmus (Shor&amp;rsquo;s Algorithm)&lt;/strong>&amp;rdquo; stellte diese Prämisse jedoch grundlegend in Frage. Es wurde mathematisch bewiesen, dass der Shor-Algorithmus, wenn er auf einem großen Quantencomputer ausgeführt wird, die Primfaktorzerlegung, für die klassische Computer länger als das Alter des Universums benötigen würden, in nur wenigen Minuten bis Stunden lösen kann.&lt;/p>
&lt;p>In diesem Artikel werden wir ausführlich im Detail erklären, wie dieser Shor-Algorithmus eine schnelle Primfaktorzerlegung durchführt, von seinem mathematischen Mechanismus bis hin zu einer konkreten Simulationsimplementierung mit Python und dem Quanten-Computing-Framework &lt;strong>Qiskit&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h1 id="2-dramatische-änderung-der-komplexität-von-exponentieller-zu-polynomieller-zeit">2. Dramatische Änderung der Komplexität: Von exponentieller zu polynomieller Zeit
&lt;/h1>&lt;p>Warum ist die Primfaktorzerlegung so schwierig? Selbst mit dem &amp;ldquo;Zahlkörpersieb (General Number Field Sieve, GNFS)&amp;rdquo;, das als bester Primfaktorzerlegungsalgorithmus für klassische Computer bekannt ist, ist die zeitliche Komplexität subexponentiell.&lt;/p>
&lt;p>Die Zeitkomplexität zur Primfaktorzerlegung einer zusammengesetzten Zahl mit $N$ Ziffern bei Verwendung klassischer Methoden ist wie folgt:&lt;/p>
$$ O\left(\exp\left( c (\log N)^{1/3} (\log \log N)^{2/3} \right)\right) $$
&lt;p>Daher würde allein durch die Verlängerung der Schlüssellänge (z. B. auf 2048 Bit oder 4096 Bit) die Entschlüsselung auf einem klassischen Computer eine unrealistische Zeit wie Jahrtausende oder Zehntausende von Jahren in Anspruch nehmen.&lt;/p>
&lt;p>Wenn jedoch der &lt;strong>Shor-Algorithmus&lt;/strong> auf einem Quantencomputer verwendet wird, reduziert sich die zeitliche Komplexität dramatisch auf polynomielle Zeit in Bezug auf die Anzahl der Eingabebits $\log N$.&lt;/p>
$$ O((\log N)^3) $$
&lt;p>Dies bedeutet, dass sich bei einer Verdoppelung der Bitzahl die Rechenzeit für einen klassischen Computer astronomisch erhöht, während sie für einen Quantencomputer höchstens um das Achtfache steigt. Diese &lt;strong>Reduzierung der Komplexitätsklasse von exponentieller auf polynomielle Zeit (Aufnahme in die BQP-Klasse)&lt;/strong> ist die wahre Genialität von Shors Algorithmus.&lt;/p>
&lt;div class="mermaid">graph TD
A["Erhöhung der Eingabegröße (Anzahl der Bits) N"] --> B{"Wahl des Algorithmus"}
B -->|Klassisch: Zahlkörpersieb| C["Subexponentielle Erhöhung O(exp(...))"]
B -->|Quanten: Shors Algorithmus| D["Polynomielle Zeit O((log N)^3)"]
C --> E["Jahrtausende bis Milliarden von Jahren (unentschlüsselbar)"]
D --> F["Wenige Minuten bis Stunden (Entschlüsselung in realistischer Zeit)"]&lt;/div>
&lt;hr>
&lt;h1 id="3-gesamtbild-des-algorithmus-und-mathematischer-hintergrund">3. Gesamtbild des Algorithmus und mathematischer Hintergrund
&lt;/h1>&lt;p>Beim Shor-Algorithmus wird nicht alles auf einem Quantencomputer ausgeführt. Er basiert auf der Zusammenarbeit zwischen Vorverarbeitung/Nachbearbeitung durch klassische Computer und dem Kernteil (Periodenfindungsalgorithmus) durch Quantencomputer.&lt;/p>
&lt;p>Der Gesamtablauf des Algorithmus ist wie folgt:&lt;/p>
&lt;div class="mermaid">graph TD
A["Eingabe: Zusammengesetzte Zahl N, die faktorisiert werden soll"] --> B["Wähle Zufallszahl a, sodass a &lt; N"]
B --> C{"gcd(a, N) > 1 ?"}
C -- "Yes" --> D["Gibt den trivialen Faktor gcd(a, N) aus und beendet"]
C -- "No" --> E["Finde Periode r von f(x) = a^x mod N mit Quantenalgorithmus"]
E --> F{"Ist r gerade und a^(r/2) ≢ -1 mod N ?"}
F -- "No" --> B
F -- "Yes" --> G["Berechne Faktoren p = gcd(a^(r/2) - 1, N), q = gcd(a^(r/2) + 1, N)"]
G --> H["Ausgabe: p, q"]&lt;/div>
&lt;h2 id="reduktion-der-primfaktorzerlegung-auf-das-periodenfindungsproblem">Reduktion der Primfaktorzerlegung auf das Periodenfindungsproblem
&lt;/h2>&lt;p>Shors geniale Idee bestand darin, das &amp;ldquo;&lt;strong>Primfaktorzerlegungsproblem&lt;/strong>&amp;rdquo; in das &amp;ldquo;&lt;strong>Periodenfindungsproblem (Order Finding Problem)&lt;/strong>&amp;rdquo; umzuwandeln.&lt;/p>
&lt;p>Betrachten wir die ganze Zahl $N$ (die zu faktorisierende Zahl) und eine teilerfremde ganze Zahl $a$ ($1 &lt; a &lt; N$). Wir definieren die folgende modulare Exponentialfunktion:&lt;/p>
$$ f(x) = a^x \bmod N $$
&lt;p>Diese Funktion hat eine bestimmte Periode $r$. Das heißt, für jedes $x$ gilt $f(x+r) = f(x)$. Insbesondere wenn $x=0$, nennt man die kleinste positive ganze Zahl $r$, die&lt;/p>
$$ a^r \equiv 1 \pmod N $$
&lt;p>erfüllt, die &amp;ldquo;Ordnung von $a$ modulo $N$ (Order)&amp;rdquo;. Wenn wir diese Periode $r$ finden können, können wir die Primfaktoren wie folgt ableiten.&lt;/p>
&lt;p>Wenn wir die Formel umstellen, erhalten wir:
&lt;/p>
$$ a^r - 1 \equiv 0 \pmod N $$
&lt;p>
Wenn $r$ gerade ist, kann dies mit der binomischen Formel (Differenz von Quadraten) faktorisiert werden.
&lt;/p>
$$ (a^{r/2} - 1)(a^{r/2} + 1) \equiv 0 \pmod N $$
&lt;p>Dies bedeutet, dass $N$ einen gemeinsamen Teiler mit entweder $(a^{r/2} - 1)$ oder $(a^{r/2} + 1)$ hat (unter der Bedingung, dass $a^{r/2} \not\equiv -1 \pmod N$). Durch Anwendung des euklidischen Algorithmus zur Berechnung von&lt;/p>
$$ p = \gcd(a^{r/2} - 1, N) $$
$$ q = \gcd(a^{r/2} + 1, N) $$
&lt;p>können wir die nichttrivialen Primfaktoren $p, q$ von $N$ finden. Diese Berechnungen (Berechnung des größten gemeinsamen Teilers und Generierung von Zufallszahlen) können von klassischen Computern sehr schnell durchgeführt werden. Das Problem beschränkt sich also auf die Frage, &lt;strong>wie man die Periode $r$ schnell finden kann&lt;/strong>. Auf klassischen Computern erfordert das Finden dieser Periode $r$ selbst exponentielle Zeit. Hier kommt der Quantencomputer ins Spiel.&lt;/p>
&lt;hr>
&lt;h1 id="4-quantenalgorithmus-teil-wie-die-periodenfindung-funktioniert">4. Quantenalgorithmus-Teil: Wie die Periodenfindung funktioniert
&lt;/h1>&lt;p>Die Subroutine zum Finden der Periode $r$ mithilfe eines Quantencomputers besteht aus den folgenden 4 Schritten:&lt;/p>
&lt;div class="mermaid">graph LR
subgraph "Übergänge der Quantenzustände"
S1["|0⟩|0⟩ (Initialisierung)"] --> S2["H-Gate: Superposition Σ|x⟩|0⟩"]
S2 --> S3["Orakel U: Σ|x⟩|a^x mod N⟩"]
S3 --> S4["QFT: Periodenextraktion durch Interferenz"]
S4 --> S5["Messung: Erhalt des Näherungswertes y"]
end&lt;/div>
&lt;h2 id="schritt-1-initialisierung-und-superposition-der-quantenregister">Schritt 1: Initialisierung und Superposition der Quantenregister
&lt;/h2>&lt;p>Zunächst bereiten wir zwei Quantenregister vor. Das erste Register dient zur Eingabe des Zustands und das zweite zur Speicherung der Ergebnisse der Funktionsberechnung.
Der Anfangszustand ist überall $|0\rangle$.&lt;/p>
$$ |\psi_0\rangle = |0\rangle_1 |0\rangle_2 $$
&lt;p>Wir wenden ein Hadamard-Gatter (Hadamard Gate) auf alle Qubits im ersten Register an, um einen Zustand gleicher Wahrscheinlichkeits-Superposition für alle möglichen Eingaben $x$ (von $0$ bis $Q-1$, mit $Q=2^n$) zu erzeugen.&lt;/p>
$$ |\psi_1\rangle = \frac{1}{\sqrt{Q}} \sum_{x=0}^{Q-1} |x\rangle_1 |0\rangle_2 $$
&lt;p>Dadurch kann der Quantencomputer mit einer einzigen Operation Zustände für alle $Q$ Eingaben gleichzeitig speichern. Dies ist die mächtige Quelle der &lt;strong>Quantenparallelität&lt;/strong>.&lt;/p>
&lt;h2 id="schritt-2-anwendung-der-orakelfunktion-modulare-exponentiation">Schritt 2: Anwendung der Orakelfunktion (Modulare Exponentiation)
&lt;/h2>&lt;p>Als Nächstes verwenden wir die Quantenschaltung $U_f$, um die Funktion $f(x) = a^x \bmod N$ zu berechnen und das Ergebnis im zweiten Register zu speichern.&lt;/p>
$$ |\psi_2\rangle = \frac{1}{\sqrt{Q}} \sum_{x=0}^{Q-1} |x\rangle_1 |a^x \bmod N\rangle_2 $$
&lt;p>Zu diesem Zeitpunkt befinden sich das erste und zweite Register in einem Zustand der &lt;strong>Quantenverschränkung (Entanglement)&lt;/strong>. Wenn wir (hypothetisch) das zweite Register beobachten und einen bestimmten Wert $k = a^{x_0} \bmod N$ erhalten, kollabiert der Zustand des ersten Registers in eine Superposition derjenigen $x$, die diesen Wert $k$ ergeben. Da die Funktion die Periode $r$ hat, sind die verbleibenden Zustände im Abstand $r$, wie $x_0, x_0+r, x_0+2r, \dots$.&lt;/p>
$$ |\psi_3\rangle = \sqrt{\frac{r}{Q}} \sum_{j=0}^{M-1} |x_0 + j r\rangle_1 |k\rangle_2 $$
&lt;p>Wir wollen jedoch nicht $x_0$ wissen, sondern die Periode $r$ selbst. Es ist unmöglich, $r$ direkt aus diesem Zustand zu beobachten. Daher verwenden wir die Quanten-Fouriertransformation.&lt;/p>
&lt;h2 id="schritt-3-phaseninterferenz-durch-quanten-fouriertransformation-qft">Schritt 3: Phaseninterferenz durch Quanten-Fouriertransformation (QFT)
&lt;/h2>&lt;p>Wir wenden die &lt;strong>Quanten-Fouriertransformation (Quantum Fourier Transform, QFT)&lt;/strong> auf das erste Register an. Die QFT ist die Quantenversion der klassischen diskreten Fouriertransformation und transformiert die Amplituden von Zustandsvektoren. Die Wirkung der QFT auf den Basiszustand $|x\rangle$ ist wie folgt definiert:&lt;/p>
$$ QFT |x\rangle = \frac{1}{\sqrt{Q}} \sum_{y=0}^{Q-1} \omega^{xy} |y\rangle $$
&lt;p>Wobei $\omega = e^{2\pi i / Q}$.&lt;/p>
&lt;p>Wenn die QFT angewendet wird, interferieren die Amplituden der Zustände. Ohne auf mathematische Details einzugehen: Wenn QFT auf einen Zustand mit Periode $r$ angewendet wird, verursachen die Wellen nur dann eine &lt;strong>konstruktive Interferenz (Constructive Interference)&lt;/strong>, wenn $y$ extrem nahe an einem ganzzahligen Vielfachen von $Q/r$ liegt. Für andere Zustände heben sich die Wahrscheinlichkeitsamplituden aufgrund von &lt;strong>destruktiver Interferenz (Destructive Interference)&lt;/strong> gegenseitig auf und nähern sich Null.&lt;/p>
&lt;h2 id="schritt-4-messung-und-kettenbruchentwicklung">Schritt 4: Messung und Kettenbruchentwicklung
&lt;/h2>&lt;p>Schließlich messen wir das erste Register. Der durch die Messung erhaltene Wert $y$ erfüllt mit hoher Wahrscheinlichkeit folgende Bedingung:&lt;/p>
$$ y \approx c \frac{Q}{r} \implies \frac{y}{Q} \approx \frac{c}{r} $$
&lt;p>($c$ ist eine unbekannte ganze Zahl mit $0 \le c &lt; r$)&lt;/p>
&lt;p>Durch Anwendung der &lt;strong>Kettenbruchentwicklung (Continued Fraction Expansion)&lt;/strong>, einem klassischen Algorithmus, auf die erhaltene rationale Zahl $y/Q$ berechnen wir den Näherungsbruch $c/r$ und extrahieren die Periode $r$ aus dem Nenner.&lt;/p>
&lt;hr>
&lt;h1 id="5-simulationsimplementierung-mit-python-und-qiskit">5. Simulationsimplementierung mit Python und Qiskit
&lt;/h1>&lt;p>Da Theorie allein schwer greifbar ist, simulieren wir Shors Algorithmus tatsächlich mit Python und &lt;strong>Qiskit&lt;/strong>, dem Quanten-Computing-Framework von IBM.&lt;/p>
&lt;p>Hier implementieren wir das klassischste und bekannteste Beispiel-Szenario: &amp;ldquo;&lt;strong>Faktorisierung von $N=15$ unter Verwendung von $a=7$&lt;/strong>&amp;rdquo;.&lt;/p>
&lt;h2 id="vorbereitung-der-ausführungsumgebung">Vorbereitung der Ausführungsumgebung
&lt;/h2>&lt;p>Bitte installieren Sie Qiskit im Voraus.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">pip install qiskit qiskit-aer numpy
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="übersicht-über-den-python-implementierungscode">Übersicht über den Python-Implementierungscode
&lt;/h2>&lt;p>Der folgende Code ist ein Implementierungsbeispiel von Shors Algorithmus, der auf $N=15, a=7$ spezialisiert ist. Da der Aufbau einer universellen modularen Exponentiationsschaltung auf aktuellen Simulatoren zu rechenintensiv ist, sind die Gatteroperationen für den spezifischen Fall von $a=7$ hartcodiert.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt"> 10
&lt;/span>&lt;span class="lnt"> 11
&lt;/span>&lt;span class="lnt"> 12
&lt;/span>&lt;span class="lnt"> 13
&lt;/span>&lt;span class="lnt"> 14
&lt;/span>&lt;span class="lnt"> 15
&lt;/span>&lt;span class="lnt"> 16
&lt;/span>&lt;span class="lnt"> 17
&lt;/span>&lt;span class="lnt"> 18
&lt;/span>&lt;span class="lnt"> 19
&lt;/span>&lt;span class="lnt"> 20
&lt;/span>&lt;span class="lnt"> 21
&lt;/span>&lt;span class="lnt"> 22
&lt;/span>&lt;span class="lnt"> 23
&lt;/span>&lt;span class="lnt"> 24
&lt;/span>&lt;span class="lnt"> 25
&lt;/span>&lt;span class="lnt"> 26
&lt;/span>&lt;span class="lnt"> 27
&lt;/span>&lt;span class="lnt"> 28
&lt;/span>&lt;span class="lnt"> 29
&lt;/span>&lt;span class="lnt"> 30
&lt;/span>&lt;span class="lnt"> 31
&lt;/span>&lt;span class="lnt"> 32
&lt;/span>&lt;span class="lnt"> 33
&lt;/span>&lt;span class="lnt"> 34
&lt;/span>&lt;span class="lnt"> 35
&lt;/span>&lt;span class="lnt"> 36
&lt;/span>&lt;span class="lnt"> 37
&lt;/span>&lt;span class="lnt"> 38
&lt;/span>&lt;span class="lnt"> 39
&lt;/span>&lt;span class="lnt"> 40
&lt;/span>&lt;span class="lnt"> 41
&lt;/span>&lt;span class="lnt"> 42
&lt;/span>&lt;span class="lnt"> 43
&lt;/span>&lt;span class="lnt"> 44
&lt;/span>&lt;span class="lnt"> 45
&lt;/span>&lt;span class="lnt"> 46
&lt;/span>&lt;span class="lnt"> 47
&lt;/span>&lt;span class="lnt"> 48
&lt;/span>&lt;span class="lnt"> 49
&lt;/span>&lt;span class="lnt"> 50
&lt;/span>&lt;span class="lnt"> 51
&lt;/span>&lt;span class="lnt"> 52
&lt;/span>&lt;span class="lnt"> 53
&lt;/span>&lt;span class="lnt"> 54
&lt;/span>&lt;span class="lnt"> 55
&lt;/span>&lt;span class="lnt"> 56
&lt;/span>&lt;span class="lnt"> 57
&lt;/span>&lt;span class="lnt"> 58
&lt;/span>&lt;span class="lnt"> 59
&lt;/span>&lt;span class="lnt"> 60
&lt;/span>&lt;span class="lnt"> 61
&lt;/span>&lt;span class="lnt"> 62
&lt;/span>&lt;span class="lnt"> 63
&lt;/span>&lt;span class="lnt"> 64
&lt;/span>&lt;span class="lnt"> 65
&lt;/span>&lt;span class="lnt"> 66
&lt;/span>&lt;span class="lnt"> 67
&lt;/span>&lt;span class="lnt"> 68
&lt;/span>&lt;span class="lnt"> 69
&lt;/span>&lt;span class="lnt"> 70
&lt;/span>&lt;span class="lnt"> 71
&lt;/span>&lt;span class="lnt"> 72
&lt;/span>&lt;span class="lnt"> 73
&lt;/span>&lt;span class="lnt"> 74
&lt;/span>&lt;span class="lnt"> 75
&lt;/span>&lt;span class="lnt"> 76
&lt;/span>&lt;span class="lnt"> 77
&lt;/span>&lt;span class="lnt"> 78
&lt;/span>&lt;span class="lnt"> 79
&lt;/span>&lt;span class="lnt"> 80
&lt;/span>&lt;span class="lnt"> 81
&lt;/span>&lt;span class="lnt"> 82
&lt;/span>&lt;span class="lnt"> 83
&lt;/span>&lt;span class="lnt"> 84
&lt;/span>&lt;span class="lnt"> 85
&lt;/span>&lt;span class="lnt"> 86
&lt;/span>&lt;span class="lnt"> 87
&lt;/span>&lt;span class="lnt"> 88
&lt;/span>&lt;span class="lnt"> 89
&lt;/span>&lt;span class="lnt"> 90
&lt;/span>&lt;span class="lnt"> 91
&lt;/span>&lt;span class="lnt"> 92
&lt;/span>&lt;span class="lnt"> 93
&lt;/span>&lt;span class="lnt"> 94
&lt;/span>&lt;span class="lnt"> 95
&lt;/span>&lt;span class="lnt"> 96
&lt;/span>&lt;span class="lnt"> 97
&lt;/span>&lt;span class="lnt"> 98
&lt;/span>&lt;span class="lnt"> 99
&lt;/span>&lt;span class="lnt">100
&lt;/span>&lt;span class="lnt">101
&lt;/span>&lt;span class="lnt">102
&lt;/span>&lt;span class="lnt">103
&lt;/span>&lt;span class="lnt">104
&lt;/span>&lt;span class="lnt">105
&lt;/span>&lt;span class="lnt">106
&lt;/span>&lt;span class="lnt">107
&lt;/span>&lt;span class="lnt">108
&lt;/span>&lt;span class="lnt">109
&lt;/span>&lt;span class="lnt">110
&lt;/span>&lt;span class="lnt">111
&lt;/span>&lt;span class="lnt">112
&lt;/span>&lt;span class="lnt">113
&lt;/span>&lt;span class="lnt">114
&lt;/span>&lt;span class="lnt">115
&lt;/span>&lt;span class="lnt">116
&lt;/span>&lt;span class="lnt">117
&lt;/span>&lt;span class="lnt">118
&lt;/span>&lt;span class="lnt">119
&lt;/span>&lt;span class="lnt">120
&lt;/span>&lt;span class="lnt">121
&lt;/span>&lt;span class="lnt">122
&lt;/span>&lt;span class="lnt">123
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">numpy&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">np&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">qiskit&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">QuantumCircuit&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">qiskit_aer&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">AerSimulator&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">qiskit.visualization&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">plot_histogram&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">fractions&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Fraction&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">math&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. Funktion zum Aufbau der inversen Quanten-Fouriertransformation (QFT†)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">qft_dagger&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Generiert eine inverse Quanten-Fouriertransformationsschaltung für n Qubits&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">QuantumCircuit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># SWAP-Gatter zur Umkehrung der Reihenfolge&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">qubit&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="o">//&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">qubit&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">qubit&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Anwendung von kontrollierten Phasengattern und H-Gattern&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">j&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">m&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">cp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pi&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="nb">float&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">)),&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">j&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">h&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;QFT_dagger&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">qc&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. Funktion zum Aufbau der kontrollierten modularen Exponentiation für 7^x mod 15&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">c_amod15&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">power&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Generiert ein kontrolliertes U-Gatter für ein spezifisches a und eine Potenz (nur für N=15)&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">QuantumCircuit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">power&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Hartcodierte Logik für 7^x mod 15, wenn a=7&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">13&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">7&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">11&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">7&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">11&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">13&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">q&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">q&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_gate&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">^&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">power&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> mod 15&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">c_U&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">U&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">control&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">c_U&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. Aufbau der Haupt-Quantenschaltung&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">shor_circuit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n_count&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># n_count: Anzahl der Bits im Kontrollregister&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Das Zielregister hat 4 Bits, um 0 bis 15 darzustellen&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">QuantumCircuit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n_count&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n_count&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Initialisierung des 1. Registers (Kontrollregister) (Erzeugung der Superposition)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">q&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n_count&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">h&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">q&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Initialisierung des 2. Registers (Zielregister) auf |1&amp;gt; (0001)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">n_count&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Anwendung der kontrollierten modularen Exponentiation (Orakel)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">q&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n_count&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Anwendung der 2^q-ten Potenz-Operation&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">c_amod15&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="n">q&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="n">q&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="n">n_count&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">)])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Anwendung der inversen Quanten-Fouriertransformation auf das 1. Register&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">qft_dagger&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n_count&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n_count&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Messung des 1. Registers&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">measure&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n_count&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n_count&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">qc&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># --- Ausführungsbereich ---&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">N&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">15&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">7&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">n_count&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">8&lt;/span> &lt;span class="c1"># Verwendung von 8 Qubits für das Kontrollregister (Q=256)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Sucheinstellungen: N=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">N&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">, a=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">, Anzahl Kontroll-Qubits=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">n_count&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Generierung der Schaltung&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">shor_circuit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n_count&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Ausführung im Simulator&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sim&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AerSimulator&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># In der neuesten Version von Qiskit wird transpile empfohlen&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kn">from&lt;/span> &lt;span class="nn">qiskit&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">transpile&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">compiled_circuit&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">transpile&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">qc&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">sim&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">job&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sim&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">compiled_circuit&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">shots&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1024&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">job&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">counts&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_counts&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">Messergebnis (Bitfolge: Anzahl der Beobachtungen):&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">bitstring&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">count&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">counts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34; &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">bitstring&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">count&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> Mal&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"># Klassische Nachbearbeitung: Identifizierung der Periode r durch Kettenbruchentwicklung&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">--- Berechnung der Periode und Primfaktorzerlegung ---&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">phases&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">output&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">counts&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Umwandlung der Bitfolge in eine Dezimalzahl&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">decimal&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">output&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Phase = Messwert / 2^n_count&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">phase&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">decimal&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="n">n_count&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">phases&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">phase&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Erhalt des Näherungsbruchs durch Kettenbruchentwicklung. Die Obergrenze des Nenners ist N=15&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">frac&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Fraction&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">phase&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">limit_denominator&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">15&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">r&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">frac&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">denominator&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Beobachteter Wert: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">decimal&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">3d&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> | Phase: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">phase&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.4f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> | Kettenbruch: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">frac&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> | Geschätzte Periode r = &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">r&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Überprüfen, ob Periode r gerade ist und ein gültiges Ergebnis liefert&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">guess1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">math&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">r&lt;/span>&lt;span class="o">//&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">guess2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">math&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">r&lt;/span>&lt;span class="o">//&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">guess1&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="ow">or&lt;/span> &lt;span class="n">guess2&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34; =&amp;gt; Erfolgreich! Die Primfaktoren von &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"> sind &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">guess1&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> und &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">guess2&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34; =&amp;gt; Nur triviale Faktoren. Noch einmal versuchen.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34; =&amp;gt; Fehlgeschlagen, da die Periode ungerade ist.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="code-erklärung-und-analyse-der-ausführungsergebnisse">Code-Erklärung und Analyse der Ausführungsergebnisse
&lt;/h2>&lt;p>Wenn Sie den obigen Code ausführen, erhalten Sie mit hoher Wahrscheinlichkeit bestimmte Peaks (Beobachtungswerte) als Messergebnis des Kontrollregisters. Für &lt;code>n_count=8&lt;/code> ($Q=256$) treten bei einem idealen Quantencomputer (oder Simulator) Werte wie &lt;code>0&lt;/code>, &lt;code>64&lt;/code>, &lt;code>128&lt;/code>, &lt;code>192&lt;/code> mit überwältigender Wahrscheinlichkeit auf.&lt;/p>
&lt;p>Teilt man diese durch $Q=256$, erhält man die Phasen $y/Q$ als $0.0$, $0.25$, $0.5$, bzw. $0.75$.
Wendet man auf diese Phasen die Kettenbruchentwicklung an:&lt;/p>
&lt;ul>
&lt;li>$0.25 \to 1/4$ (Geschätzte Periode $r=4$)&lt;/li>
&lt;li>$0.50 \to 1/2$ (Geschätzte Periode $r=2$)&lt;/li>
&lt;li>$0.75 \to 3/4$ (Geschätzte Periode $r=4$)&lt;/li>
&lt;/ul>
&lt;p>Mit der hier erhaltenen Periode $r=4$ berechnen wir die Primfaktoren.
Da $a=7, r=4$, gilt:
$p = \gcd(7^2 - 1, 15) = \gcd(48, 15) = 3$
$q = \gcd(7^2 + 1, 15) = \gcd(50, 15) = 5$&lt;/p>
&lt;p>Wir haben erfolgreich die Primfaktorzerlegung $15 = 3 \times 5$ durchgeführt.&lt;/p>
&lt;blockquote>
&lt;p>[!TIP]
Wenn der Messwert $y=128$ (Phase $0.5$) erhalten wird, ist der Nenner $2$, und wir erhalten einen Teiler anstelle der wahren Periode $r=4$. In solchen Fällen können wir die wahre Periode finden, indem wir den Algorithmus mehrmals ausführen oder Vielfache der erhaltenen $r$ untersuchen.&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h1 id="6-herausforderungen-für-die-praktische-anwendung-und-die-grenzen-der-nisq-ära">6. Herausforderungen für die praktische Anwendung und die Grenzen der NISQ-Ära
&lt;/h1>&lt;p>Obwohl es einfach war, $N=15$ auf einem Simulator zu faktorisieren, gibt es für reale Quantencomputer noch viele Hürden, um RSA-2048 (eine 617-stellige Dezimalzahl), wie es in der realen Welt verwendet wird, zu faktorisieren.&lt;/p>
&lt;p>Die Ära, in der wir derzeit leben, wird als &lt;strong>NISQ-Ära (Noisy Intermediate-Scale Quantum: verrauschtes, mittelgroßes Quanten-Computing)&lt;/strong> bezeichnet. Qubits sind extrem anfällig für Umgebungsrauschen und unterliegen während der Berechnungen der &amp;ldquo;Dekohärenz&amp;rdquo;, wodurch ihre Zustände zerstört werden.&lt;/p>
&lt;p>Um tiefe Schaltungen (mit vielen Gattern) wie Shors Algorithmus fehlerfrei auszuführen, ist eine &lt;strong>Quantenfehlerkorrektur (Quantum Error Correction)&lt;/strong> unerlässlich, um das Rauschen zu korrigieren. Um ein rauschfreies &amp;ldquo;logisches Qubit&amp;rdquo; zu erzeugen, müssen Tausende von &amp;ldquo;physischen Qubits&amp;rdquo; mit Verfahren wie dem Surface Code codiert werden.&lt;/p>
&lt;p>Um eine 2048-Bit-RSA-Verschlüsselung zu knacken, werden Tausende von perfekten logischen Qubits benötigt. Schätzungen zufolge ist dafür ein fehlertoleranter Quantencomputer mit &lt;strong>Millionen bis zig Millionen physischen Qubits&lt;/strong> erforderlich. Da selbst die modernsten heutigen Quantenprozessoren nur über einige Hundert bis Tausend physische Qubits verfügen, werden die Verschlüsselungen der Welt nicht unmittelbar morgen geknackt.&lt;/p>
&lt;blockquote>
&lt;p>[!WARNING]
Es gibt jedoch ein Bedrohungsmodell namens &amp;ldquo;Store Now, Decrypt Later (Jetzt speichern, später entschlüsseln)&amp;rdquo;. Angreifer könnten große Mengen der aktuell verschlüsselten vertraulichen Kommunikation in verschlüsselter Form speichern und die Strategie verfolgen, alles zu entschlüsseln, sobald in 10 bis 20 Jahren ein leistungsstarker Quantencomputer gebaut ist.&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h1 id="7-übergang-zur-post-quanten-kryptographie-pqc">7. Übergang zur Post-Quanten-Kryptographie (PQC)
&lt;/h1>&lt;p>In Vorbereitung auf die Ankunft eines solchen &amp;ldquo;Q-Day (der Tag, an dem Quantencomputer Verschlüsselungen knacken)&amp;rdquo; standardisieren Kryptographen weltweit, allen voran das amerikanische National Institute of Standards and Technology (NIST), die &lt;strong>Post-Quanten-Kryptographie (Post-Quantum Cryptography, PQC)&lt;/strong>.&lt;/p>
&lt;p>PQC basiert auf neuen mathematischen Problemen (Gitterprobleme, multivariate Polynome, hashbasiert usw.), von denen mathematisch angenommen wird, dass sie selbst mit Shors Algorithmus (oder Grovers Algorithmus) nicht effizient lösbar sind. Algorithmen wie &amp;ldquo;CRYSTALS-Kyber&amp;rdquo; und &amp;ldquo;CRYSTALS-Dilithium&amp;rdquo; wurden bereits als Standard ausgewählt und schrittweise in Apples iMessage und verschiedene Webbrowser-Kommunikationsprotokolle eingeführt.&lt;/p>
&lt;p>Für Ingenieure, die IT-Infrastrukturen verwalten, wird der Einbau von &amp;ldquo;Crypto-Agility (Krypto-Agilität: das Design zum schnellen Wechseln von Verschlüsselungsmethoden)&amp;rdquo; von bestehenden RSA- oder elliptischen Kurven zu PQC eine wichtige zukünftige Aufgabe sein.&lt;/p>
&lt;hr>
&lt;h1 id="8-fazit">8. Fazit
&lt;/h1>&lt;p>In diesem Artikel haben wir eine umfassende Erklärung im Umfang von etwa 10.000 Zeichen geliefert, beginnend mit dem theoretischen mathematischen Hintergrund des Shor-Algorithmus, über den Mechanismus der Periodenextraktion mittels der Quanten-Fouriertransformation, bis hin zu spezifischem Simulationscode mit Python und Qiskit.&lt;/p>
&lt;p>Die Tatsache, dass die physikalischen Gesetze der mikroskopischen Welt der Quantenmechanik die Grundlagen der Komplexitätstheorie und der Kryptographietheorie, die die Grundlagen der makroskopischen Informationswissenschaft bilden, komplett umstürzen können, ist einer der aufregendsten Paradigmenwechsel in der Geschichte der Wissenschaft. Es bleibt spannend, die anhaltende technologische Entwicklung der Quantencomputer und die Abwehrschlacht durch neue Verschlüsselungstechnologien weiter zu beobachten.&lt;/p>
&lt;p>Wir ermutigen Sie, den hier vorgestellten Python-Code in Ihrer eigenen Umgebung auszuführen und die &amp;ldquo;Magie der Berechnung&amp;rdquo; zu erleben, die durch die Superposition und Interferenz von Quantenzuständen entsteht.&lt;/p>
&lt;hr>
&lt;p>&lt;strong>Referenzen&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Shor, P. W. (1994). &amp;ldquo;Algorithms for quantum computation: discrete logarithms and factoring&amp;rdquo;. Proceedings 35th Annual Symposium on Foundations of Computer Science.&lt;/li>
&lt;li>Nielsen, M. A., &amp;amp; Chuang, I. L. (2010). &amp;ldquo;Quantum Computation and Quantum Information&amp;rdquo;. Cambridge University Press.&lt;/li>
&lt;li>Qiskit Documentation: &lt;a class="link" href="https://qiskit.org/documentation/" target="_blank" rel="noopener"
>https://qiskit.org/documentation/&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>【Grafik PQC】Vergleich der wichtigsten Algorithmen für die Post-Quanten-Kryptographie</title><link>http://kenji.blog/de/p/post-quantum-cryptography-algorithms-comparison/</link><pubDate>Fri, 11 Sep 2026 07:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/post-quantum-cryptography-algorithms-comparison/</guid><description>&lt;img src="http://kenji.blog/p/post-quantum-cryptography-algorithms-comparison/img/eyecatch.jpg" alt="Featured image of post 【Grafik PQC】Vergleich der wichtigsten Algorithmen für die Post-Quanten-Kryptographie" />&lt;h2 id="1-einleitung-die-krise-der-kryptographie-durch-quantencomputer">1. Einleitung: Die &amp;ldquo;Krise der Kryptographie&amp;rdquo; durch Quantencomputer
&lt;/h2>&lt;p>In der modernen Internetgesellschaft ist die Public-Key-Kryptographie eine unverzichtbare Infrastruktur zum Schutz der Vertraulichkeit von Kommunikation und der Datenintegrität. Die derzeit weit verbreiteten RSA- und Elliptische-Kurven-Kryptographie (ECC) stützen sich für ihre Sicherheit auf mathematische Hürden, nämlich die &amp;ldquo;Schwierigkeit der Primfaktorzerlegung riesiger zusammengesetzter Zahlen&amp;rdquo; und die &amp;ldquo;Schwierigkeit des diskreten Logarithmusproblems auf elliptischen Kurven&amp;rdquo;. Es wurde bewiesen, dass klassische Computer (die Computer, die wir heute benutzen, einschließlich Supercomputern) länger als das Alter des Universums bräuchten, um diese mathematischen Probleme zu lösen, was die Grundlage für ihre Sicherheit darstellte.&lt;/p>
&lt;p>Diese robuste Annahme wird jedoch durch Fortschritte in der Theorie und praktischen Anwendung von &lt;strong>Quantencomputern&lt;/strong> grundlegend auf den Kopf gestellt. Der &amp;ldquo;&lt;strong>Shor-Algorithmus&lt;/strong>&amp;rdquo;, der 1994 von dem Kryptographen Peter Shor vorgestellt wurde, bewies theoretisch, dass sowohl das Primfaktorzerlegungsproblem als auch das Problem des diskreten Logarithmus in &amp;ldquo;polynomieller Zeit&amp;rdquo; entschlüsselt werden können, wenn er auf einem ausreichend leistungsfähigen, fehlertoleranten universellen Quantencomputer (CRQC: Cryptographically Relevant Quantum Computer) ausgeführt wird. Das bedeutet, dass alle derzeit verwendeten Public-Key-Kryptographien unwirksam werden.&lt;/p>
&lt;div class="mermaid">graph TD
A["Großer Quantencomputer (CRQC)"] -->|Ausführung| B["Shor-Algorithmus"]
B -->|Entschlüsselung in polynomieller Zeit| C["Primfaktorzerlegungsproblem (RSA)"]
B -->|Entschlüsselung in polynomieller Zeit| D["Diskretes Logarithmusproblem (ECC / ECDSA)"]
C --> E["Abhören verschlüsselter Kommunikation, Datenmanipulation, Spoofing"]
D --> E
F["Store Now, Decrypt Later (SNDL)"] --> E&lt;/div>
&lt;p>Es ist sehr gefährlich zu denken: &amp;ldquo;Die vollständige Fertigstellung von Quantencomputern liegt noch Jahrzehnte in der Zukunft, also ist es kein Problem&amp;rdquo;. Denn eine Angriffsmethode namens &lt;strong>Store Now, Decrypt Later (SNDL)&lt;/strong> stellt bereits eine reale Bedrohung dar. Bei diesem Angriff speichern böswillige Staaten oder Hackerorganisationen große Mengen der derzeit verschlüsselten Kommunikationsdaten (wie TLS-Traffic) und entschlüsseln sie alle in dem Moment, in dem in Zukunft ein leistungsstarker Quantencomputer verfügbar wird. Staatsgeheimnisse, Infrastrukturinformationen und medizinische Daten, die über lange Zeiträume geschützt werden müssen, sind dieser Bedrohung bereits ausgesetzt.&lt;/p>
&lt;p>Für symmetrische Schlüsselkryptographie (wie AES) und Hash-Funktionen (wie SHA-256) existiert zudem der 1996 entdeckte &lt;strong>Grover-Algorithmus&lt;/strong>. Dieser reduziert den Rechenaufwand für Brute-Force-Angriffe auf die Quadratwurzel. Mit anderen Worten, das Sicherheitsniveau von AES-128 wird effektiv auf 2 hoch 64 halbiert. Im Quantenzeitalter wird daher die Verwendung längerer Schlüssel und Hash-Längen wie AES-256 und SHA-384 empfohlen.&lt;/p>
&lt;p>Um dieser beispiellosen Kryptographie-Krise zu begegnen, wurde die &lt;strong>Post-Quanten-Kryptographie (Post-Quantum Cryptography: PQC)&lt;/strong> entwickelt, die auf neuen mathematischen Problemen basiert, welche auch mit Quantencomputern schwer zu lösen sind. Basierend auf den Ergebnissen des vom National Institute of Standards and Technology (NIST) der USA geleiteten PQC-Standardisierungsprozesses erläutert dieser Artikel detailliert die wichtigsten PQC-Algorithmen, von ihren mathematischen Hintergründen über ihre Mechanismen bis hin zu Architekturvergleichen.&lt;/p>
&lt;hr>
&lt;h2 id="2-der-pqc-standardisierungsprozess-von-nist-gesamtbild-und-geschichte">2. Der PQC-Standardisierungsprozess von NIST: Gesamtbild und Geschichte
&lt;/h2>&lt;p>Der Übergang zu neuen Kryptographietechnologien, der die Neugestaltung von Protokollen, Systemaktualisierungen und den Austausch von Hardware umfasst, dauert Jahre bis Jahrzehnte. Daher haben Kryptographen auf der ganzen Welt frühzeitig die Erforschung von PQC vorangetrieben. Eine zentrale Rolle hat dabei das US-amerikanische NIST (National Institute of Standards and Technology) gespielt. Im Jahr 2016 rief NIST den PQC-Standardisierungsprozess aus und nahm Vorschläge für völlig neue kryptographische Algorithmen aus der weltweiten Kryptographie-Community entgegen.&lt;/p>
&lt;p>Gegenstand der Standardisierung waren die folgenden zwei Hauptkategorien:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Public-Key-Kryptographie / Schlüsselkapselungsmechanismen (KEM: Key Encapsulation Mechanism)&lt;/strong>: Ein Mechanismus zum sicheren Teilen (Verteilen) von symmetrischen Schlüsseln für die Verschlüsselung von Kommunikationskanälen, z. B. in TLS-Verbindungen.&lt;/li>
&lt;li>&lt;strong>Digitale Signaturen (Digital Signatures)&lt;/strong>: Ein Mechanismus für Software-Updates und digitale Zertifikate, um zu beweisen, dass Daten nicht manipuliert wurden und kein Spoofing des Absenders vorliegt (Authentizität).&lt;/li>
&lt;/ol>
&lt;p>Nach etwa sechs Jahren intensiver Evaluation, Analyse und kryptanalytischem Wettbewerb (Runde 1 bis Runde 3) sowie einer zusätzlichen Evaluierung (Runde 4) für einige Algorithmen, wurden im Jahr 2024 die folgenden Algorithmen offiziell als Federal Information Processing Standards (FIPS) veröffentlicht und somit als künftige weltweite Standards festgelegt:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>FIPS 203 (ML-KEM)&lt;/strong>: KEM basierend auf CRYSTALS-Kyber&lt;/li>
&lt;li>&lt;strong>FIPS 204 (ML-DSA)&lt;/strong>: Digitale Signatur basierend auf CRYSTALS-Dilithium&lt;/li>
&lt;li>&lt;strong>FIPS 205 (SLH-DSA)&lt;/strong>: Zustandlose Hash-basierte Signatur basierend auf SPHINCS+&lt;/li>
&lt;li>&lt;strong>(In zukünftiger Planung) FN-DSA&lt;/strong>: Digitale Signatur basierend auf FALCON&lt;/li>
&lt;/ul>
&lt;p>Die ausgewählten Algorithmen stützen sich auf jeweils unterschiedliche mathematische &amp;ldquo;Schwierigkeitsprobleme&amp;rdquo;, sodass eine Vielfalt (Crypto Agility) gewährleistet ist. Sollte in Zukunft eine fatale Schwachstelle in einem Algorithmus entdeckt werden, wird so verhindert, dass das gesamte System zusammenbricht. Im Standardisierungsprozess nahm die gitterbasierte Kryptographie (Lattice-based cryptography) aufgrund ihrer Leistung die Hauptrolle ein, jedoch wurden hashbasierte und codebasierte Kryptographien als starke Backups übernommen.&lt;/p>
&lt;hr>
&lt;h2 id="3-klassifizierung-der-wichtigsten-mathematischen-ansätze-in-pqc">3. Klassifizierung der wichtigsten mathematischen Ansätze in PQC
&lt;/h2>&lt;p>PQC-Algorithmen lassen sich nach den mathematischen Problemen, die ihre Sicherheit begründen, in die folgenden fünf Hauptkategorien einteilen. In diesem Artikel gehen wir speziell auf die ersten drei näher ein.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Gitterbasierte Kryptographie (Lattice-based Cryptography)&lt;/strong>:
Basiert auf dem Problem des kürzesten Vektors (Shortest Vector Problem, SVP), dem Problem des nächsten Vektors (Closest Vector Problem, CVP) in mehrdimensionalen Gitterräumen sowie dem davon abgeleiteten LWE-Problem. Dies ist das Herzstück der NIST-Standardisierung; Kyber, Dilithium und FALCON gehören dazu. Es bietet die beste Balance aus Verarbeitungsgeschwindigkeit, Public-Key-Größe und Chiffretextgröße und eignet sich daher für allgemeine Anwendungen.&lt;/li>
&lt;li>&lt;strong>Hash-basierte Kryptographie (Hash-based Cryptography)&lt;/strong>:
Stützt sich für ihre Sicherheit ausschließlich auf die &amp;ldquo;Kollisionsresistenz&amp;rdquo; und die &amp;ldquo;Einweg-Eigenschaft&amp;rdquo; von kryptographischen Hash-Funktionen (wie SHA-2 und SHAKE). Sie ist nur auf digitale Signaturen (wie SPHINCS+) anwendbar, bietet jedoch die stärksten Sicherheitsbeweise und zeichnet sich durch extrem hohe Resistenz gegen unbekannte mathematische Angriffe aus.&lt;/li>
&lt;li>&lt;strong>Code-basierte Kryptographie (Code-based Cryptography)&lt;/strong>:
Basiert auf der Theorie der Fehlerkorrekturcodes und stützt sich auf die Schwierigkeit des Syndrom-Decodierungsproblems (Syndrome Decoding Problem). Ein typisches Beispiel ist das in den 1970er Jahren vorgeschlagene Classic McEliece, das eine lange Geschichte und bewährte Sicherheit aufweist, aber den Nachteil extrem großer Public-Key-Größen im Megabyte-Bereich hat.&lt;/li>
&lt;li>&lt;strong>Multivariate polynomische Kryptographie (Multivariate Polynomial Cryptography)&lt;/strong>:
Basiert auf der Schwierigkeit, Lösungen für Systeme von multivariaten quadratischen Gleichungen über endlichen Körpern zu finden (MQ-Problem). Sie wurde hauptsächlich für digitale Signaturen (wie Rainbow) vorgeschlagen, jedoch wurde während der finalen NIST-Runde eine leistungsstarke Angriffsmethode entdeckt, die es ermöglichte, sie auf einem einzigen PC in wenigen Tagen zu knacken, weshalb viele dieser Algorithmen aus der Standardisierung herausfielen.&lt;/li>
&lt;li>&lt;strong>Isogenie-basierte Kryptographie (Isogeny-based Cryptography)&lt;/strong>:
Basiert auf dem Problem der Wegfindung auf Isogenie-Graphen elliptischer Kurven. Sie hatte sehr kleine Schlüsselgrößen und galt als legitimer Nachfolger von ECC. Der finale Kandidat &amp;ldquo;SIKE&amp;rdquo; wurde jedoch 2022 mithilfe klassischer Mathematik (z.B. Castryck-Decru-Angriff) auf einem normalen PC in nur wenigen Stunden vollständig geknackt, was ein dramatisches Ende darstellte und die Schwierigkeit und Gefahr des PQC-Designs symbolisiert.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="4-die-tiefen-der-gitterkryptographie-lwe-problem-und-die-mathematischen-grundlagen-von-module-lwe">4. Die Tiefen der Gitterkryptographie: LWE-Problem und die mathematischen Grundlagen von Module-LWE
&lt;/h2>&lt;p>Die &lt;strong>Gitterkryptographie&lt;/strong>, die derzeit als vielversprechendster Ansatz gilt und im Zentrum der Standardisierung steht. Die Grundlage ihrer Sicherheit ist das &lt;strong>LWE-Problem (Learning with Errors: Lernen mit Fehlern)&lt;/strong>. Es wurde 2005 von Oded Regev vorgestellt, eine bahnbrechende Leistung, für die er den Gödel-Preis erhielt. Ohne das Verständnis des LWE-Problems kann man die moderne PQC nicht diskutieren.&lt;/p>
&lt;h3 id="41-was-ist-das-lwe-problem-learning-with-errors">4.1. Was ist das LWE-Problem (Learning with Errors)?
&lt;/h3>&lt;p>Betrachten wir zunächst ein einfaches lineares Gleichungssystem. Angenommen, es gibt unter einem Modul $q$ eine bekannte zufällige Matrix $A$ und einen unbekannten geheimen Vektor $\vec{s}$, und ihr Produkt $\vec{b}$ sei gegeben.&lt;/p>
$$ \vec{b} = A\vec{s} \pmod q $$
&lt;p>In diesem Fall ist es einfach, das unbekannte $\vec{s}$ aus den öffentlichen Informationen $A$ und $\vec{b}$ zu ermitteln. Mit dem klassischen &amp;ldquo;Gaußschen Eliminationsverfahren&amp;rdquo; kann $\vec{s}$ leicht in polynomieller Zeit berechnet werden.&lt;/p>
&lt;p>Wenn wir dieser Gleichung jedoch einen &amp;ldquo;kleinen absichtlichen Fehler (Rauschen)&amp;rdquo; hinzufügen, steigt der Schwierigkeitsgrad des Problems dramatisch an. Das ist das &lt;strong>LWE-Problem&lt;/strong>.&lt;/p>
&lt;p>Wir bereiten einen unbekannten geheimen Vektor $\vec{s} \in \mathbb{Z}_q^n$ und eine zufällig gewählte Matrix $A \in \mathbb{Z}_q^{m \times n}$ vor. Darüber hinaus bereiten wir einen Fehlervektor $\vec{e} \in \mathbb{Z}_q^m$ vor, dessen Werte nach einer Normal- oder Binomialverteilung ausgewählt wurden und &amp;ldquo;ausreichend klein&amp;rdquo; sind, und berechnen $\vec{b}$ wie folgt:&lt;/p>
$$ \vec{b} = A\vec{s} + \vec{e} \pmod q $$
&lt;p>Das &lt;strong>Search-LWE-Problem&lt;/strong> besteht darin, &amp;ldquo;die geheimen Informationen $\vec{s}$ aus den öffentlichen Informationen $(A, \vec{b})$ zu ermitteln&amp;rdquo;. Durch die Anwesenheit dieses Fehlers $\vec{e}$ werden algebraische Lösungsmethoden wie die Gaußsche Elimination scheitern, da der Fehler $\vec{e}$ durch die Addition und Subtraktion von Gleichungen schneeballartig anwächst, bis er schließlich von zufälligen Werten nicht mehr zu unterscheiden ist.&lt;/p>
&lt;p>Das Großartige am LWE-Problem ist, dass es einen starken theoretischen Beweis (Reduktion) gibt: Sofern kein Quantenalgorithmus existiert, der &amp;ldquo;Worst-Case-Probleme auf Gittern&amp;rdquo; wie GapSVP (Entscheidungsproblem des kürzesten Vektors) oder SIVP (Problem der kürzesten unabhängigen Vektoren) lösen kann, kann das LWE-Problem auch im Durchschnittsfall (Average-case) nicht gelöst werden. Das bedeutet, dass selbst zufällig generierte kryptographische Schlüssel eine robuste, durch theoretische Obergrenzen untermauerte Sicherheit garantieren.&lt;/p>
&lt;h3 id="42-dramatische-effizienzsteigerung-durch-ring-lwe-und-module-lwe">4.2. Dramatische Effizienzsteigerung durch Ring-LWE und Module-LWE
&lt;/h3>&lt;p>Das gewöhnliche LWE-Problem (Standard-LWE) hat eine sehr klare Sicherheitsbasis, ist jedoch unpraktisch, da die Größe der Matrix $A$ extrem anwächst und Schlüsselgrößen im Megabyte-Bereich entstehen. Daher wurde ein Ansatz vorgeschlagen, Polynomringe (Polynomial Rings) zu nutzen, um eine algebraische Struktur einzuführen.&lt;/p>
&lt;p>Beim &lt;strong>Ring-LWE-Problem&lt;/strong> werden anstelle einfacher Vektoren oder Matrizen Elemente (Polynome) eines bestimmten Polynomrings $R_q$ verwendet. Die in den NIST-Standards am häufigsten verwendeten sind Kreisteilungs-Polynomringe wie:&lt;/p>
$$ R_q = \mathbb{Z}_q[X]/(X^n + 1) $$
&lt;p>Hier ist $n$ eine Potenz von 2 (z. B. 256) und $q$ eine geeignete Primzahl. Auf diesem Ring werden Elemente $a, s, e \in R_q$ verwendet, um $b = a \cdot s + e \pmod q$ zu berechnen. Da ein einziges Polynom $a$ über $n$ Koeffizienten verfügt, können Daten erheblich komprimiert werden. Darüber hinaus ermöglicht die Verwendung der &lt;strong>NTT (Number Theoretic Transform: Zahlentheoretische Transformation)&lt;/strong>, einer Endliche-Körper-Version der schnellen Fourier-Transformation (FFT), extrem schnelle Polynommultiplikationen in $O(n \log n)$ Rechenschritten.&lt;/p>
&lt;p>Bei Ring-LWE bestand jedoch die Sorge, dass &amp;ldquo;aufgrund der speziellen algebraischen Ringstruktur unbekannte Schwachstellen existieren könnten&amp;rdquo;. Ein weiteres technisches Problem war, dass bei der Änderung des Sicherheitsniveaus (z.B. äquivalent zu AES-128, 192, 256) der Polynomgrad $n$ selbst geändert werden musste, wodurch die gesamte Implementierung, wie etwa der NTT-Algorithmus, umgeschrieben werden musste.&lt;/p>
&lt;p>Deshalb haben die standardisierten Algorithmen Kyber und Dilithium das &lt;strong>Module-LWE (M-LWE) Problem&lt;/strong> übernommen. Module-LWE ist ein Kompromiss, der genau in der Mitte zwischen dem strukturlosen Standard-LWE und dem zu stark strukturierten Ring-LWE liegt, indem es $k \times k$ Matrizen (Module) verwendet, deren Komponenten Elemente des Polynomrings $R_q$ sind:&lt;/p>
$$ \vec{b} = A\vec{s} + \vec{e} \pmod{R_q} \quad (A \in R_q^{k \times k}, \vec{s}, \vec{e} \in R_q^k) $$
&lt;p>Der größte Vorteil von Module-LWE ist, dass das Sicherheitsniveau leicht skaliert werden kann, indem lediglich die Matrixdimension $k$ geändert wird, während der Polynomgrad $n$ ($n=256$ in den NIST-Standards) konstant bleibt.
Zum Beispiel wird bei Kyber die Dimension $k$ wie folgt angepasst:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Kyber512 (Level 1)&lt;/strong>: $k = 2$ (entspricht AES-128)&lt;/li>
&lt;li>&lt;strong>Kyber768 (Level 3)&lt;/strong>: $k = 3$ (entspricht AES-192)&lt;/li>
&lt;li>&lt;strong>Kyber1024 (Level 5)&lt;/strong>: $k = 4$ (entspricht AES-256)&lt;/li>
&lt;/ul>
&lt;p>Dies machte es möglich, den zugrunde liegenden NTT-Code und Hardware-Schaltungen für Polynomoperationen über alle Sicherheitsstufen hinweg zu 100% wiederzuverwenden, was die Sicherheit und Effizienz der Implementierung drastisch verbesserte.&lt;/p>
&lt;hr>
&lt;h2 id="5-crystals-kyber-ml-kem-der-schlüsselkapselungsmechanismus-der-nächsten-generation">5. CRYSTALS-Kyber (ML-KEM): Der Schlüsselkapselungsmechanismus der nächsten Generation
&lt;/h2>&lt;p>CRYSTALS-Kyber, offiziell als &lt;strong>FIPS 203 (ML-KEM)&lt;/strong> standardisiert, ist ein Schlüsselkapselungsmechanismus (KEM), der auf dem oben erwähnten Module-LWE-Problem basiert. Er wird de facto der künftige weltweite Standard für das sichere Teilen von Sitzungsschlüsseln in Protokollen wie TLS 1.3 und SSH sein.&lt;/p>
&lt;h3 id="51-architektur-des-kem-key-encapsulation-mechanism">5.1. Architektur des KEM (Key Encapsulation Mechanism)
&lt;/h3>&lt;p>In der PQC-Ära wird anstelle des direkten Ansatzes von RSA, bei dem &amp;ldquo;der Client einen symmetrischen Schlüssel erstellt, ihn mit dem öffentlichen Schlüssel des Servers verschlüsselt und sendet&amp;rdquo;, das Kapselungs-Framework KEM zum Standard.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant Client as "Client (Alice)"
participant Server as "Server (Bob)"
Note over Client: "ML-KEM KeyGen()"
Client->>Client: "Erzeugt privaten (sk) und öffentlichen Schlüssel (pk)"
Client->>Server: "Sendet öffentlichen Schlüssel (pk)"
Note over Server: "ML-KEM Encaps()"
Server->>Server: "Erzeugt zufälligen symmetrischen Schlüssel (K)"
Server->>Server: "Kapselt K mit pk, erstellt Chiffretext (c)"
Server->>Client: "Sendet Chiffretext (c)"
Note over Client: "ML-KEM Decaps()"
Client->>Client: "Entschlüsselt Chiffretext (c) mit privatem Schlüssel (sk)"
Client->>Client: "Entkapselt und extrahiert den symmetrischen Schlüssel (K)"
Note over Client, Server: "Start der verschlüsselten Kommunikation (z. B. AES) mit dem geteilten Schlüssel (K)"&lt;/div>
&lt;h3 id="52-der-interne-algorithmus-von-kyber-und-die-fujisaki-okamoto-transformation">5.2. Der interne Algorithmus von Kyber und die Fujisaki-Okamoto-Transformation
&lt;/h3>&lt;p>Das Design von Kyber ist sehr raffiniert. Zunächst wird ein Public-Key-Kryptosystem (Kyber.CPAPKE) konstruiert, das nur gegen CPA (Chosen-Plaintext Attacks) sicher ist. Durch die Anwendung einer kryptographisch sehr mächtigen Methode namens &lt;strong>Fujisaki-Okamoto-Transformation (Fujisaki-Okamoto Transform)&lt;/strong> wird dieses System zu einem vollständigen KEM aufgerüstet, das auch gegen CCA (Adaptive Chosen-Ciphertext Attacks) sicher ist.&lt;/p>
&lt;p>Der zentrale Verschlüsselungs- und Entschlüsselungsmechanismus von CPAPKE funktioniert wie folgt:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Schlüsselerzeugung (Key Generation)&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>Eine Matrix $A \in R_q^{k \times k}$ im NTT-Bereich wird aus einem zufälligen Seed generiert. Der Modul $q$ ist $3329$.&lt;/li>
&lt;li>Der geheime Vektor $\vec{s}$ und der Fehlervektor $\vec{e}$ mit kleinen Koeffizienten werden aus einer zentrierten Binomialverteilung (CBD) abgetastet.&lt;/li>
&lt;li>Es wird $\vec{t} = A\vec{s} + \vec{e}$ berechnet. Der öffentliche Schlüssel ist $(A, \vec{t})$, der private Schlüssel ist $\vec{s}$. (In der Praxis wird $A$ als Seed veröffentlicht, um Bandbreite zu sparen).&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Verschlüsselung (Encryption)&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>Die zu teilende 32-Byte-Nachricht (Schlüsselmaterial) $m$ wird in ein Polynom kodiert.&lt;/li>
&lt;li>Ein neuer zufälliger Vektor $\vec{r}$ und kleine Fehler $\vec{e_1}, e_2$ werden generiert.&lt;/li>
&lt;li>$\vec{u} = A^T\vec{r} + \vec{e_1}$&lt;/li>
&lt;li>$v = \vec{t}^T\vec{r} + e_2 + \lfloor q/2 \rceil \cdot m$&lt;/li>
&lt;li>Der Chiffretext ist $(\vec{u}, v)$.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Entschlüsselung (Decryption)&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>Der Empfänger berechnet $v - \vec{s}^T\vec{u}$.&lt;/li>
&lt;li>Wenn wir diese Gleichung ausklappen, erhalten wir:
$v - \vec{s}^T\vec{u} = (\vec{t}^T\vec{r} + e_2 + \lfloor q/2 \rceil \cdot m) - \vec{s}^T(A^T\vec{r} + \vec{e_1})$&lt;/li>
&lt;li>Setzen wir hier $\vec{t} = A\vec{s} + \vec{e}$ ein, heben sich die Hauptterme $\vec{s}^TA^T\vec{r}$ auf.&lt;/li>
&lt;li>Übrig bleibt $\lfloor q/2 \rceil \cdot m + (\vec{e}^T\vec{r} + e_2 - \vec{s}^T\vec{e_1})$.&lt;/li>
&lt;li>Da die Terme in den Klammern &amp;ldquo;Produkte und Summen kleiner Fehler&amp;rdquo; sind, bleibt das Ganze ein ausreichend kleiner Wert (Rauschen). Daher kann durch Schwellenwertbestimmung, ob jeder Koeffizient näher an $0$ oder $q/2$ liegt, das Bit der ursprünglichen Nachricht $m$ (0 oder 1) völlig fehlerfrei wiederhergestellt werden.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>Die größte Stärke von Kyber liegt in seiner enormen &lt;strong>Verarbeitungsgeschwindigkeit&lt;/strong> und der &lt;strong>moderaten Schlüsselgröße&lt;/strong>. Bei Kyber768 beträgt die Public-Key-Größe 1.184 Bytes und die Chiffretextgröße 1.088 Bytes. Auch wenn dies im Vergleich zu RSA-3072 (Schlüsselgröße ca. 384 Bytes) größer ist, passt es ohne Paketfragmentierung in die MTU (Maximum Transmission Unit) moderner Internetkommunikation und hat kaum negative Auswirkungen auf die Netzwerklatenz.&lt;/p>
&lt;hr>
&lt;h2 id="6-crystals-dilithium-ml-dsa-gitterbasierte-universelle-digitale-signatur">6. CRYSTALS-Dilithium (ML-DSA): Gitterbasierte universelle digitale Signatur
&lt;/h2>&lt;p>Bei der Standardisierung digitaler Signaturen konkurrierten Algorithmen mit unterschiedlichen Designphilosophien innerhalb desselben gitterbasierten Ansatzes. Unter diesen wurde &lt;strong>CRYSTALS-Dilithium&lt;/strong> als universelle digitale Signatur &lt;strong>FIPS 204 (ML-DSA)&lt;/strong> ausgewählt.&lt;/p>
&lt;h3 id="61-das-fiat-shamir-with-aborts-paradigma">6.1. Das &amp;ldquo;Fiat-Shamir with Aborts&amp;rdquo;-Paradigma
&lt;/h3>&lt;p>Dilithium ist, wie Kyber, ein digitales Signaturschema, das auf Module-LWE (und dem Module-SIS-Problem) basiert. Die Grundlage seines Designs ist das extrem wichtige Paradigma der &lt;strong>&amp;ldquo;Fiat-Shamir-Transformation mit Abbrüchen (Fiat-Shamir with Aborts)&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;p>Die Fiat-Shamir-Transformation an sich ist eine Standardmethode zur Umwandlung interaktiver Zero-Knowledge-Beweisprotokolle in nicht-interaktive digitale Signaturen. Der Beweiser (Signierende) erzeugt ein Commitment $y$, berechnet $w = Ay$ und leitet es durch eine Hash-Funktion, um eine zufällige Challenge $c$ zu erhalten, und berechnet die Antwort $z = y + cs$.&lt;/p>
&lt;p>Wenn dies jedoch einfach in der Gitterkryptographie angewendet wird, verzerrt sich die Verteilung der Antwort $z$ abhängig vom Wert des privaten Schlüssels $s$. Dies führte zu dem fatalen Problem, dass ein Angreifer, der viele Signaturen beobachtet, nach und nach Informationen über den privaten Schlüssel $s$ erlangen konnte (ein mathematisches Leck, das Seitenkanalangriffen ähnelt).&lt;/p>
&lt;p>Das Dilithium-Designteam (Lyubashevsky et al.) führte eine Methode namens &lt;strong>&amp;ldquo;Rejection Sampling (Verwerfungsmethode)&amp;rdquo;&lt;/strong> ein. Dabei wird der gesamte Signaturprozess abgebrochen (Abort), wenn die Koeffizienten des berechneten Ergebnisses $z$ nicht in einen voreingestellten sicheren Schwellenwertbereich fallen, und die Berechnung mit einer neuen Zufallszahl $y$ von vorn begonnen.&lt;/p>
&lt;p>Dadurch folgt die letztendlich ausgegebene Signatur $z$ einer vollkommen gleichmäßigen Verteilung, die völlig unabhängig vom privaten Schlüssel ist, wodurch Informationslecks mathematisch vollständig verhindert werden konnten.&lt;/p>
&lt;h3 id="62-vorteile-von-dilithium-und-einfache-implementierung">6.2. Vorteile von Dilithium und einfache Implementierung
&lt;/h3>&lt;p>Ein großer Designvorteil von Dilithium besteht darin, dass es im Signaturerzeugungsprozess &lt;strong>überhaupt kein&lt;/strong> komplexes &amp;ldquo;Sampling aus Gauß-Verteilungen&amp;rdquo; oder &amp;ldquo;Fließkommaoperationen&amp;rdquo; verwendet. Da es nur mit Sampling aus einer Gleichverteilung, einfachen ganzzahligen Modulo-Operationen, NTT und Hash-Funktionen (SHAKE) implementiert werden kann, ist es in einer Vielzahl von Umgebungen – vom eingebetteten Mikrocontroller bis zum Cloud-Server – einfach sicher und in konstanter Zeit (Constant-time) zu implementieren. Dies macht es sehr widerstandsfähig gegen physische Seitenkanalangriffe wie Timing-Angriffe.&lt;/p>
&lt;hr>
&lt;h2 id="7-falcon-fn-dsa-die-ultimativ-kompakte-gittersignatur">7. FALCON (FN-DSA): Die ultimativ kompakte Gittersignatur
&lt;/h2>&lt;p>Das NIST hat als eine weitere gitterbasierte Signatur mit anderen Eigenschaften als Dilithium &lt;strong>FALCON (Fast-Fourier Lattice-based Compact Signatures over NTRU)&lt;/strong> als Standardisierungskandidaten ausgewählt (derzeit als FN-DSA im Entwurfsstadium).&lt;/p>
&lt;h3 id="71-ntru-gitter-und-gauß-sampling">7.1. NTRU-Gitter und Gauß-Sampling
&lt;/h3>&lt;p>Das Hauptmerkmal von FALCON ist, dass es nicht das LWE-Problem, sondern das seit 1996 existierende und historische &lt;strong>NTRU-Gitter (N-th degree Truncated polynomial Ring Units)&lt;/strong> verwendet. Darüber hinaus nutzt es das &lt;strong>&amp;ldquo;Hash-and-Sign&amp;rdquo;&lt;/strong>-Paradigma, das auf dem GPV-Framework (Gentry-Peikert-Vaikuntanathan) basiert.&lt;/p>
&lt;p>Bei Hash-and-Sign wird der Hash-Wert der Nachricht als Zielpunkt im Raum betrachtet und der diesem Punkt am nächsten liegende Gitterpunkt (eine ungefähre Lösung des Problems des nächsten Vektors) als Signatur gefunden. Hierfür müssen Punkte nach einer diskreten Gauß-Verteilung abgetastet werden, wofür die &amp;ldquo;kurze Basis guter Qualität&amp;rdquo;, der private Schlüssel, verwendet wird.&lt;/p>
&lt;p>FALCON beschleunigt diese rechenintensive Aufgabe drastisch durch eine Technik namens &lt;strong>&amp;ldquo;Fast Fourier Orthogonalization (FFO)&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;h3 id="72-vor--und-nachteile-von-falcon">7.2. Vor- und Nachteile von FALCON
&lt;/h3>&lt;p>Der überwältigende Vorteil von FALCON ist, dass &lt;strong>seine Signaturgröße und Public-Key-Größe extrem klein (kompakt)&lt;/strong> sind. Während die Signaturgröße von Dilithium3 etwa 3.309 Bytes beträgt, liegt sie bei FALCON-512 bei nur ca. 666 Bytes. Auch der öffentliche Schlüssel ist mit 897 Bytes sehr klein, was es zum Retter in Umgebungen mit extrem eingeschränkter Bandbreite, für IoT-Geräte oder bestimmte Netzwerkprotokolle macht.&lt;/p>
&lt;p>Allerdings gibt es einen gravierenden Nachteil. Da die Signaturerzeugung zwangsläufig komplexes diskretes Gauß-Sampling mit &lt;strong>Fließkommaoperationen (64-Bit IEEE 754)&lt;/strong> erfordert, ist eine Constant-Time-Implementierung zur Vermeidung von Timing-Leaks äußerst schwierig, und der Code bläht sich auf. Aus diesem Grund positioniert sich FALCON im Gegensatz zur allgemeinen Nutzung (Dilithium) als leistungsstarker, spezialisierter Algorithmus für spezifische Anwendungen.&lt;/p>
&lt;div class="mermaid">graph LR
A["Anforderungen an digitale Signaturen"] --> B{"Was ist die oberste Priorität?"}
B -->|"Einfachheit der Implementierung, Vielseitigkeit, leichte Constant-Time-Implementierung"| C["Dilithium (ML-DSA)"]
B -->|"Minimierung der Bandbreite, kompakte Datengröße"| D["FALCON (FN-DSA)"]
C --> E["Allgemeine TLS-Zertifikate, elektronische Signaturen für Software"]
D --> F["Protokolle mit strengen Paketgrößenlimits, spezielle Umgebungen"]&lt;/div>
&lt;hr>
&lt;h2 id="8-sphincs-slh-dsa-hash-basierte-signatur-mit-der-stärksten-sicherheit">8. SPHINCS+ (SLH-DSA): Hash-basierte Signatur mit der stärksten Sicherheit
&lt;/h2>&lt;p>Für den Worst-Case, dass die Sicherheit der Gitterkryptographie in Zukunft durch den Durchbruch eines genialen Mathematikers gebrochen wird, hat NIST &lt;strong>FIPS 205 (SLH-DSA)&lt;/strong>, sprich &lt;strong>SPHINCS+&lt;/strong>, als Standard mit einem völlig anderen Ansatz als die Gitterkryptographie festgelegt.&lt;/p>
&lt;p>SPHINCS+ wird als &lt;strong>hash-basierte Signatur&lt;/strong> klassifiziert. Die Basis seiner Sicherheit stützt sich nur auf einen einzigen Punkt: &amp;ldquo;Die verwendete kryptographische Hash-Funktion (wie SHA-2 oder SHAKE256) muss kollisionsresistent und eine Einwegfunktion sein&amp;rdquo;. Da es nicht von mathematischen Problemen mit spezifischen algebraischen Strukturen wie LWE oder Primfaktorzerlegung abhängt, bietet es eine extrem robuste Sicherheit (die konservativste Sicherheit). Egal, wie mächtige Quantenalgorithmen in Zukunft erscheinen mögen, es kann abgewehrt werden, indem man einfach die Ausgabelänge der Hash-Funktion erhöht.&lt;/p>
&lt;h3 id="81-zustandslose-architektur-mit-wots-und-fors">8.1. Zustandslose Architektur mit WOTS+ und FORS
&lt;/h3>&lt;p>Die Geschichte der hash-basierten Signaturen reicht weit in die 1970er Jahre zu Lamport-Signaturen und Winternitz-Einmal-Signaturen (WOTS) zurück. Dabei handelte es sich um Wegwerfschlüssel, mit denen &amp;ldquo;nur einmal sicher signiert&amp;rdquo; werden konnte. Um diese mehrfach verwendbar zu machen, wurden Algorithmen wie XMSS (eXtended Merkle Signature Scheme) oder LMS entwickelt, die einen Merkle-Baum kombinieren, um unzählige Einmalschlüssel mit einem einzigen Root-Hash zu verwalten.&lt;/p>
&lt;p>XMSS und LMS wiesen jedoch den großen Nachteil auf, dass sie &lt;strong>&amp;ldquo;zustandsbehaftet (stateful)&amp;rdquo;&lt;/strong> waren. Bei jeder Signatur musste der Index-Status (&amp;ldquo;der wievielte Einmalschlüssel wurde verwendet&amp;rdquo;) strikt im nichtflüchtigen Speicher mitgeschrieben werden. Wenn der Zustand z. B. durch das Wiederherstellen eines VM-Snapshots zurückgesetzt wird und derselbe Einmalschlüssel ein zweites Mal verwendet wird, ist der private Schlüssel sofort kompromittiert und das System bricht zusammen.&lt;/p>
&lt;p>SPHINCS+ ist eine &lt;strong>&amp;ldquo;zustandslose (stateless)&amp;rdquo;&lt;/strong> hash-basierte Signatur, die dieses lästige Zustandsmanagement gelöst hat.
Seine Kerntechnologie besteht aus folgender Kombination:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>WOTS+ (Winternitz One-Time Signature Plus)&lt;/strong>: Eine grundlegende Einmal-Signatur.&lt;/li>
&lt;li>&lt;strong>FORS (Forest of Random Subsets)&lt;/strong>: Eine Few-Time-Signature-Technologie. Sie gewährleistet die Sicherheit, auch wenn derselbe Schlüssel ein paar Mal wiederverwendet wird.&lt;/li>
&lt;li>&lt;strong>Hyper-Tree (Riesige Baumstruktur)&lt;/strong>: Eine gigantische Struktur, bei der Merkle-Bäume mehrschichtig übereinandergelegt werden.&lt;/li>
&lt;/ol>
&lt;p>Bei der Signierung mit SPHINCS+ wird, anstatt Zustände zu verwalten, mittels Pseudozufallszahlen zufällig einer der unzähligen FORS-Schlüssel an der Basis des Hyper-Trees ausgewählt. Da die Anzahl der Blätter am Baum astronomisch hoch ist, wird die Wahrscheinlichkeit (Kollision), denselben Schlüssel zufällig zweimal zu wählen, verschwindend gering, was letztlich zur Zustandslosigkeit führt.&lt;/p>
&lt;p>Die einzige und größte Schwäche von SPHINCS+ ist die &lt;strong>extrem große Signaturgröße&lt;/strong>. Je nach Parametern erreicht die Signaturgröße 17 bis 49 Kilobytes, und die Signaturerzeugung ist im Vergleich zur Gitterkryptographie überwältigend langsam. Daher wird sie eher nicht für das alltägliche Webbrowsing eingesetzt, sondern für Anwendungen wie Software-Update-Signaturen oder Root-Zertifikate (CA), bei denen nicht häufig signiert wird, aber langfristige absolute Sicherheit zwingend erforderlich ist.&lt;/p>
&lt;hr>
&lt;h2 id="9-code-basierte-kryptographie-der-gute-alte-riese-classic-mceliece">9. Code-basierte Kryptographie: Der gute alte Riese Classic McEliece
&lt;/h2>&lt;p>Ein wichtiger Ansatz, der als Finalist in Runde 4 des NIST-Standardisierungsprozesses weiterhin evaluiert wird, ist &lt;strong>Classic McEliece&lt;/strong>, das auf &lt;strong>code-basierter Kryptographie&lt;/strong> beruht.&lt;/p>
&lt;p>Dieser Algorithmus wurde 1978 von Robert McEliece vorgeschlagen und ist neben RSA einer der ältesten in der Geschichte der Public-Key-Kryptographie. Er verwendet algebraisch-geometrische Codes, sogenannte &amp;ldquo;Goppa-Codes&amp;rdquo;. Dabei wird eine Nachricht durch absichtliches Hinzufügen von Fehlern (Rauschvektoren) verschlüsselt. Nur wer die Paritätsprüfmatrix des Goppa-Codes als privaten Schlüssel besitzt, kann die starke Fehlerkorrekturfähigkeit nutzen, um die Fehler zu entfernen und die ursprüngliche Nachricht zu entschlüsseln. Dies basiert auf dem &lt;strong>&amp;ldquo;Syndrom-Decodierungsproblem (Syndrome Decoding Problem)&amp;rdquo;&lt;/strong>.&lt;/p>
$$ \vec{c} = \vec{m} G + \vec{e} $$
&lt;p>
(Wobei $G$ die verschlüsselte Generatormatrix als öffentlicher Schlüssel und $\vec{e}$ der Fehlervektor vom Gewicht $t$ ist)&lt;/p>
&lt;p>Das Erstaunliche an Classic McEliece ist seine überwältigende Erfolgsbilanz: &lt;strong>Obwohl es seit seinem Entwurf vor über 40 Jahren intensiver kryptanalytischer Forschung von Kryptographen auf der ganzen Welt ausgesetzt war, wurde nie eine grundlegende Schwachstelle entdeckt.&lt;/strong> Unter allen PQC-Ansätzen besitzt es die &amp;ldquo;durch die Zeit am besten bewiesene, robuste Sicherheit&amp;rdquo;.&lt;/p>
&lt;p>Darüber hinaus hat es den Vorteil, dass die Chiffretextgröße sehr klein ist (nur etwa 100 bis 200 Bytes). Es hat jedoch den fatalen Nachteil, dass &lt;strong>die Public-Key-Größe in den Megabyte-Bereich (MB) reicht&lt;/strong>. Selbst auf der niedrigsten Sicherheitsstufe (entsprechend AES-128) ist der öffentliche Schlüssel ca. 250 KB groß, auf höheren Stufen übersteigt er 1 MB.&lt;/p>
&lt;p>Aus diesem Grund eignet es sich überhaupt nicht für Anwendungsfälle wie den TLS-Handshake, bei denen der öffentliche Schlüssel bei jeder Kommunikation über das Netzwerk gesendet wird. In speziellen Anwendungsfällen jedoch, bei denen der öffentliche Schlüssel im Voraus im System platziert werden kann, wie etwa beim Schlüsselaustausch für VPNs, bei in Firmware hartkodierten öffentlichen Schlüsseln oder bei Satellitenkommunikation, wird er aufgrund seiner starken Sicherheit weiterhin als äußerst vielversprechende Option betrachtet.&lt;/p>
&lt;hr>
&lt;h2 id="10-leistungsvergleich-und-kompromisse-der-einzelnen-pqc-algorithmen">10. Leistungsvergleich und Kompromisse der einzelnen PQC-Algorithmen
&lt;/h2>&lt;p>Die Leistungsmerkmale der bisher diskutierten Hauptalgorithmen bei gängigen Sicherheitsniveaus (NIST Level 2 bis 3, entsprechend AES-128 bis 192) sind in der folgenden Tabelle zusammengefasst.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Algorithmus (Standardname)&lt;/th>
&lt;th style="text-align:left">Kategorie&lt;/th>
&lt;th style="text-align:left">Mathematische Grundlage&lt;/th>
&lt;th style="text-align:left">Public-Key-Größe&lt;/th>
&lt;th style="text-align:left">Private-Key-Größe&lt;/th>
&lt;th style="text-align:left">Chiffretext-/Signaturgröße&lt;/th>
&lt;th style="text-align:left">Verarbeitungsgeschwindigkeit&lt;/th>
&lt;th style="text-align:left">Hauptmerkmale und Anwendungen&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Kyber768&lt;/strong>&lt;br>(ML-KEM)&lt;/td>
&lt;td style="text-align:left">KEM&lt;/td>
&lt;td style="text-align:left">Module-LWE&lt;/td>
&lt;td style="text-align:left">1.184 Bytes&lt;/td>
&lt;td style="text-align:left">2.400 Bytes&lt;/td>
&lt;td style="text-align:left">1.088 Bytes&lt;/td>
&lt;td style="text-align:left">Sehr schnell&lt;/td>
&lt;td style="text-align:left">Beste Balance aus Schlüsselgröße und Geschwindigkeit. Universeller KEM-Standard für z. B. TLS 1.3.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Dilithium3&lt;/strong>&lt;br>(ML-DSA)&lt;/td>
&lt;td style="text-align:left">Signatur&lt;/td>
&lt;td style="text-align:left">Module-LWE&lt;/td>
&lt;td style="text-align:left">1.952 Bytes&lt;/td>
&lt;td style="text-align:left">4.032 Bytes&lt;/td>
&lt;td style="text-align:left">3.309 Bytes&lt;/td>
&lt;td style="text-align:left">Erzeugung &amp;amp; Verifizierung schnell&lt;/td>
&lt;td style="text-align:left">Einfache Implementierung. Universeller Standard für digitale Signaturen.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>FALCON-512&lt;/strong>&lt;br>(FN-DSA)&lt;/td>
&lt;td style="text-align:left">Signatur&lt;/td>
&lt;td style="text-align:left">NTRU-Gitter&lt;/td>
&lt;td style="text-align:left">897 Bytes&lt;/td>
&lt;td style="text-align:left">1.281 Bytes&lt;/td>
&lt;td style="text-align:left">666 Bytes&lt;/td>
&lt;td style="text-align:left">Erzeugung eher langsam, Verifizierung ultraschnell&lt;/td>
&lt;td style="text-align:left">Minimale Signaturgröße. Erfordert jedoch Fließkommaoperationen. Für Embedded &amp;amp; IoT.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>SPHINCS+&lt;/strong>&lt;br>(SLH-DSA)&lt;/td>
&lt;td style="text-align:left">Signatur&lt;/td>
&lt;td style="text-align:left">Hash-Funktion&lt;/td>
&lt;td style="text-align:left">32 Bytes&lt;/td>
&lt;td style="text-align:left">64 Bytes&lt;/td>
&lt;td style="text-align:left">ca. 17.000 Bytes&lt;/td>
&lt;td style="text-align:left">Erzeugung sehr langsam&lt;/td>
&lt;td style="text-align:left">Mathematisches Ausfallrisiko fast null. Hochsicherheitsanwendungen wie Root-Zertifikate.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Classic McEliece&lt;/strong>&lt;/td>
&lt;td style="text-align:left">KEM&lt;/td>
&lt;td style="text-align:left">Goppa-Code&lt;/td>
&lt;td style="text-align:left">&lt;strong>ca. 1,04 MB&lt;/strong>&lt;/td>
&lt;td style="text-align:left">13.568 Bytes&lt;/td>
&lt;td style="text-align:left">&lt;strong>188 Bytes&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Kapselung ist schnell&lt;/td>
&lt;td style="text-align:left">40 Jahre bewiesene Sicherheit. Riesiger öffentlicher Schlüssel. Für Umgebungen mit Hartkodierung.&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="kompromisse-verstehen">Kompromisse verstehen
&lt;/h3>&lt;p>In der Welt der PQC gibt es keinen einzigen magischen Algorithmus mit den Eigenschaften &amp;ldquo;kleine Größe, hohe Geschwindigkeit und perfekte mathematische Garantie&amp;rdquo;.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Internet-Standards (Kyber / Dilithium)&lt;/strong>: Bieten die beste Leistungsbalance und eignen sich am besten als Drop-In-Ersatz für heutiges RSA/ECC.&lt;/li>
&lt;li>&lt;strong>Ultimativer Konservativismus (SPHINCS+)&lt;/strong>: Wird gewählt, wenn man auf Kosten von Datengröße und Verarbeitungsgeschwindigkeit eine absolute Versicherung gegen zukünftige mathematische Durchbrüche haben möchte.&lt;/li>
&lt;li>&lt;strong>Für spezielle Umgebungen (FALCON / Classic McEliece)&lt;/strong>: Spezialwaffen, die je nach Umgebungsbeschränkungen ausgewählt werden, z. B. bei extrem geringer Bandbreite oder der Möglichkeit der Vorabverteilung.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="11-herausforderungen-bei-der-praktischen-anwendung-und-die-praktische-lösung-der-hybriden-kryptographie">11. Herausforderungen bei der praktischen Anwendung und die praktische Lösung der &amp;ldquo;hybriden Kryptographie&amp;rdquo;
&lt;/h2>&lt;p>Mit dem Abschluss der NIST-Standardisierung und der offiziellen Veröffentlichung der FIPS-Standards hat die PQC-Migration (&lt;strong>PQC Migration&lt;/strong>) der IT-Infrastruktur weltweit ernsthaft begonnen. Googles Chrome-Browser, Apples iMessage (PQ3-Protokoll) und Netzwerkanbieter wie Cloudflare haben die PQC-Unterstützung bereits in ihre Protokolle implementiert und mit dem praktischen Einsatz begonnen.&lt;/p>
&lt;p>Ein abrupter und vollständiger Wechsel zu neuen kryptographischen Algorithmen ist jedoch mit sehr hohen Risiken verbunden. Angenommen, ein brillanter Mathematiker entdeckt in einigen Jahren eine fatale Angriffsmethode auf Gitterkryptographien wie Kyber (einen mathematischen Fehler, der auch mit klassischen Computern gelöst werden könnte), dann würde das gesamte davon abhängige System in einem Augenblick schutzlos sein.&lt;/p>
&lt;p>Der realistische und empfohlene Ansatz, um dieses Unsicherheitsrisiko zu mindern, ist die &lt;strong>&amp;ldquo;hybride Kryptographie (Hybrid Cryptography)&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;p>In der hybriden Kryptographie werden sowohl bestehende klassische Kryptographien mit jahrelanger Erfolgsgeschichte (z.B. elliptische Kurven wie X25519) als auch neue PQC (z.B. Kyber768) gleichzeitig für den Schlüsselaustausch verwendet. Jeder Algorithmus generiert unabhängig voneinander symmetrische Schlüsselkomponenten. Schließlich werden beide Komponenten mithilfe einer sicheren Schlüsselableitungsfunktion (Key Derivation Function, KDF) gemischt, um das endgültige Master-Secret zu generieren.&lt;/p>
&lt;div class="mermaid">graph TD
A["Client"] -->|① Sendet öffentlichen Schlüssel von X25519 + öffentlichen Schlüssel von Kyber| B["Server"]
B -->|② Antwortet mit geteiltem Schlüssel von X25519 + gekapseltem Chiffretext von Kyber| A
A --> C{"Ableitung des Master-Secrets (KDF)"}
B --> C
C -->|Eingabe: (X25519 gemeinsamer Schlüssel) || (Kyber gemeinsamer Schlüssel)| D["Sicherer Kommunikationsschlüssel (AES-256 / ChaCha20)"]
D -->|"Widerstandsfähig gegen Quantenbedrohungen UND klassische Schwachstellen"| E["Sichere hybride verschlüsselte Kommunikation (TLS 1.3)"]&lt;/div>
&lt;p>Dadurch entsteht eine robuste zweischichtige Sicherheit: &amp;ldquo;Selbst wenn Quantencomputer realisiert und ECC geknackt werden, schützt Kyber die Kommunikation&amp;rdquo;, und umgekehrt &amp;ldquo;Sollte ein unbekannter mathematischer Fehler in Kyber gefunden werden, schützt ECC die Kommunikation&amp;rdquo;. Ein prominentes Beispiel ist der IETF-Standardisierungsentwurf &lt;strong>X25519MLKEM768 (früher X25519Kyber768)&lt;/strong>. Die heutige Kommunikation zwischen Webbrowsern und modernsten Servern nutzt genau diese hybride Methode.&lt;/p>
&lt;p>Darüber hinaus wird im Systemdesign das Konzept der &lt;strong>Crypto Agility (Kryptographische Agilität)&lt;/strong> zu einer zwingenden Anforderung für die zukünftige Systementwicklung. Dies bedeutet, eine Architektur aufzubauen, &amp;ldquo;die nicht übermäßig von einem bestimmten kryptographischen Algorithmus abhängt und schnell auf einen anderen Algorithmus umstellen kann (z.B. von Kyber auf McEliece, von Dilithium auf SPHINCS+), sollte ein Algorithmus scheitern&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="12-fazit-ein-neuer-horizont-der-kryptographie">12. Fazit: Ein neuer Horizont der Kryptographie
&lt;/h2>&lt;p>Die Menschheitstraum-Technologie des Quantencomputers ist ironischerweise zur größten Bedrohung geworden, um unsere lange als vertrauenswürdig erachteten mathematischen Verteidigungslinien wie &amp;ldquo;Primfaktorzerlegung&amp;rdquo; und das &amp;ldquo;diskrete Logarithmusproblem&amp;rdquo; zu durchbrechen. Dennoch haben Kryptographen auf der ganzen Welt nicht aufgegeben. Stattdessen haben sie komplexere und tiefgründigere mehrdimensionale mathematische Gebiete wie Gittertheorie, Hash-Funktions-Bäume und Fehlerkorrekturcodes erschlossen, um mit der Post-Quanten-Kryptographie (PQC) ein neues Bollwerk zu errichten.&lt;/p>
&lt;p>Der Abschluss der NIST-Standardisierung mit FIPS 203 (ML-KEM), FIPS 204 (ML-DSA) und FIPS 205 (SLH-DSA) ist nicht das Ziel. Es ist nur der erste Schritt einer epischen PQC-Migration, die noch Jahrzehnte dauern wird. Für Softwareentwickler und Systemarchitekten wird es die große technische Herausforderung der Zukunft sein, herauszufinden, wie man die &amp;ldquo;Zunahme der Schlüsselgrößen&amp;rdquo; und &amp;ldquo;Veränderungen bei den Berechnungskosten&amp;rdquo;, die diese neuen Algorithmen mit sich bringen, optimal an Netzwerkprotokolle und Systeme anpasst.&lt;/p>
&lt;p>Der Kampf zwischen Quantencomputern und Kryptographie ist ein spannendes Feld, in dem die menschliche Erforschung der Mathematik und die technologische Evolution am intensivsten aufeinandertreffen. Ich hoffe, dieser Artikel hat Ihnen ein tieferes Verständnis der wunderschönen mathematischen Theorie hinter der PQC sowie der erstaunlichen Mechanismen der einzelnen Algorithmen, die die Zukunft der Cybersicherheit prägen werden, vermittelt.&lt;/p>
&lt;hr>
&lt;p>&lt;em>References:&lt;/em>&lt;/p>
&lt;ul>
&lt;li>&lt;em>NIST Post-Quantum Cryptography Standardization Program&lt;/em>&lt;/li>
&lt;li>&lt;em>FIPS 203: Module-Lattice-Based Key-Encapsulation Mechanism Standard&lt;/em>&lt;/li>
&lt;li>&lt;em>FIPS 204: Module-Lattice-Based Digital Signature Standard&lt;/em>&lt;/li>
&lt;li>&lt;em>FIPS 205: Stateless Hash-Based Digital Signature Standard&lt;/em>&lt;/li>
&lt;/ul></description></item><item><title>Der Tag, an dem Quantencomputer praktisch werden: Der aktuelle Stand im Jahr 2026</title><link>http://kenji.blog/de/p/quantum-computing-2026-current-status/</link><pubDate>Fri, 11 Sep 2026 06:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/quantum-computing-2026-current-status/</guid><description>&lt;img src="http://kenji.blog/p/quantum-computing-2026-current-status/img/eyecatch.jpg" alt="Featured image of post Der Tag, an dem Quantencomputer praktisch werden: Der aktuelle Stand im Jahr 2026" />&lt;h2 id="1-einführung-wie-weit-sind-quantencomputer-im-jahr-2026-gekommen">1. Einführung: Wie weit sind Quantencomputer im Jahr 2026 gekommen?
&lt;/h2>&lt;p>Im Jahr 2026 hat das Quantencomputing einen entscheidenden Wandel vom einstigen „theoretischen Traum“ zur „ingenieurstechnischen Realität“ vollzogen. Da die Grenzen der bis vor wenigen Jahren noch vorherrschenden &lt;strong>NISQ (Noisy Intermediate-Scale Quantum)&lt;/strong>-Geräte deutlich wurden, haben Forschungseinrichtungen und Tech-Giganten weltweit das Ruder in Richtung der Realisierung des „fehlertoleranten Quantencomputings (FTQC: Fault-Tolerant Quantum Computing)“ herumgerissen.&lt;/p>
&lt;p>In diesem Artikel werden wir den aktuellen Stand von Quantencomputern eingehend beleuchten und dabei die neuesten Durchbrüche des Jahres 2026 miteinbeziehen. Insbesondere werden wir die Quantenfehlerkorrektur (Oberflächencode), den Unterschied zwischen physischen und logischen Qubits, Fortschritte beim topologischen Quantencomputing sowie die neuesten Entwicklungen bei supraleitenden und Ionenfallen-Ansätzen im Detail erläutern.&lt;/p>
&lt;hr>
&lt;h2 id="2-grundlagen-von-quantenzuständen-und-fidelität-fidelity">2. Grundlagen von Quantenzuständen und Fidelität (Fidelity)
&lt;/h2>&lt;p>Das Qubit, die grundlegende Einheit eines Quantencomputers, kann sich im Gegensatz zu einem klassischen Bit (0 oder 1) in einem Überlagerungszustand (Superposition) von 0 und 1 befinden. Der Zustand eines einzelnen Qubits wird als Vektor in einem Hilbertraum wie folgt dargestellt:&lt;/p>
$$
|\psi\rangle = \alpha|0\rangle + \beta|1\rangle
$$
&lt;p>Hierbei sind $\alpha$ und $\beta$ komplexe Wahrscheinlichkeitsamplituden, die die folgende Normalisierungsbedingung erfüllen:&lt;/p>
$$
|\alpha|^2 + |\beta|^2 = 1
$$
&lt;p>Eine extrem wichtige Kennzahl zur Messung der Leistung von Quantenberechnungen ist die &lt;strong>Fidelität (Fidelity)&lt;/strong>. Die Fidelität $F$ zwischen einem idealen Quantenzustand $|\psi\rangle$ und einer durch Rauschen degradierten, zu einem gemischten Zustand gewordenen tatsächlichen Dichtematrix $\rho$ ist wie folgt definiert:&lt;/p>
$$
F(\rho, |\psi\rangle) = \langle \psi | \rho | \psi \rangle
$$
&lt;p>Heutzutage, im Jahr 2026, hat die Fidelität von 2-Qubit-Gattern (z. B. CNOT- oder CZ-Gattern) bei supraleitenden Systemen stabil die Hürde von &lt;strong>99,99 %&lt;/strong> (die sogenannten „vier Neunen“) überschritten. Dies liegt deutlich über dem Schwellenwert für die Fehlerkorrektur mit Oberflächencodes (ca. 99 %) und ist einer der größten Durchbrüche auf dem Weg zur praktischen Anwendung.&lt;/p>
&lt;hr>
&lt;h2 id="3-die-grenzen-der-nisq-ära-und-der-paradigmenwechsel-zu-ftqc">3. Die Grenzen der NISQ-Ära und der Paradigmenwechsel zu FTQC
&lt;/h2>&lt;p>Von den späten 2010er bis in die frühen 2020er Jahre hinein war die Ära von NISQ (Noisy Intermediate-Scale Quantum), also von Geräten mit zehn bis hunderten von Qubits ohne Fehlerkorrektur. NISQ hatte jedoch klare Grenzen.&lt;/p>
&lt;p>Mit zunehmender Schaltkreistiefe (Depth) häufen sich Fehler exponentiell an, was es unmöglich macht, aussagekräftige Berechnungsergebnisse zu erzielen. Die Gesamterfolgswahrscheinlichkeit $P_{success}$ bei einer Schaltkreistiefe $D$ nimmt in Bezug auf die Fidelität eines einzelnen Gatters $f$ und die Anzahl der Gatter $N$ wie folgt ab:&lt;/p>
$$
P_{success} \approx f^N
$$
&lt;p>Wenn man 1000 Gatter mit $f = 0,99$ anwendet, ergibt sich $0,99^{1000} \approx 4,3 \times 10^{-5}$, und das Ergebnis geht fast vollständig in zufälligem Rauschen unter. Daher konzentrieren sich die Ressourcen im Jahr 2026 weniger auf die direkte Skalierung von NISQ-Algorithmen (wie VQE oder QAOA), sondern auf die Erzeugung von &lt;strong>logischen Qubits (Logical Qubits)&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h2 id="4-quantenfehlerkorrektur-und-logische-qubits-die-vorderste-front-des-oberflächencodes">4. Quantenfehlerkorrektur und logische Qubits: Die vorderste Front des Oberflächencodes
&lt;/h2>&lt;p>Die Quantenfehlerkorrektur (QEC: Quantum Error Correction) ist eine Technologie, bei der mehrere „physische Qubits“ kodiert werden, um ein einzelnes „logisches Qubit“ zu erzeugen und Fehler zu erkennen und zu korrigieren. Derzeit gilt der &lt;strong>Oberflächencode (Surface Code)&lt;/strong> als am vielversprechendsten.&lt;/p>
&lt;h3 id="41-struktur-des-oberflächencodes-surface-code">4.1 Struktur des Oberflächencodes (Surface Code)
&lt;/h3>&lt;p>Beim Oberflächencode werden die Qubits in einem zweidimensionalen Gitter angeordnet. Daten-Qubits (die die eigentlichen Informationen speichern) und Mess-Qubits (für die Syndrommessung) sind schachbrettartig angeordnet.&lt;/p>
&lt;div class="mermaid">graph TD
A["Daten-Qubit (D1)"] --- B["Mess-Qubit (M1)"]
B --- C["Daten-Qubit (D2)"]
C --- D["Mess-Qubit (M2)"]
D --- E["Daten-Qubit (D3)"]
B --- F["Daten-Qubit (D4)"]
D --- G["Daten-Qubit (D5)"]
style A fill:#e1f5fe,stroke:#039be5
style C fill:#e1f5fe,stroke:#039be5
style E fill:#e1f5fe,stroke:#039be5
style F fill:#e1f5fe,stroke:#039be5
style G fill:#e1f5fe,stroke:#039be5
style B fill:#fff3e0,stroke:#fb8c00
style D fill:#fff3e0,stroke:#fb8c00&lt;/div>
&lt;p>Mithilfe der Stabilisator-Operatoren $S_x$ und $S_z$ werden Bitflips (X-Fehler) und Phasenflips (Z-Fehler) kontinuierlich überwacht.&lt;/p>
$$
S_x = \prod_{i \in \text{star}} X_i, \quad S_z = \prod_{j \in \text{plaquette}} Z_j
$$
&lt;p>Ein entscheidender Fortschritt im Jahr 2026 war das vollständige Durchbrechen des „Break-Even-Punkts (Break-even point)“. Das bedeutet, dass das durch die Fehlerkorrektur beseitigte Rauschen größer wurde als das zusätzliche Rauschen, das durch die für die Fehlerkorrektur erforderlichen Schaltkreise entsteht, sodass die Lebensdauer von logischen Qubits die von physischen Qubits um viele Größenordnungen übertrifft.&lt;/p>
&lt;h3 id="42-der-zyklus-der-quantenfehlerkorrektur">4.2 Der Zyklus der Quantenfehlerkorrektur
&lt;/h3>&lt;p>Die Fehlerkorrektur fungiert als kontinuierliche Feedbackschleife.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant D as "Daten-Qubits"
participant M as "Ancilla-/Mess-Qubits"
participant C as "Klassischer Controller"
loop "Syndrom-Extraktionszyklus (ca. 1 Mikrosekunde)"
D->>M: "Verschränken (CNOT/CZ)"
M->>C: "Zustand messen (Syndrom)"
C->>C: "Syndrom decodieren (z. B. Minimum Weight Perfect Matching)"
C-->>D: "Pauli-Korrektur anwenden (falls erforderlich)"
end&lt;/div>
&lt;p>Mittlerweile hat sich die Technologie etabliert, diesen klassischen Dekodierungsprozess (Syndromanalyse) mit FPGAs oder dedizierten ASICs im Nanosekundenbereich durchzuführen, wodurch die Fehlerkorrektur in Echtzeit das Stadium der praktischen Anwendung erreicht hat.&lt;/p>
&lt;hr>
&lt;h2 id="5-die-evolution-der-hardware-architektur-ausgabe-2026">5. Die Evolution der Hardware-Architektur (Ausgabe 2026)
&lt;/h2>&lt;p>Die Quantenhardware im Jahr 2026 entwickelt sich hauptsächlich entlang dreier Achsen: „Supraleitender Ansatz“, „Ionenfallen-Ansatz“ und „Topologischer Ansatz“.&lt;/p>
&lt;h3 id="51-integration-von-supraleitenden-qubits">5.1 Integration von supraleitenden Qubits
&lt;/h3>&lt;p>Der supraleitende Ansatz ist ein Bereich, der von IBM und Google angeführt wird, wobei Transmon-Qubits (Transmon) mit Josephson-Kontakten vorherrschen. Im Jahr 2026 wurden Mega-Chips realisiert, die Tausende bis Zehntausende von physischen Qubits auf einem einzigen Chip integrieren.&lt;/p>
&lt;p>Besonders hervorzuheben ist die Etablierung von &lt;strong>quantenmechanischen Verbindungen zwischen Modulen (Quantum Interconnects)&lt;/strong>. Die Quantenteleportation zwischen Chips mithilfe von Mikrowellenphotonen wurde auf kommerziellem Niveau implementiert, wodurch die Größenbeschränkungen eines einzelnen Mischkryostaten (Verdünnungskühlschranks) umgangen werden können.&lt;/p>
&lt;h3 id="52-zweidimensionale-skalierung-von-ionenfallen-und-optische-interconnects">5.2 Zweidimensionale Skalierung von Ionenfallen und optische Interconnects
&lt;/h3>&lt;p>Beim Ionenfallen-Ansatz (vorangetrieben unter anderem von Quantinuum und IonQ) werden die internen Energiezustände von im Vakuum schwebenden Ionen als Qubits genutzt. Im Vergleich zum supraleitenden Ansatz haben sie den Vorteil extrem langer T1/T2-Kohärenzzeiten und ermöglichen eine All-to-All-Konnektivität (All-to-All Connectivity).&lt;/p>
&lt;p>Der Durchbruch des Jahres 2026 ist die zweidimensionale Ausrichtung der QCCD-Architektur (Quantum Charge Coupled Device) und die Hochgeschwindigkeits-Verschränkungserzeugung zwischen mehreren Fallen mithilfe von photonischen Interconnects. Dadurch wurden die Schwächen der Ionenfallen, nämlich „langsame Gatter-Geschwindigkeit“ und „mangelnde Skalierbarkeit“, dramatisch verbessert.&lt;/p>
&lt;h3 id="53-topologisches-quantencomputing-kontrolle-von-anyonen">5.3 Topologisches Quantencomputing: Kontrolle von Anyonen
&lt;/h3>&lt;p>Das &lt;strong>topologische Quantencomputing&lt;/strong>, das lange Zeit als rein theoretisch galt, hat im Jahr 2026 endlich die Phase der experimentellen Demonstration erreicht. Dieser Ansatz, der unter anderem von Microsoft vorangetrieben wird, nutzt nicht-abelsche Anyonen (Non-Abelian Anyons), die als „Majorana-Nullmoden (Majorana Zero Modes)“ bezeichnet werden.&lt;/p>
&lt;p>Quantengatter werden durch eine Operation namens „Braiding (Flechten)“ ausgeführt, bei der die Positionen der Anyon-Teilchen vertauscht werden.&lt;/p>
$$
|\psi_{final}\rangle = B_{ij} |\psi_{initial}\rangle
$$
&lt;p>Hierbei ist $B_{ij}$ der Braiding-Operator. Da beim topologischen Ansatz die Speicherung von Informationen nicht vom lokalen Zustand der Teilchen abhängt, sondern von der Topologie der gesamten „Knoten“, ist er von Natur aus widerstandsfähig gegen Umgebungsrauschen (Fehlertoleranz auf Hardware-Ebene). Im Jahr 2026 wurde weltweit zum ersten Mal die Erzeugung topologischer logischer Qubits mit hoher Fidelität bestätigt, was große Aufmerksamkeit als starke Abkürzung zu FTQC erregte.&lt;/p>
&lt;hr>
&lt;h2 id="6-roadmap-und-ausblick-auf-die-praktische-anwendung">6. Roadmap und Ausblick auf die praktische Anwendung
&lt;/h2>&lt;p>Damit Quantencomputer ihre &lt;strong>Quantenüberlegenheit (Quantum Advantage)&lt;/strong>, mit der sie klassische Computer (Supercomputer) in Bereichen wie „chemische Berechnungen“, „Materialwissenschaften“ und „Finanzmodellierung“ übertreffen, wirklich entfalten können, sind Tausende von logischen Qubits erforderlich.&lt;/p>
&lt;div class="mermaid">gantt
title "Quantencomputing-Roadmap (Überarbeitet 2026)"
dateFormat YYYY
axisFormat %Y
section "NISQ-Ära"
"Verrauschte Qubits (&lt;1000)" :done, 2018, 2024
section "Frühes FTQC"
"Demonstration des Break-Even-Punkts" :done, 2024, 2026
"Hunderte von logischen Qubits" :active, 2026, 2028
section "Vollwertiges FTQC"
"1000+ logische Qubits (Komm. Anwendung)" : 2028, 2030
"Universeller fehlertoleranter Quantencomputer" : 2030, 2035&lt;/div>
&lt;h3 id="61-aktuelle-herausforderungen-und-die-zukunft">6.1 Aktuelle Herausforderungen und die Zukunft
&lt;/h3>&lt;p>Die größte Herausforderung im Jahr 2026 ist die Kühlkapazität der riesigen Kryostate (Verdünnungskühlschränke) zur Aufrechterhaltung der extrem niedrigen Temperaturen sowie die Verkabelung (I/O-Flaschenhals), die die Steuergeräte bei Raumtemperatur mit den Quantenchips bei tiefen Temperaturen verbindet. Um dem zu begegnen, schreitet die Entwicklung von CMOS-Controller-Chips (Cryo-CMOS), die in kryogenen Umgebungen funktionieren, rasant voran.&lt;/p>
&lt;h3 id="fazit">Fazit
&lt;/h3>&lt;p>Das Jahr 2026 wird in die Geschichte der Quantencomputer als „das erste Jahr der Skalierung logischer Qubits“ eingehen. Dank der Demonstration von Fehlerkorrekturalgorithmen, der Modularisierung der Hardware und der rasanten Fortschritte beim topologischen Ansatz ist der „Tag der praktischen Anwendung“ keine ferne Zukunft mehr, sondern kann als konkreter Meilenstein für die nächsten Jahre angesehen werden. Für Entwickler von Quantenalgorithmen und Unternehmen ist jetzt genau der richtige Zeitpunkt, um ernsthaft in quantennative Problemlösungen zu investieren.&lt;/p>
&lt;hr>
&lt;p>&lt;em>Dieser Artikel basiert auf den neuesten Forschungsarbeiten und Branchentrends im Bereich des Quantencomputings mit Stand 2026.&lt;/em>&lt;/p></description></item></channel></rss>