<?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/en/categories/mathematics/</link><description>Recent content in Mathematics on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 22:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/en/categories/mathematics/index.xml" rel="self" type="application/rss+xml"/><item><title>Fundamentals and Implementation of Cryptography Using Fermat's Little Theorem</title><link>http://kenji.blog/en/p/fermats-little-theorem-cryptography-implementation/</link><pubDate>Fri, 11 Sep 2026 22:00:00 +0900</pubDate><guid>http://kenji.blog/en/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 Fundamentals and Implementation of Cryptography Using Fermat's Little Theorem" />&lt;h2 id="1-introduction-the-mystery-of-mathematics-supporting-modern-cryptography">1. Introduction: The Mystery of Mathematics Supporting Modern Cryptography
&lt;/h2>&lt;p>In modern digital society, especially in communication over the Internet, &amp;ldquo;encryption&amp;rdquo; has become an indispensable foundational technology. The reason we can securely browse websites via HTTPS, perform financial transactions through online banking, and exchange private messages on messaging apps is because cryptographic protocols backed by highly advanced mathematical theories are working behind the scenes. Among them, &amp;ldquo;Public-Key Cryptography&amp;rdquo; plays a particularly important role, and its prime representative is &lt;strong>RSA cryptography&lt;/strong>.&lt;/p>
&lt;p>The security and correctness of many cryptographic algorithms, including RSA cryptography, depend heavily on a very beautiful and powerful theorem discovered by the 17th-century French mathematician Pierre de Fermat. That is &lt;strong>Fermat&amp;rsquo;s Little Theorem&lt;/strong>. Furthermore, Leonhard Euler&amp;rsquo;s theorem, which generalizes this, also plays a decisive role in cryptographic theory.&lt;/p>
&lt;p>In this article, we will thoroughly explain from the basics how the pure mathematical discovery of Fermat&amp;rsquo;s Little Theorem is applied to modern practical cryptographic technologies, especially &amp;ldquo;primality testing&amp;rdquo; and &amp;ldquo;RSA cryptography&amp;rdquo;. This will be a highly detailed technical guide covering mathematical proofs, encryption and decryption mechanisms, and specific algorithm implementations using C++ and Python.&lt;/p>
&lt;hr>
&lt;h2 id="2-fundamentals-of-congruences-and-modular-arithmetic">2. Fundamentals of Congruences and Modular Arithmetic
&lt;/h2>&lt;p>To understand Fermat&amp;rsquo;s Little Theorem, you first need to become familiar with the mathematical concept of &amp;ldquo;modular arithmetic (congruence)&amp;rdquo;. Modular arithmetic is a calculation system that focuses on the &amp;ldquo;remainder&amp;rdquo; when dividing by a certain fixed number (called the modulus). Because it&amp;rsquo;s a calculation like a clock face (which cycles every 12 hours), it is also called &amp;ldquo;clock mathematics&amp;rdquo;.&lt;/p>
&lt;p>When the remainders of dividing integers $a$ and $b$ by a positive integer $n$ are equal, it is described mathematically as follows:&lt;/p>
$$
a \equiv b \pmod n
$$
&lt;p>This is read as &amp;ldquo;$a$ and $b$ are congruent modulo $n$&amp;rdquo;. For example, the remainder of 17 divided by 5 is 2, and the remainder of 12 divided by 5 is also 2. Therefore, it can be written as:&lt;/p>
$$
17 \equiv 12 \pmod 5 \equiv 2 \pmod 5
$$
&lt;p>In modular arithmetic, normal basic arithmetic operations (addition, subtraction, multiplication) apply as they are.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Addition&lt;/strong>: If $a \equiv b \pmod n$ and $c \equiv d \pmod n$, then $a + c \equiv b + d \pmod n$&lt;/li>
&lt;li>&lt;strong>Subtraction&lt;/strong>: If $a \equiv b \pmod n$ and $c \equiv d \pmod n$, then $a - c \equiv b - d \pmod n$&lt;/li>
&lt;li>&lt;strong>Multiplication&lt;/strong>: If $a \equiv b \pmod n$ and $c \equiv d \pmod n$, then $a \times c \equiv b \times d \pmod n$&lt;/li>
&lt;li>&lt;strong>Exponentiation&lt;/strong>: If $a \equiv b \pmod n$, then for any natural number $k$, $a^k \equiv b^k \pmod n$&lt;/li>
&lt;/ol>
&lt;p>However, care must be taken with &lt;strong>division&lt;/strong>. In general, just because $a \times c \equiv b \times c \pmod n$, you cannot divide both sides by $c$ to get $a \equiv b \pmod n$. This only holds true when $c$ and $n$ are coprime (their greatest common divisor is 1). This concept of &amp;ldquo;modular inverse&amp;rdquo; becomes extremely important in the key generation of RSA cryptography discussed later.&lt;/p>
&lt;hr>
&lt;h2 id="3-mathematical-background-and-proof-of-fermats-little-theorem">3. Mathematical Background and Proof of Fermat&amp;rsquo;s Little Theorem
&lt;/h2>&lt;p>Having grasped the basics of modular arithmetic, let&amp;rsquo;s look at the main subject, Fermat&amp;rsquo;s Little Theorem.&lt;/p>
&lt;h3 id="31-definition-of-the-theorem">3.1 Definition of the Theorem
&lt;/h3>&lt;p>Fermat&amp;rsquo;s Little Theorem is formulated as follows:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Fermat&amp;rsquo;s Little Theorem&lt;/strong>
Let $p$ be a prime number, and let $a$ be any integer that is not a multiple of $p$ (i.e., $a$ and $p$ are coprime). Then, the following congruence holds:
&lt;/p>
$$ a^{p-1} \equiv 1 \pmod p $$
&lt;/blockquote>
&lt;p>It is also common to express it in a form that holds for all integers $a$ by removing the condition that &amp;ldquo;$a$ is not a multiple of $p$&amp;rdquo;. In that case, multiplying both sides by $a$ gives:&lt;/p>
$$
a^p \equiv a \pmod p
$$
&lt;h3 id="32-verification-with-concrete-examples">3.2 Verification with Concrete Examples
&lt;/h3>&lt;p>Let&amp;rsquo;s check if the theorem really holds using specific numbers.
Let the prime number $p = 5$. $p-1 = 4$. We choose an integer $a$ that is not a multiple of $p$.&lt;/p>
&lt;ul>
&lt;li>For $a = 2$: $2^{5-1} = 2^4 = 16$. $16 \div 5 = 3$ remainder $1$. Thus $16 \equiv 1 \pmod 5$. (Holds)&lt;/li>
&lt;li>For $a = 3$: $3^{5-1} = 3^4 = 81$. $81 \div 5 = 16$ remainder $1$. Thus $81 \equiv 1 \pmod 5$. (Holds)&lt;/li>
&lt;li>For $a = 4$: $4^{5-1} = 4^4 = 256$. $256 \div 5 = 51$ remainder $1$. Thus $256 \equiv 1 \pmod 5$. (Holds)&lt;/li>
&lt;/ul>
&lt;p>In this way, no matter what $a$ you choose (as long as it&amp;rsquo;s not a multiple of 5), raising it to the 4th power and dividing by 5 will always yield a remainder of 1. It seems like magic, but this comes from the beautiful properties that prime numbers possess.&lt;/p>
&lt;h3 id="33-mathematical-proof-of-the-theorem">3.3 Mathematical Proof of the Theorem
&lt;/h3>&lt;p>Why does this happen? Here we introduce an elegant proof using the set of residue classes.&lt;/p>
&lt;p>Consider the set $S = \{1, 2, 3, \dots, p-1\}$. These are representatives of integers whose remainders when divided by $p$ are from $1$ to $p-1$.
Here, consider a new set $T$ obtained by multiplying each element by an integer $a$ that is coprime to $p$:
&lt;/p>
$$ T = \{1a, 2a, 3a, \dots, (p-1)a\} $$
&lt;p>Consider the remainder of each element of this set $T$ when divided by $p$. Surprisingly, these remainders, although their order might change, perfectly match the set of elements in the original set $S$.
Because:&lt;/p>
&lt;ol>
&lt;li>No element of $T$ can be a multiple of $p$ (since neither $a$ nor the original elements are multiples of $p$).&lt;/li>
&lt;li>There are no two distinct elements in $T$ that are congruent modulo $p$. If $ia \equiv ja \pmod p$ ($i \neq j$), since $a$ and $p$ are coprime, we can divide by $a$ to get $i \equiv j \pmod p$, which is a contradiction.&lt;/li>
&lt;/ol>
&lt;p>Therefore, the product of all elements of $S$ and the product of all elements of $T$ are congruent 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>Simplifying the left side, since there are $p-1$ copies of $a$:&lt;/p>
$$
a^{p-1} \cdot (p-1)! \equiv (p-1)! \pmod p
$$
&lt;p>Since $(p-1)!$ is coprime to $p$, we can divide both sides by $(p-1)!$, which finally leads to the theorem:&lt;/p>
$$
a^{p-1} \equiv 1 \pmod p
$$
&lt;p>This is the proof of Fermat&amp;rsquo;s Little Theorem.&lt;/p>
&lt;hr>
&lt;h2 id="4-eulers-totient-function-and-eulers-theorem">4. Euler&amp;rsquo;s Totient Function and Euler&amp;rsquo;s Theorem
&lt;/h2>&lt;p>Fermat&amp;rsquo;s Little Theorem is a theorem concerning &amp;ldquo;prime numbers $p$&amp;rdquo;, but it was Leonhard Euler who generalized this to &amp;ldquo;any positive integer $n$&amp;rdquo;. This extension is essential for understanding RSA cryptography.&lt;/p>
&lt;h3 id="41-eulers-totient-function-phin">4.1 Euler&amp;rsquo;s Totient Function $\phi(n)$
&lt;/h3>&lt;p>Euler&amp;rsquo;s totient function (or Euler&amp;rsquo;s $\phi$ function) $\phi(n)$ is a function that represents &amp;ldquo;the number of integers from $1$ to $n$ that are coprime to $n$&amp;rdquo;.&lt;/p>
&lt;ul>
&lt;li>For a prime number $p$, all integers from $1$ to $p-1$ are coprime to $p$, so $\phi(p) = p - 1$.&lt;/li>
&lt;li>For two distinct prime numbers $p, q$, their product $n = p \times q$ has a $\phi(n)$ given by a very simple formula:
$$ \phi(p \times q) = \phi(p) \times \phi(q) = (p - 1)(q - 1) $$&lt;/li>
&lt;/ul>
&lt;p>This property is the fundamental logic in RSA key generation.&lt;/p>
&lt;h3 id="42-eulers-theorem">4.2 Euler&amp;rsquo;s Theorem
&lt;/h3>&lt;p>Euler generalized Fermat&amp;rsquo;s Little Theorem as follows:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Euler&amp;rsquo;s Theorem&lt;/strong>
For a positive integer $n$ and an integer $a$ coprime to it, the following holds:
&lt;/p>
$$ a^{\phi(n)} \equiv 1 \pmod n $$
&lt;/blockquote>
&lt;p>If $n$ is a prime number $p$, then $\phi(p) = p - 1$, so this becomes Fermat&amp;rsquo;s Little Theorem itself ($a^{p-1} \equiv 1 \pmod p$). In other words, Fermat&amp;rsquo;s Little Theorem is merely a special case of Euler&amp;rsquo;s Theorem.&lt;/p>
&lt;hr>
&lt;h2 id="5-finding-giant-prime-numbers-fermat-primality-test">5. Finding Giant Prime Numbers: Fermat Primality Test
&lt;/h2>&lt;p>In cryptographic technologies (such as RSA cryptography and Diffie-Hellman key exchange), it is necessary to find &amp;ldquo;giant prime numbers&amp;rdquo; spanning hundreds of digits at high speed. However, to test whether a giant number $N$ is prime, checking if it is divisible by every number from $2$ to $\sqrt{N}$ (trial division) would take as long as the lifespan of the universe.&lt;/p>
&lt;p>This is where the &lt;strong>Fermat Primality Test&lt;/strong> comes in, a &amp;ldquo;probabilistic primality test&amp;rdquo; that takes advantage of Fermat&amp;rsquo;s Little Theorem.&lt;/p>
&lt;h3 id="51-what-is-a-probabilistic-primality-test">5.1 What is a Probabilistic Primality Test?
&lt;/h3>&lt;p>According to Fermat&amp;rsquo;s Little Theorem, if $p$ is prime, then for any $a$ ($1 &lt; a &lt; p$), $a^{p-1} \equiv 1 \pmod p$ must hold.
Taking the contrapositive, we can say that &amp;ldquo;if $a^{p-1} \not\equiv 1 \pmod p$ for some $a$, then $p$ is &lt;strong>absolutely not a prime number (it is a composite number)&lt;/strong>&amp;rdquo;.&lt;/p>
&lt;p>Therefore, if we want to determine whether $N$ is prime, we randomly choose several $a$&amp;rsquo;s, calculate $a^{N-1} \pmod N$, and check if it equals $1$. If an answer other than $1$ appears even once, $N$ is definitively a composite number. If it equals $1$ no matter how many times we try, we can determine with high probability that $N$ is &amp;ldquo;probably prime&amp;rdquo;.&lt;/p>
&lt;h3 id="52-algorithm-explanation-and-flowchart">5.2 Algorithm Explanation and Flowchart
&lt;/h3>&lt;p>The algorithm for the Fermat primality test is as follows:&lt;/p>
&lt;div class="mermaid">flowchart TD
Start["Start"] --> Input["Input number to test p and number of tests k"]
Input --> LoopStart["Loop for i = 0 to k-1"]
LoopStart --> Condition{"i &lt; k ?"}
Condition -- "Yes" --> RandomA["Select random integer a in range 1 &lt; a &lt; p-1"]
RandomA --> Calc["Calculate modular exponentiation a^(p-1) mod p"]
Calc --> CheckPrime{"Is result 1 ?"}
CheckPrime -- "No" --> ReturnComposite["p is a composite number (definite)"]
CheckPrime -- "Yes" --> Increment["Increment i"]
Increment --> Condition
Condition -- "No" --> ReturnPrime["p is probably prime (probabilistic)"]
ReturnComposite --> End["End"]
ReturnPrime --> End&lt;/div>
&lt;h3 id="53-the-pitfall-of-carmichael-numbers-pseudoprimes">5.3 The Pitfall of Carmichael Numbers (Pseudoprimes)
&lt;/h3>&lt;p>While the Fermat test is very fast, it has a significant flaw. There are devilish numbers that are composite numbers but still satisfy $a^{N-1} \equiv 1 \pmod N$ for all $a$. These are called &lt;strong>Carmichael numbers&lt;/strong>. The smallest Carmichael number is $561$ ($3 \times 11 \times 17$).&lt;/p>
&lt;p>Because Carmichael numbers exist, a pure Fermat test alone cannot provide absolute primality testing. Therefore, in actual cryptographic systems (such as OpenSSL), the &lt;strong>Miller-Rabin primality test&lt;/strong>, an improved version of the Fermat test, is used as the standard. The Miller-Rabin test can detect Carmichael numbers, effectively reducing the probability of misjudgment to zero.&lt;/p>
&lt;h3 id="54-fast-modular-exponentiation-exponentiation-by-squaring">5.4 Fast Modular Exponentiation (Exponentiation by Squaring)
&lt;/h3>&lt;p>In the primality testing algorithm, we need to calculate $a^{N-1} \pmod N$, but when $N$ is huge, $a^{N-1}$ becomes an astronomically large number that cannot fit into a computer&amp;rsquo;s memory.
This is solved by &lt;strong>Exponentiation by Squaring&lt;/strong> or modular exponentiation. By taking the modulo ($mod N$) at each step of the calculation, the value is always kept smaller than $N$, allowing it to be calculated very quickly (with a computational complexity of $O(\log N)$).&lt;/p>
&lt;hr>
&lt;h2 id="6-implementation-of-primality-testing-and-modular-exponentiation">6. Implementation of Primality Testing and Modular Exponentiation
&lt;/h2>&lt;p>Now, let&amp;rsquo;s implement the Fermat primality test and exponentiation by squaring in C++ and Python.&lt;/p>
&lt;h3 id="61-implementation-in-c">6.1 Implementation in C++
&lt;/h3>&lt;p>In C++, standard integer types are prone to overflow, so handling giant numbers requires a multiple-precision integer library (like GMP), but here we show an implementation within the range of 64-bit integers (&lt;code>unsigned long long&lt;/code>) to understand the algorithm.&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">// Fast modular exponentiation (a^b mod m) - Exponentiation by squaring
&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">// If the lowest bit of b is 1, multiply result by 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 extension to prevent overflow
&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">// Square a
&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">// Right shift b (halve it)
&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 primality test
&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">// If a^(p-1) mod p is not 1, it&amp;#39;s composite
&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">// Probably prime
&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">// A known prime
&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-implementation-in-python">6.2 Implementation in Python
&lt;/h3>&lt;p>Python&amp;rsquo;s standard integer type supports arbitrary precision integers, so there&amp;rsquo;s no need to worry about overflow. Furthermore, Python&amp;rsquo;s built-in function &lt;code>pow(a, b, m)&lt;/code> internally uses exponentiation by squaring, so it&amp;rsquo;s very fast.&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"> Probabilistic primality test using Fermat&amp;#39;s primality test
&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"># Choose a random number a between 2 and 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"># Calculate a^(p-1) mod p. Built-in pow is fast.&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"># Definitely composite&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"># Probably prime&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"> is probably prime.&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"> is composite.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="7-application-to-rsa-cryptography-where-fermat-and-euler-bear-fruit">7. Application to RSA Cryptography: Where Fermat and Euler Bear Fruit
&lt;/h2>&lt;p>The greatest application of Fermat&amp;rsquo;s Little Theorem (and Euler&amp;rsquo;s Theorem) is &lt;strong>RSA cryptography&lt;/strong>, developed in 1977 by Rivest, Shamir, and Adleman.
RSA cryptography is an epoch-making system called &amp;ldquo;public-key cryptography&amp;rdquo;, realizing a mechanism where the key for encryption (public key) is published to the whole world, while the key for decryption (private key) is known only to the receiver themselves.&lt;/p>
&lt;p>This asymmetry is based on the computational security that &amp;ldquo;factorizing a giant composite number into its prime factors is extremely difficult.&amp;rdquo;&lt;/p>
&lt;h3 id="71-mechanism-of-rsa-cryptography-key-generation-encryption-decryption">7.1 Mechanism of RSA Cryptography (Key Generation, Encryption, Decryption)
&lt;/h3>&lt;p>Let&amp;rsquo;s check the overall communication flow of RSA cryptography with a Mermaid sequence diagram.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant Alice["Alice (Receiver)"]
participant Bob["Bob (Sender)"]
Alice->>Alice: "Generate large primes p, q"
Alice->>Alice: "Calculate N = p * q, φ(N) = (p-1)(q-1)"
Alice->>Alice: "Calculate public key e and private key d (e*d ≡ 1 mod φ(N))"
Alice->>Bob: "Send public key (N, e)"
Note over Bob: "Prepare plaintext M (M &lt; N)"
Bob->>Bob: "Calculate ciphertext C = M^e mod N"
Bob->>Alice: "Send ciphertext C"
Alice->>Alice: "Calculate plaintext M = C^d mod N to decrypt"&lt;/div>
&lt;p>The mathematical detail steps are explained below.&lt;/p>
&lt;h4 id="step-1-key-generation-task-of-receiver-alice">Step 1: Key Generation (Task of Receiver Alice)
&lt;/h4>&lt;ol>
&lt;li>Randomly generate two giant prime numbers $p$ and $q$ (the primality test mentioned above is used here).&lt;/li>
&lt;li>Calculate their product $N = p \times q$. This $N$ is made public.&lt;/li>
&lt;li>Using Euler&amp;rsquo;s totient function, calculate $\phi(N) = (p-1)(q-1)$.&lt;/li>
&lt;li>Choose an integer $e$ (public exponent) that is coprime to $\phi(N)$ (often $e = 65537$ is used).&lt;/li>
&lt;li>Calculate the modular inverse $d$ (private exponent) of $e$. In other words, find $d$ that satisfies:
$$ e \cdot d \equiv 1 \pmod{\phi(N)} $$
The &lt;strong>extended Euclidean algorithm&lt;/strong> is used for this calculation.&lt;/li>
&lt;/ol>
&lt;p>Now, the &lt;strong>public key is $(N, e)$&lt;/strong>, and the &lt;strong>private key is $(N, d)$&lt;/strong>. ($p, q, \phi(N)$ are immediately discarded or strictly hidden).&lt;/p>
&lt;h4 id="step-2-encryption-task-of-sender-bob">Step 2: Encryption (Task of Sender Bob)
&lt;/h4>&lt;p>Suppose Bob wants to send a message $M$ to Alice ($M$ is a numerically converted character, and $0 \le M &lt; N$).
Bob uses Alice&amp;rsquo;s public key $(N, e)$ to perform the following calculation to create ciphertext $C$.&lt;/p>
$$
C \equiv M^e \pmod N
$$
&lt;p>He sends this $C$ to Alice over the network.&lt;/p>
&lt;h4 id="step-3-decryption-task-of-receiver-alice">Step 3: Decryption (Task of Receiver Alice)
&lt;/h4>&lt;p>Alice, receiving the ciphertext $C$, performs the following calculation using the private key $d$ that only she knows.&lt;/p>
$$
M' \equiv C^d \pmod N
$$
&lt;p>Surprisingly, this calculation result $M'$ perfectly matches the original message $M$.&lt;/p>
&lt;h3 id="72-why-can-it-be-decrypted-mathematical-proof">7.2 Why can it be decrypted? (Mathematical Proof)
&lt;/h3>&lt;p>Here, Fermat&amp;rsquo;s Little Theorem (Euler&amp;rsquo;s Theorem) shows its true worth. Why does $C^d \pmod N$ return to $M$?&lt;/p>
&lt;p>Let&amp;rsquo;s expand the decryption equation.
Since $C \equiv M^e \pmod N$,
&lt;/p>
$$ C^d \equiv (M^e)^d \equiv M^{ed} \pmod N $$
&lt;p>In the key generation step, we chose $d$ such that $e \cdot d \equiv 1 \pmod{\phi(N)}$. This means there exists an integer $k$ such that it can be written as:
&lt;/p>
$$ e \cdot d = 1 + k \cdot \phi(N) $$
&lt;p>Substitute this into the above equation:
&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>Here, &lt;strong>Euler&amp;rsquo;s Theorem&lt;/strong> ($M^{\phi(N)} \equiv 1 \pmod N$) comes into play. (*Strictly speaking, $M$ and $N$ need to be coprime, but in RSA, the probability that $M$ and $N$ are not coprime is astronomically low, and using the Chinese Remainder Theorem, it can be proven to hold even if they are not coprime).&lt;/p>
&lt;p>Applying Euler&amp;rsquo;s Theorem, since $M^{\phi(N)} \equiv 1$:
&lt;/p>
$$ M \cdot (1)^k \equiv M \pmod N $$
&lt;p>$M$ is beautifully restored! The properties of numbers discovered hundreds of years ago by Fermat and Euler perfectly guarantee the confidentiality of modern digital communication.&lt;/p>
&lt;hr>
&lt;h2 id="8-toy-implementation-of-rsa-cryptography-python">8. Toy Implementation of RSA Cryptography (Python)
&lt;/h2>&lt;p>It&amp;rsquo;s hard to get a real feel from theory alone, so let&amp;rsquo;s actually implement the key generation, encryption, and decryption process of RSA cryptography using Python. This is a &amp;ldquo;toy implementation&amp;rdquo; for educational purposes, but the math used is exactly the same as the real thing.&lt;/p>
&lt;p>The &amp;ldquo;extended Euclidean algorithm&amp;rdquo; for finding the modular inverse $d$ is also included in the implementation.&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"># Find the greatest common divisor&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"># Extended Euclidean algorithm (Find x, y for ax + by = gcd(a,b))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Used to find d for e*d ≡ 1 (mod φ(N))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">extended_gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">extended_gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">g&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">//&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">mod_inverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">extended_gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">g&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">Exception&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Inverse does not exist&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"># Prime number generation function (simplified version: generates small primes)&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"># Simplified check instead of the Fermat test mentioned above&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 key generation&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"># Ensure p and q are not the same&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">q&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">q&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">generate_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">q&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">phi&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">q&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># e is often a prime like 65537, but here we choose it randomly&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"># Calculation of private key 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"># Public key (e, n), Private key (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"># Calculate 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"># Calculate cipher^d mod n and convert back to characters&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"># Example execution&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 Cryptography Toy Implementation ---&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"># Use 12-bit primes&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;Public key (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;Private key (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">Original message: &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"># Encryption&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;Ciphertext: &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"># Decryption&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;Decrypted message: &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>When you run this code, you can see how an array of characters is converted into an unfamiliar array of numbers (ciphertext), which is then beautifully restored to the original string by the private key.&lt;/p>
&lt;hr>
&lt;h2 id="9-conclusion-the-intersection-of-mathematical-beauty-and-practicality">9. Conclusion: The Intersection of Mathematical Beauty and Practicality
&lt;/h2>&lt;p>In the 17th century when Pierre de Fermat discovered this &amp;ldquo;Little Theorem&amp;rdquo;, no one thought it would be of any use. Fermat himself studied number theory out of pure mathematical curiosity.&lt;/p>
&lt;p>However, about 300 years later in the 1970s, at the dawn of computer networks, Fermat&amp;rsquo;s theorem made a dramatic comeback as an indispensable cryptographic technology for establishing secure communication protocols. Primality testing technology based on Fermat&amp;rsquo;s Little Theorem and RSA cryptography based on Euler&amp;rsquo;s theorem literally support modern Internet infrastructure.&lt;/p>
&lt;p>The LINE messages we casually send every day, the shopping on Amazon, all dance on this simple and beautiful formula $a^{p-1} \equiv 1 \pmod p$. No matter how abstract mathematics may be, Fermat&amp;rsquo;s Little Theorem teaches us that the time will definitely come when it will be useful to humanity.&lt;/p>
&lt;p>When studying programming or cryptographic theory, understanding the mathematical structures at their foundation will become a great weapon for deeply understanding the behavior of libraries provided as black boxes and designing more secure systems.&lt;/p></description></item><item><title>Mathematical Intuition of Lattice-based Cryptography</title><link>http://kenji.blog/en/p/lattice-based-cryptography-math-intuition/</link><pubDate>Fri, 11 Sep 2026 21:00:00 +0900</pubDate><guid>http://kenji.blog/en/p/lattice-based-cryptography-math-intuition/</guid><description>&lt;img src="http://kenji.blog/p/lattice-based-cryptography-math-intuition/img/eyecatch.jpg" alt="Featured image of post Mathematical Intuition of Lattice-based Cryptography" />&lt;h1 id="1-introduction-the-dawn-of-post-quantum-cryptography-pqc-and-the-rise-of-lattice-based-cryptography">1. Introduction: The Dawn of Post-Quantum Cryptography (PQC) and the Rise of Lattice-based Cryptography
&lt;/h1>&lt;p>The digital infrastructure of modern society is supported by public-key cryptography technologies such as RSA cryptography and Elliptic Curve Cryptography (ECC). These cryptographic schemes base their security on the mathematical difficulty of problems like the &amp;ldquo;prime factorization problem&amp;rdquo; and the &amp;ldquo;discrete logarithm problem,&amp;rdquo; which are believed to be inefficient (requiring exponential time) to solve with conventional classical computers.&lt;/p>
&lt;p>However, &amp;ldquo;Shor&amp;rsquo;s algorithm,&amp;rdquo; published by Peter Shor in 1994, sent shockwaves through the cryptographic world. This algorithm mathematically proved that once a large-scale quantum computer is realized, it would be able to solve the prime factorization problem and the discrete logarithm problem in polynomial time. This means that the widely used public-key cryptography of today will become completely decipherable in the future.&lt;/p>
&lt;p>To counter such a &amp;ldquo;Quantum Threat,&amp;rdquo; research into new cryptographic schemes that are difficult to break even with quantum computers became an urgent task. This field is called &amp;ldquo;Post-Quantum Cryptography (PQC)&amp;rdquo; or &amp;ldquo;quantum-resistant cryptography.&amp;rdquo;&lt;/p>
&lt;p>There are several strong candidates for PQC. Examples include hash-based cryptography, code-based cryptography, multivariate polynomial cryptography, and isogeny-based cryptography. Among them, &amp;ldquo;Lattice-based cryptography&amp;rdquo; is currently attracting the most attention and is at the center of the PQC standardization process by NIST (National Institute of Standards and Technology). Compared to other methods, lattice-based cryptography has extremely fast encryption and decryption processing speeds, and it has the outstanding feature of an extremely strong security proof in cryptographic theory: a reduction from &amp;ldquo;worst-case complexity&amp;rdquo; to &amp;ldquo;average-case complexity.&amp;rdquo;&lt;/p>
&lt;p>In this article, starting from the mathematical definition of a &amp;ldquo;Lattice,&amp;rdquo; which is the foundation of lattice-based cryptography, we will thoroughly and deeply explain difficult problems on lattices such as SVP (Shortest Vector Problem) and CVP (Closest Vector Problem), and the &amp;ldquo;LWE (Learning With Errors) problem,&amp;rdquo; which can be said to be the heart of modern lattice-based cryptography, using mathematical formulas, geometric intuition, and specific numerical examples.&lt;/p>
&lt;h1 id="2-mathematical-definition-and-geometric-intuition-of-a-lattice">2. Mathematical Definition and Geometric Intuition of a Lattice
&lt;/h1>&lt;h2 id="21-vector-spaces-and-lattices">2.1 Vector Spaces and Lattices
&lt;/h2>&lt;p>In mathematics, a &amp;ldquo;Lattice&amp;rdquo; is a set of discrete points arranged regularly in an $n$-dimensional real vector space $\mathbb{R}^n$. It is similar to a Vector Space learned in linear algebra, but there is a crucial difference. While a vector space is a continuous space represented by a linear combination of basis vectors with &amp;ldquo;real coefficients,&amp;rdquo; a lattice is a discrete space represented by a linear combination of basis vectors with &amp;ldquo;integer coefficients.&amp;rdquo;&lt;/p>
&lt;p>Let&amp;rsquo;s give a strict mathematical definition. Consider $n$ ($n \le m$) linearly independent vectors $\mathbf{b}_1, \mathbf{b}_2, \dots, \mathbf{b}_n$ in an $m$-dimensional real vector space $\mathbb{R}^m$. Let a matrix having these vectors as column vectors be $B = [\mathbf{b}_1, \mathbf{b}_2, \dots, \mathbf{b}_n] \in \mathbb{R}^{m \times n}$. This $B$ is called the &amp;ldquo;Basis&amp;rdquo; of the lattice.&lt;/p>
&lt;p>The lattice $\mathcal{L}(B)$ generated by this basis $B$ is defined as follows:&lt;/p>
$$
\mathcal{L}(B) = \left\{ \sum_{i=1}^{n} x_i \mathbf{b}_i \mathrel{\bigg|} x_i \in \mathbb{Z} \right\} = \{ B \mathbf{x} \mid \mathbf{x} \in \mathbb{Z}^n \}
$$
&lt;p>What is important here is that the coefficients $x_i$ are limited to integers $\mathbb{Z}$, not real numbers $\mathbb{R}$. As a result, rather than a continuous space with infinitely many points, a &amp;ldquo;set of discrete points&amp;rdquo; like equally spaced intersections is formed.&lt;/p>
&lt;h2 id="22-geometric-image">2.2 Geometric Image
&lt;/h2>&lt;p>Let&amp;rsquo;s consider an example of a 2-dimensional plane $\mathbb{R}^2$. When $\mathbf{b}_1 = \begin{pmatrix} 1 \\ 0 \end{pmatrix}$ and $\mathbf{b}_2 = \begin{pmatrix} 0 \\ 1 \end{pmatrix}$ are chosen as basis vectors, the lattice generated by them is the set of all integer coordinates $(x, y) \in \mathbb{Z}^2$ on the coordinate plane. This is the simplest &amp;ldquo;square lattice.&amp;rdquo;&lt;/p>
&lt;p>However, lattices are not always orthogonal. For example, considering the basis $\mathbf{b}_1 = \begin{pmatrix} 2 \\ 1 \end{pmatrix}$ and $\mathbf{b}_2 = \begin{pmatrix} 1 \\ 3 \end{pmatrix}$, the generated points become like the intersections of an obliquely skewed mesh.&lt;/p>
&lt;h2 id="23-non-uniqueness-of-the-basis-and-unimodular-transformations">2.3 Non-uniqueness of the Basis and Unimodular Transformations
&lt;/h2>&lt;p>There is an important property related to the foundation of the security of lattice-based cryptography. That is, &amp;ldquo;there are infinitely many bases that generate the same lattice.&amp;rdquo;&lt;/p>
&lt;p>For example, the $\mathbb{Z}^2$ lattice generated by the previous basis $\mathbf{b}_1 = (1, 0)^T, \mathbf{b}_2 = (0, 1)^T$ can be generated as exactly the same lattice $\mathbb{Z}^2$ using the basis $\mathbf{b}'_1 = (1, 1)^T, \mathbf{b}'_2 = (2, 3)^T$.&lt;/p>
&lt;p>The necessary and sufficient condition for a basis $B$ and another basis $B'$ to generate the same lattice is that there exists a matrix with integer components $U \in \mathbb{Z}^{n \times n}$ whose determinant is $\det(U) = \pm 1$, and it can be expressed as:
&lt;/p>
$$ B' = B U $$
&lt;p>
Such a matrix $U$ is called a &amp;ldquo;Unimodular matrix.&amp;rdquo;&lt;/p>
&lt;p>The basic idea in its application to cryptography is to use a &amp;ldquo;good basis&amp;rdquo; (a basis that is close to orthogonal and consists of short vectors) as a secret key, and a &amp;ldquo;bad basis&amp;rdquo; (a basis that is extremely skewed relative to each other and consists of very long vectors) as a public key. It becomes very difficult to calculate a good basis from a bad basis as the dimension increases. This is the basic intuition behind lattice-based cryptography.&lt;/p>
&lt;h1 id="3-computationally-hard-problems-in-lattices">3. Computationally Hard Problems in Lattices
&lt;/h1>&lt;p>The security of lattice-based cryptography depends on the difficulty of solving specific mathematical problems on lattices. Here, we introduce the two most fundamental and famous problems.&lt;/p>
&lt;h2 id="31-shortest-vector-problem-svp">3.1 Shortest Vector Problem (SVP)
&lt;/h2>&lt;p>SVP is the most classical and famous problem in lattice theory.&lt;/p>
&lt;p>&lt;strong>Definition (SVP):&lt;/strong>
Given an arbitrary lattice basis $B$, find the vector $\mathbf{v}$ with the minimum Euclidean norm (length) among the non-zero vectors belonging to that lattice $\mathcal{L}(B)$.&lt;/p>
&lt;p>Expressed mathematically, it is the problem of finding $\mathbf{v}$ such that $\min_{\mathbf{v} \in \mathcal{L}(B) \setminus \{\mathbf{0}\}} \| \mathbf{v} \|$. This minimum length is written as $\lambda_1(\mathcal{L})$ and is called the &amp;ldquo;first successive minimum&amp;rdquo; of the lattice.&lt;/p>
&lt;p>In lower dimensions such as 2D or 3D, you can draw a figure and visually find the shortest vector. Alternatively, it can be efficiently solved using algorithms like Gauss&amp;rsquo;s lattice reduction algorithm. However, when the dimension $n$ becomes a high dimension such as hundreds to thousands, it is known that strictly solving SVP is NP-hard.&lt;/p>
&lt;p>In actual cryptography, instead of the strict shortest vector, an approximate SVP ($\gamma$-SVP) is used, which finds an &amp;ldquo;approximately short vector.&amp;rdquo; When the approximation factor $\gamma$ is of polynomial size, this problem is still considered very difficult.&lt;/p>
&lt;h2 id="32-closest-vector-problem-cvp">3.2 Closest Vector Problem (CVP)
&lt;/h2>&lt;p>CVP is also an extremely important problem in lattice-based cryptography.&lt;/p>
&lt;p>&lt;strong>Definition (CVP):&lt;/strong>
Given an arbitrary lattice basis $B$ and an arbitrary target vector $\mathbf{t} \in \mathbb{R}^m$ in space (which is not necessarily a lattice point), find the lattice point $\mathbf{v} \in \mathcal{L}(B)$ that is closest to $\mathbf{t}$ among the lattice points.&lt;/p>
&lt;p>Expressed mathematically, it is the problem of searching for a lattice point $\mathbf{v}$ such that $\min_{\mathbf{v} \in \mathcal{L}(B)} \| \mathbf{v} - \mathbf{t} \|$.&lt;/p>
&lt;p>Like SVP, CVP is also NP-hard in high dimensions. From the perspective of application to cryptography, the LWE problem described later is closely related to a special variant of this CVP (Bounded Distance Decoding: BDD).&lt;/p>
&lt;h2 id="33-why-are-they-unsolvable-in-high-dimensions-limits-of-lll-and-bkz">3.3 Why Are They Unsolvable in High Dimensions? (Limits of LLL and BKZ)
&lt;/h2>&lt;p>A famous algorithm for solving high-dimensional lattice problems is the LLL algorithm (Lenstra-Lenstra-Lovász algorithm). The LLL algorithm operates in polynomial time and can reduce a lattice basis to a &amp;ldquo;good basis&amp;rdquo; to some extent. However, since the shortest vector found by the LLL algorithm has an exponential approximation factor ($2^{\mathcal{O}(n)}$) relative to the length of the true shortest vector, it is not enough to break the security of the cryptography.&lt;/p>
&lt;p>By using a more powerful basis reduction algorithm such as the BKZ (Block Korkine-Zolotarev) algorithm, which is an improvement over LLL, a shorter vector can be found, but its computational complexity increases exponentially with respect to the block size. In lattice-based cryptography, secure parameters (such as the size of the dimension $n$) are determined by estimating the execution time of this BKZ algorithm. In current PQC standard parameters, values of dimension $n$ from 500 to over 1000 are chosen, and it is said that it would take more than the age of the universe to decrypt even if supercomputers or future quantum computers were used.&lt;/p>
&lt;h1 id="4-mathematical-formulation-of-the-lwe-learning-with-errors-problem">4. Mathematical Formulation of the LWE (Learning With Errors) Problem
&lt;/h1>&lt;p>Most of modern lattice-based cryptography is based on the &amp;ldquo;LWE (Learning With Errors) problem&amp;rdquo; proposed by Oded Regev in 2005. The beauty of the LWE problem lies in the simplicity of its formulation and the fact that it has a powerful mathematical proof of &amp;ldquo;reduction from worst-case to average-case complexity.&amp;rdquo;&lt;/p>
&lt;h2 id="41-systems-of-linear-equations-without-noise">4.1 Systems of Linear Equations Without Noise
&lt;/h2>&lt;p>To understand the LWE problem, let&amp;rsquo;s first consider a simple system of linear equations without noise.
Suppose there is an unknown secret vector $\mathbf{s} \in \mathbb{Z}_q^n$ (each component is an integer from $0$ to $q-1$). Here, $q$ is assumed to be a prime number.&lt;/p>
&lt;p>Choose random coefficient vectors $\mathbf{a}_1, \mathbf{a}_2, \dots \in \mathbb{Z}_q^n$, and calculate their inner product with the secret vector $\mathbf{s}$ modulo $q$.
$b_1 = \langle \mathbf{a}_1, \mathbf{s} \rangle \pmod q$
$b_2 = \langle \mathbf{a}_2, \mathbf{s} \rangle \pmod q$
$\vdots$&lt;/p>
&lt;p>Given a sufficient number (at least $n$) of pairs $(\mathbf{a}_i, b_i)$, we can easily recover the secret vector $\mathbf{s}$ by using &amp;ldquo;Gaussian elimination&amp;rdquo; in linear algebra. This is a problem that can be easily solved in polynomial time.&lt;/p>
&lt;h2 id="42-definition-of-the-lwe-problem-adding-noise">4.2 Definition of the LWE Problem: Adding Noise
&lt;/h2>&lt;p>So, what happens if we add a slight &amp;ldquo;noise (error)&amp;rdquo; to this problem?
This is the essence of the LWE problem.&lt;/p>
&lt;p>For an unknown secret vector $\mathbf{s} \in \mathbb{Z}_q^n$, we add a small error $e_i \in \mathbb{Z}_q$ to the result of each equation.
$b_i = \langle \mathbf{a}_i, \mathbf{s} \rangle + e_i \pmod q$&lt;/p>
&lt;p>Here, $e_i$ is a small integer value with a mean of 0 and a relatively small standard deviation (for example, chosen from a discrete Gaussian distribution, like a normal distribution).
The given information is a list of pairs of a random vector $\mathbf{a}_i$ and $b_i$ calculated by adding an error to it.
$( \mathbf{a}_1, b_1 ), ( \mathbf{a}_2, b_2 ), \dots, ( \mathbf{a}_m, b_m )$&lt;/p>
&lt;p>This becomes very neat when expressed as a matrix.
Using a random matrix $A \in \mathbb{Z}_q^{m \times n}$, a secret vector $\mathbf{s} \in \mathbb{Z}_q^n$, and an error vector $\mathbf{e} \in \mathbb{Z}_q^m$, it can be written as:
&lt;/p>
$$ \mathbf{b} = A \mathbf{s} + \mathbf{e} \pmod q $$
&lt;p>
Only $A$ and $\mathbf{b}$ are given. The problem of finding $\mathbf{s}$ from this is the &amp;ldquo;Search LWE problem.&amp;rdquo;&lt;/p>
&lt;p>Because the error $e_i$ is included, if one tries to use Gaussian elimination, the errors amplify exponentially during the process of adding and subtracting equations, making it impossible to reach the correct answer. At first glance, it looks like a simple system of linear equations, but just by adding this small noise, the difficulty of the problem jumps to an NP-hard level.&lt;/p>
&lt;h2 id="43-decision-lwe-problem">4.3 Decision LWE Problem
&lt;/h2>&lt;p>What is frequently used in cryptographic theory proofs is the &amp;ldquo;Decision LWE problem,&amp;rdquo; a variation of the Search LWE problem.&lt;/p>
&lt;p>The Decision LWE problem is the problem of determining which of the following two distributions a given list of samples came from:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>LWE Distribution&lt;/strong>: Intentionally calculated $(A, \mathbf{b} = A\mathbf{s} + \mathbf{e} \pmod q)$&lt;/li>
&lt;li>&lt;strong>Uniform Random Distribution&lt;/strong>: $(A, \mathbf{u})$ consisting of a completely randomly chosen matrix $A$ and vector $\mathbf{u}$&lt;/li>
&lt;/ol>
&lt;p>Surprisingly, if the parameters of the LWE problem are chosen appropriately, the pairs obtained from the LWE distribution become &amp;ldquo;Computationally Indistinguishable&amp;rdquo; from pairs of completely random data. This property provides the foundation for LWE-based cryptography to generate &amp;ldquo;ciphertexts indistinguishable from random numbers.&amp;rdquo;&lt;/p>
&lt;h2 id="44-reduction-from-worst-case-to-average-case-complexity-regevs-theorem">4.4 Reduction from Worst-Case to Average-Case Complexity (Regev&amp;rsquo;s Theorem)
&lt;/h2>&lt;p>Oded Regev&amp;rsquo;s greatest achievement is mathematically linking the difficulty of this LWE problem to the difficulty of the aforementioned lattice problems (SVP and CVP).&lt;/p>
&lt;p>Using a quantum reduction, he proved that &amp;ldquo;if there is a polynomial-time algorithm that can solve the LWE problem on average (for randomly chosen $A$ and $\mathbf{e}$), then there is a polynomial-time quantum algorithm that can solve the Gap-SVP for the worst case (the most difficult case) of any lattice.&amp;rdquo; (Later, a classical reduction was also demonstrated by Peikert et al.)&lt;/p>
&lt;p>This is a dream-like property in cryptographic theory. This is because it dispels the concern that &amp;ldquo;the cipher might be broken because we happened to choose a weak key (a part of the average case),&amp;rdquo; and gives a strong guarantee that &amp;ldquo;if average-case LWE can be solved, all hard problems on lattices can be solved (therefore LWE is absolutely hard).&amp;rdquo;&lt;/p>
&lt;div class="mermaid">graph TD
A["Worst-case Lattice Problems (Gap-SVP, SIVP)"] -->|Quantum/Classical Reduction| B["Average-case LWE Problem"]
B -->|Cryptographic Construction| C["LWE-based Cryptosystems (PKE, KEM, FHE)"]
style A fill:#ffcccc,stroke:#ff0000,stroke-width:2px,color:#000
style B fill:#ccffcc,stroke:#00aa00,stroke-width:2px,color:#000
style C fill:#ccccff,stroke:#0000ff,stroke-width:2px,color:#000&lt;/div>
&lt;h1 id="5-construction-of-a-public-key-cryptosystem-regevs-cryptosystem-using-lwe">5. Construction of a Public-Key Cryptosystem (Regev&amp;rsquo;s Cryptosystem) using LWE
&lt;/h1>&lt;p>Now that we understand the difficulty of the LWE problem, let&amp;rsquo;s look at the basic public-key cryptosystem proposed by Oded Regev to see how it is used for encryption and decryption. Here, we will explain the most basic mechanism for encrypting a 1-bit message $M \in \{0, 1\}$.&lt;/p>
&lt;h2 id="51-key-generation">5.1 Key Generation
&lt;/h2>&lt;ol>
&lt;li>Determine the system parameters: the modulus prime number $q$, the dimension $n$, and the number of equations $m$ ($m > n \log q$).&lt;/li>
&lt;li>As a secret key, choose a vector $\mathbf{s} \in \mathbb{Z}_q^n$ at random.&lt;/li>
&lt;li>Generate a random matrix $A \in \mathbb{Z}_q^{m \times n}$.&lt;/li>
&lt;li>Choose a small error vector $\mathbf{e} \in \mathbb{Z}_q^m$ from an error distribution such as a discrete Gaussian distribution.&lt;/li>
&lt;li>Calculate the vector $\mathbf{b} = A \mathbf{s} + \mathbf{e} \pmod q$.&lt;/li>
&lt;li>The Public Key will be $(A, \mathbf{b})$.&lt;/li>
&lt;li>The Secret Key will be $\mathbf{s}$.&lt;/li>
&lt;/ol>
&lt;p>The public key is exactly an &amp;ldquo;instance of the LWE problem.&amp;rdquo; Finding the secret key $\mathbf{s}$ from the public key $(A, \mathbf{b})$ is equivalent to solving the Search LWE problem, thereby ensuring security.&lt;/p>
&lt;h2 id="52-encryption">5.2 Encryption
&lt;/h2>&lt;p>Alice encrypts a 1-bit message $M \in \{0, 1\}$ using Bob&amp;rsquo;s public key $(A, \mathbf{b})$.&lt;/p>
&lt;ol>
&lt;li>Choose a random binary vector (components are 0 or 1) $\mathbf{r} \in \{0, 1\}^m$.&lt;/li>
&lt;li>As the first half of the ciphertext, compute the vector $\mathbf{u} = A^T \mathbf{r} \pmod q$. ($A^T$ is the transpose of $A$. That is, we are adding up the rows of $A$ where the component of $\mathbf{r}$ is 1).&lt;/li>
&lt;li>As the second half of the ciphertext, compute the scalar $v = \mathbf{b}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor \pmod q$.
(If the message $M$ is 0, add nothing; if $1$, add exactly half the value of $q$, $\lfloor \frac{q}{2} \rfloor$).&lt;/li>
&lt;li>The Ciphertext will be $(\mathbf{u}, v)$.&lt;/li>
&lt;/ol>
&lt;p>The intuitive meaning of encryption is to take the &amp;ldquo;sum of a random subset&amp;rdquo; for the public key matrix $A$ and vector $\mathbf{b}$. Due to the difficulty of the Decision LWE problem, this ciphertext $(\mathbf{u}, v)$ appears indistinguishable from a completely random vector and uniform random number (Semantic Security).&lt;/p>
&lt;div class="mermaid">flowchart LR
M["Message M in {0,1}"] --> Enc
PK["Public Key (A, b)"] --> Enc
r["Random binary vector r"] --> Enc
subgraph Enc ["Encryption Process"]
direction TB
u_calc["u = A^T * r mod q"]
v_calc["v = b^T * r + M * floor(q/2) mod q"]
end
Enc --> CT["Ciphertext (u, v)"]&lt;/div>
&lt;h2 id="53-decryption">5.3 Decryption
&lt;/h2>&lt;p>Bob decrypts the ciphertext $(\mathbf{u}, v)$ using the secret key $\mathbf{s}$.&lt;/p>
&lt;ol>
&lt;li>Compute the following value: $D = v - \mathbf{s}^T \mathbf{u} \pmod q$&lt;/li>
&lt;li>If the computed result is closer to $0$, output $M=0$; if it is closer to $\lfloor \frac{q}{2} \rfloor$, output $M=1$.&lt;/li>
&lt;/ol>
&lt;p>Let&amp;rsquo;s expand this mathematically to see why this can decrypt the message.
Recall that $\mathbf{b} = A \mathbf{s} + \mathbf{e}$.&lt;/p>
$$
\begin{aligned}
v - \mathbf{s}^T \mathbf{u} &amp;= (\mathbf{b}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor) - \mathbf{s}^T (A^T \mathbf{r}) \\
&amp;= ((A \mathbf{s} + \mathbf{e})^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor) - \mathbf{s}^T A^T \mathbf{r} \\
&amp;= (\mathbf{s}^T A^T \mathbf{r} + \mathbf{e}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor) - \mathbf{s}^T A^T \mathbf{r} \\
&amp;= \mathbf{e}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor \pmod q
\end{aligned}
$$
&lt;p>Here, $\mathbf{s}^T A^T \mathbf{r}$ perfectly cancelled out from the equation!
What remains is $\mathbf{e}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor$.&lt;/p>
&lt;p>$\mathbf{e}$ is a noise vector with very small components, and $\mathbf{r}$ is a binary vector whose components are 0 or 1. Therefore, their inner product $\mathbf{e}^T \mathbf{r}$ also remains a relatively small value (if parameters are chosen properly).&lt;/p>
&lt;ul>
&lt;li>If $M=0$, the result is $\mathbf{e}^T \mathbf{r}$, which is a small value close to $0$.&lt;/li>
&lt;li>If $M=1$, the result is $\mathbf{e}^T \mathbf{r} + \lfloor \frac{q}{2} \rfloor$, which will be located around half the value of $q$, $\lfloor \frac{q}{2} \rfloor$.&lt;/li>
&lt;/ul>
&lt;p>If the parameters are designed so that the absolute value of the error $\mathbf{e}^T \mathbf{r}$ stays under $\frac{q}{4}$, Bob can accurately determine (decrypt) the message $M$ just by seeing whether the computed result is closer to $0$ or $\lfloor \frac{q}{2} \rfloor$. This is the beautiful mechanism by which LWE-based cryptography functions.&lt;/p>
&lt;div class="mermaid">flowchart LR
CT["Ciphertext (u, v)"] --> Dec
SK["Secret Key s"] --> Dec
subgraph Dec ["Decryption Process"]
direction TB
calc["Compute D = v - s^T * u mod q"]
check["Check if D is closer to 0 or q/2"]
end
calc --> check
Dec --> M_out["Recovered Message M"]&lt;/div>
&lt;h1 id="6-toy-example-of-lwe-cryptography-using-specific-numerical-values">6. Toy Example of LWE Cryptography Using Specific Numerical Values
&lt;/h1>&lt;p>Since simply listing formulas might make it hard to get a real sense of it, let&amp;rsquo;s actually set very small numerical parameters and follow the calculations from encryption to decryption.
(* In actual cryptographic systems, values of $n$ of 500 or more and $q$ of several thousands or more are used to ensure security)&lt;/p>
&lt;p>&lt;strong>[Parameter Settings]&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Modulus $q = 17$ (A prime number. Therefore, values take the range from $0$ to $16$)&lt;/li>
&lt;li>Dimension $n = 2$&lt;/li>
&lt;li>Number of equations $m = 4$&lt;/li>
&lt;li>Suppose we want to encrypt the message $M = 1$.&lt;/li>
&lt;li>Message shift amount: $\lfloor \frac{q}{2} \rfloor = \lfloor \frac{17}{2} \rfloor = 8$&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>[1. Key Generation Phase]&lt;/strong>
Bob randomly chooses the secret key $\mathbf{s}$, matrix $A$, and error vector $\mathbf{e}$.
&lt;/p>
$$ \mathbf{s} = \begin{pmatrix} 3 \\ 4 \end{pmatrix} \in \mathbb{Z}_{17}^2 $$
$$ A = \begin{pmatrix} 2 &amp; 15 \\ 1 &amp; 8 \\ 14 &amp; 5 \\ 9 &amp; 10 \end{pmatrix} \in \mathbb{Z}_{17}^{4 \times 2} $$
$$ \mathbf{e} = \begin{pmatrix} 1 \\ -1 \\ 0 \\ 2 \end{pmatrix} \equiv \begin{pmatrix} 1 \\ 16 \\ 0 \\ 2 \end{pmatrix} \pmod{17} $$
&lt;p>Next, calculate the public key $\mathbf{b}$.
&lt;/p>
$$ A \mathbf{s} = \begin{pmatrix} 2 &amp; 15 \\ 1 &amp; 8 \\ 14 &amp; 5 \\ 9 &amp; 10 \end{pmatrix} \begin{pmatrix} 3 \\ 4 \end{pmatrix} = \begin{pmatrix} 2\times 3 + 15\times 4 \\ 1\times 3 + 8\times 4 \\ 14\times 3 + 5\times 4 \\ 9\times 3 + 10\times 4 \end{pmatrix} = \begin{pmatrix} 6 + 60 \\ 3 + 32 \\ 42 + 20 \\ 27 + 40 \end{pmatrix} = \begin{pmatrix} 66 \\ 35 \\ 62 \\ 67 \end{pmatrix} $$
&lt;p>
Calculate this modulo 17. (e.g., $66 = 17 \times 3 + 15$)
&lt;/p>
$$ A \mathbf{s} \pmod{17} = \begin{pmatrix} 15 \\ 1 \\ 11 \\ 16 \end{pmatrix} $$
&lt;p>
Add the error vector $\mathbf{e}$.
&lt;/p>
$$ \mathbf{b} = A \mathbf{s} + \mathbf{e} = \begin{pmatrix} 15 \\ 1 \\ 11 \\ 16 \end{pmatrix} + \begin{pmatrix} 1 \\ 16 \\ 0 \\ 2 \end{pmatrix} = \begin{pmatrix} 16 \\ 17 \\ 11 \\ 18 \end{pmatrix} \equiv \begin{pmatrix} 16 \\ 0 \\ 11 \\ 1 \end{pmatrix} \pmod{17} $$
&lt;p>The public key is $A$ and $\mathbf{b} = (16, 0, 11, 1)^T$.&lt;/p>
&lt;p>&lt;strong>[2. Encryption Phase]&lt;/strong>
Alice encrypts the message $M = 1$.
Choose a random vector $\mathbf{r}$. Here, let $\mathbf{r} = (1, 0, 1, 0)^T$.&lt;/p>
&lt;p>Calculate $\mathbf{u}$.
&lt;/p>
$$ \mathbf{u} = A^T \mathbf{r} = \begin{pmatrix} 2 &amp; 1 &amp; 14 &amp; 9 \\ 15 &amp; 8 &amp; 5 &amp; 10 \end{pmatrix} \begin{pmatrix} 1 \\ 0 \\ 1 \\ 0 \end{pmatrix} = \begin{pmatrix} 2 \times 1 + 14 \times 1 \\ 15 \times 1 + 5 \times 1 \end{pmatrix} = \begin{pmatrix} 16 \\ 20 \end{pmatrix} \equiv \begin{pmatrix} 16 \\ 3 \end{pmatrix} \pmod{17} $$
&lt;p>Calculate $v$.
&lt;/p>
$$ \mathbf{b}^T \mathbf{r} = (16, 0, 11, 1) \begin{pmatrix} 1 \\ 0 \\ 1 \\ 0 \end{pmatrix} = 16 \times 1 + 11 \times 1 = 27 \equiv 10 \pmod{17} $$
&lt;p>
Add the value $\lfloor 17/2 \rfloor = 8$ corresponding to the message $M=1$.
&lt;/p>
$$ v = \mathbf{b}^T \mathbf{r} + M \cdot 8 = 10 + 1 \times 8 = 18 \equiv 1 \pmod{17} $$
&lt;p>Alice sends the ciphertext $(\mathbf{u}, v) = \left( \begin{pmatrix} 16 \\ 3 \end{pmatrix}, 1 \right)$ to Bob.&lt;/p>
&lt;p>&lt;strong>[3. Decryption Phase]&lt;/strong>
Bob, upon receiving the ciphertext, decrypts it using the secret key $\mathbf{s} = (3, 4)^T$.
Calculate the decryption formula: $D = v - \mathbf{s}^T \mathbf{u} \pmod{17}$.&lt;/p>
$$ \mathbf{s}^T \mathbf{u} = (3, 4) \begin{pmatrix} 16 \\ 3 \end{pmatrix} = 3 \times 16 + 4 \times 3 = 48 + 12 = 60 \equiv 9 \pmod{17} $$
$$ D = v - \mathbf{s}^T \mathbf{u} = 1 - 9 = -8 \pmod{17} $$
&lt;p>Here, in the modulo 17 world, $-8$ is equal to $9$ ($-8 + 17 = 9$).
Determine whether the obtained value $D = 9$ is closer to $0$ or $8$ ($\lfloor 17/2 \rfloor$).
Since $9$ is clearly closer to $8$ than to $0$, Bob correctly restored $M = 1$!&lt;/p>
&lt;p>Why did it become $9$? Let&amp;rsquo;s recall the previous proof.
The error part is $\mathbf{e}^T \mathbf{r} = (1, -1, 0, 2) (1, 0, 1, 0)^T = 1 \times 1 + 0 \times 1 = 1$.
Therefore, the calculation result is $\mathbf{e}^T \mathbf{r} + M \cdot 8 = 1 + 8 = 9$, confirming that the theoretically expected value was calculated.&lt;/p>
&lt;h1 id="7-evolution-towards-practical-application-ring-lwe-and-module-lwe">7. Evolution Towards Practical Application: Ring-LWE and Module-LWE
&lt;/h1>&lt;p>The Standard LWE problem explained so far has an extremely strong security proof, but it has a fatal flaw in practical use. That is, &amp;ldquo;the size of the keys becomes huge&amp;rdquo; and &amp;ldquo;the computational cost is high.&amp;rdquo;&lt;/p>
&lt;p>In Standard LWE, the public key includes a huge matrix $A \in \mathbb{Z}_q^{m \times n}$. When the parameter $n$ goes up to hundreds or thousands, the size of this matrix reaches several megabytes, making it too heavy to transmit and receive every time over Internet communication protocols (such as TLS). Also, multiplying a matrix and a vector requires a computational complexity of $\mathcal{O}(n^2)$.&lt;/p>
&lt;p>To solve this problem, &amp;ldquo;Ring-LWE (RLWE)&amp;rdquo; and &amp;ldquo;Module-LWE (MLWE)&amp;rdquo; were introduced, incorporating an algebraic structure called polynomial rings into the lattice.&lt;/p>
&lt;h2 id="71-intuition-of-ring-lwe">7.1 Intuition of Ring-LWE
&lt;/h2>&lt;p>In Ring-LWE, vectors and matrices are replaced with elements (polynomials) over a polynomial ring $\mathcal{R}_q = \mathbb{Z}_q[X]/(X^n + 1)$. (Here, $n$ is chosen as a power of 2).&lt;/p>
&lt;p>Whereas the public key of Standard LWE was a matrix $A$, Ring-LWE uses a single polynomial $a(x)$. The secret key $s(x)$ and the error $e(x)$ also become polynomials.
The equation looks like this:
&lt;/p>
$$ b(x) = a(x) \cdot s(x) + e(x) \pmod q $$
&lt;p>Since this is polynomial multiplication, by using the &amp;ldquo;Number Theoretic Transform (NTT),&amp;rdquo; which is similar to the Fast Fourier Transform (FFT), the computational complexity can be dramatically reduced to $\mathcal{O}(n \log n)$. Furthermore, because the size of the public key shrinks from a matrix to a single polynomial, the data size is reduced to $\mathcal{O}(n)$. This brings an overwhelming advantage in communication bandwidth.&lt;/p>
&lt;p>Mathematically speaking, Ring-LWE reduces to a problem on a lattice with a special symmetry called an &amp;ldquo;Ideal Lattice&amp;rdquo; rather than a general lattice.&lt;/p>
&lt;h2 id="72-module-lwe-and-nist-standardization-kyber--ml-kem">7.2 Module-LWE and NIST Standardization (Kyber / ML-KEM)
&lt;/h2>&lt;p>While Ring-LWE is efficient, there was some concern that the special algebraic structure of ideal lattices might become a clue for future attacks. Therefore, &amp;ldquo;Module-LWE (MLWE)&amp;rdquo; was created to take the &amp;ldquo;best of both worlds&amp;rdquo;: the conservative security of Standard LWE and the efficiency of Ring-LWE.&lt;/p>
&lt;p>Module-LWE considers small matrices and vectors whose elements are polynomials. In other words, it handles modules over a ring.
Currently, &amp;ldquo;CRYSTALS-Kyber&amp;rdquo; (standardized name: ML-KEM), which NIST selected as the standard for PQC key encapsulation mechanisms (KEM), is built precisely on the difficulty of this Module-LWE problem.&lt;/p>
&lt;h1 id="8-why-is-it-secure-against-quantum-computers">8. Why is it Secure Against Quantum Computers?
&lt;/h1>&lt;p>Finally, let&amp;rsquo;s touch upon the core issue: &amp;ldquo;Why is lattice-based cryptography considered unbreakable even when using quantum computers?&amp;rdquo;&lt;/p>
&lt;p>Shor&amp;rsquo;s algorithm, which allows quantum computers to break RSA cryptography and Elliptic Curve Cryptography, is essentially an algorithm that solves the &amp;ldquo;Hidden Subgroup Problem (HSP).&amp;rdquo; The mathematical structure (finite abelian groups) behind RSA and ECC has periodicity, and by using a specific operation of quantum algorithms called the Quantum Fourier Transform (QFT), this period (hidden subgroup) can be extracted all at once.&lt;/p>
&lt;p>However, lattice problems are fundamentally different. Although lattices also have periodicity, what is required in SVP and CVP is a geometric, non-linear property such as &amp;ldquo;shortest distance&amp;rdquo; or &amp;ldquo;removal of noise.&amp;rdquo; Even if a &amp;ldquo;Quantum Fourier Transform over an abelian group&amp;rdquo; like Shor&amp;rsquo;s algorithm is applied directly, useful information that would be the answer to the lattice problem cannot be efficiently extracted. To date, no quantum algorithm that can solve SVP or LWE in polynomial time has been discovered, and it is widely believed that even with the parallel computing power of quantum computers, the only effective means is near-brute-force search (about the level of square root speedup by Grover&amp;rsquo;s algorithm).&lt;/p>
&lt;h1 id="9-conclusion">9. Conclusion
&lt;/h1>&lt;p>In this article, we explained the mathematical intuition of lattice-based cryptography in detail, starting from the geometric definition of a lattice, to the formulation of the LWE problem, and the construction of a public-key cryptosystem.&lt;/p>
&lt;ol>
&lt;li>A &lt;strong>Lattice&lt;/strong> is a discrete space represented by integer-coefficient linear combinations of basis vectors, and finding a &amp;ldquo;good basis&amp;rdquo; close to orthogonal (SVP) becomes difficult in high dimensions.&lt;/li>
&lt;li>The &lt;strong>LWE (Learning With Errors) problem&lt;/strong> is the problem of solving a system of linear equations with noise, and since it is tied to the difficulty of worst-case problems on lattices, it provides a powerful security foundation.&lt;/li>
&lt;li>By using the LWE problem, encryption and decryption (&lt;strong>Regev&amp;rsquo;s Cryptosystem&lt;/strong>) are realized through an ingenious mechanism of intentionally adding and removing noise.&lt;/li>
&lt;li>In real-world protocols, &lt;strong>Ring-LWE&lt;/strong> and &lt;strong>Module-LWE&lt;/strong> using polynomial rings are adopted to improve communication efficiency and computation speed, serving as the foundation for the NIST-standard &lt;strong>ML-KEM&lt;/strong>.&lt;/li>
&lt;/ol>
&lt;p>As the unprecedented computational paradigm shift of quantum computers approaches, it is quite romantic that &amp;ldquo;lattice-based cryptography,&amp;rdquo; born from the depths of classical linear algebra and number theory, will bear the foundation of future internet security. The math that forms the foundation of lattice-based cryptography is by no means too esoteric, and anyone with a basic knowledge of linear algebra and probability can fully understand its beautiful structure. We hope this article has helped you understand lattice-based cryptography, the core of PQC.&lt;/p></description></item><item><title>The Riemann Hypothesis and the Distribution of Prime Numbers: A Deep Connection with Modern Cryptography</title><link>http://kenji.blog/en/p/riemann-hypothesis-prime-distribution-cryptography/</link><pubDate>Fri, 11 Sep 2026 16:00:00 +0900</pubDate><guid>http://kenji.blog/en/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 The Riemann Hypothesis and the Distribution of Prime Numbers: A Deep Connection with Modern Cryptography" />&lt;h1 id="1-introduction-the-mystery-of-the-universe-in-prime-numbers-and-the-riemann-hypothesis">1. Introduction: The Mystery of the Universe in Prime Numbers and the Riemann Hypothesis
&lt;/h1>&lt;p>&amp;ldquo;Prime Numbers&amp;rdquo; are natural numbers divisible only by 1 and themselves, often called the &amp;ldquo;atoms&amp;rdquo; in the world of mathematics. The sequence of 2, 3, 5, 7, 11, 13&amp;hellip; appears at first glance to be unordered and random. Ever since the ancient Greek mathematician Euclid proved that &amp;ldquo;there are infinitely many prime numbers,&amp;rdquo; countless mathematicians have challenged themselves to unravel the regularity hidden in the arrangement of these primes.&lt;/p>
&lt;p>The closest anyone has come to the mystery of prime numbers is the &lt;strong>&amp;ldquo;Riemann Hypothesis&amp;rdquo;&lt;/strong> proposed by the German mathematician Bernhard Riemann in 1859. The Riemann Hypothesis is one of the most important and unsolved difficult problems in modern mathematics, and carries a $1 million prize as one of the Millennium Prize Problems designated by the Clay Mathematics Institute.&lt;/p>
&lt;p>At first glance, a difficult problem in pure mathematics regarding the distribution of prime numbers may seem unrelated to our daily lives. However, internet security, which supports the infrastructure of modern society, especially &lt;strong>modern cryptographic technologies such as RSA cryptography and Elliptic Curve Cryptography (ECC)&lt;/strong>, relies deeply on the properties of gigantic prime numbers.&lt;/p>
&lt;p>In this article, we will embark on a mathematical journey from the distribution of prime numbers to the Prime Number Theorem, the Riemann Zeta function, and the core of the Riemann Hypothesis. We will provide an extremely detailed and deep explanation of how it is connected to modern cryptography and what would happen to the world if the Riemann Hypothesis were proven.&lt;/p>
&lt;hr>
&lt;h1 id="2-the-prime-number-theorem-and-the-distribution-of-primes-gausss-discovery">2. The Prime Number Theorem and the Distribution of Primes: Gauss&amp;rsquo;s Discovery
&lt;/h1>&lt;p>To understand how prime numbers are distributed, mathematicians considered the &lt;strong>Prime-counting function&lt;/strong> $\pi(x)$, which represents &amp;ldquo;how many prime numbers exist up to a certain number $x$.&amp;rdquo;&lt;/p>
&lt;p>For example:&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>The 15-year-old genius mathematician Carl Friedrich Gauss calculated vast tables of prime numbers and discovered that the frequency of appearance of prime numbers decreases in inverse proportion to the natural logarithm $\ln x$. That is, he conjectured that the probability of finding a prime number near a certain number $x$ is approximately $\frac{1}{\ln x}$.&lt;/p>
&lt;p>Expressing this using integration gives the &lt;strong>Logarithmic integral&lt;/strong> $\text{Li}(x)$:&lt;/p>
$$ \text{Li}(x) = \int_{2}^{x} \frac{dt}{\ln t} $$
&lt;p>Gauss&amp;rsquo;s conjecture was later independently proven in 1896 by Jacques Hadamard and Charles Jean de la Vallée Poussin, and was established as the &lt;strong>Prime Number Theorem (PNT)&lt;/strong>.&lt;/p>
$$ \lim_{x \to \infty} \frac{\pi(x)}{\text{Li}(x)} = 1 $$
&lt;p>Or, it can be approximately expressed as follows:&lt;/p>
$$ \pi(x) \sim \frac{x}{\ln x} $$
&lt;p>Through this theorem, it became clear that prime numbers have a very smooth and predictable distribution when viewed macroscopically. However, microscopically, there is always an &amp;ldquo;error&amp;rdquo; or &amp;ldquo;fluctuation&amp;rdquo; between $\pi(x)$ and $\text{Li}(x)$. The true nature of this fluctuation is exactly the greatest mystery that the Riemann Hypothesis attempts to unravel.&lt;/p>
&lt;hr>
&lt;h1 id="3-the-riemann-zeta-function-and-the-euler-product">3. The Riemann Zeta Function and the Euler Product
&lt;/h1>&lt;p>The most powerful weapon for analyzing the distribution of prime numbers is the &lt;strong>Riemann Zeta Function&lt;/strong>. Originally, it was an infinite series defined by Leonhard Euler for real numbers $s > 1$.&lt;/p>
$$ \zeta(s) = \sum_{n=1}^\infty \frac{1}{n^s} = 1 + \frac{1}{2^s} + \frac{1}{3^s} + \frac{1}{4^s} + \dots $$
&lt;p>One of Euler&amp;rsquo;s greatest achievements was proving that this infinite series can be expressed as an infinite product over all prime numbers $p$. This is the &lt;strong>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>An intuitive understanding of the proof is that if each term on the right side is expanded as a geometric series and multiplied together, by the Fundamental Theorem of Arithmetic (every natural number can be uniquely represented as a product of primes), the sum of the reciprocals of natural numbers on the left side is perfectly reconstructed.&lt;/p>
&lt;p>&lt;strong>This single mathematical formula became the bridge connecting analysis (infinite series, continuous functions) and number theory (prime numbers, discrete numbers).&lt;/strong> Investigating the Zeta function is synonymous with investigating the distribution of prime numbers.&lt;/p>
&lt;hr>
&lt;h1 id="4-analytic-continuation-and-extension-to-the-complex-plane">4. Analytic Continuation and Extension to the Complex Plane
&lt;/h1>&lt;p>Riemann&amp;rsquo;s genius lay in extending the variable $s$ of $\zeta(s)$, which Euler had considered only for real numbers, to &lt;strong>complex numbers $s = \sigma + it$ (where $\sigma$ is the real part and $t$ is the imaginary part)&lt;/strong>.&lt;/p>
&lt;p>The original infinite series only converges for $\sigma > 1$, but using a technique called &amp;ldquo;Analytic Continuation,&amp;rdquo; Riemann extended the definition so that $\zeta(s)$ is meaningful over the entire complex plane, excluding the pole at $s = 1$.&lt;/p>
&lt;p>He further derived a beautiful functional equation satisfied by the Zeta function:&lt;/p>
$$ \zeta(s) = 2^s \pi^{s-1} \sin\left(\frac{\pi s}{2}\right) \Gamma(1-s) \zeta(1-s) $$
&lt;p>Here, $\Gamma(x)$ is the Gamma function. Through this equation, the properties of the left half-plane can be known from the properties of the right half-plane.&lt;/p>
&lt;h3 id="zeros-of-the-zeta-function">Zeros of the Zeta Function
&lt;/h3>&lt;p>Complex numbers $s$ for which the value of the Zeta function becomes 0 are called &amp;ldquo;zeros&amp;rdquo;.
From the functional equation, when $s$ is a negative even integer ($-2, -4, -6, \dots$), $\sin(\pi s / 2)$ becomes 0, resulting in $\zeta(s) = 0$. These are called &lt;strong>Trivial zeros&lt;/strong>.&lt;/p>
&lt;p>However, what is important in the distribution of prime numbers are the other zeros, namely the &lt;strong>Non-trivial zeros&lt;/strong> that exist in the &amp;ldquo;Critical strip&amp;rdquo; where $0 \le \sigma \le 1$.&lt;/p>
&lt;hr>
&lt;h1 id="5-the-core-of-the-riemann-hypothesis-and-the-explicit-formula">5. The Core of the Riemann Hypothesis and the Explicit Formula
&lt;/h1>&lt;p>Riemann calculated a small number of zeros and formulated a remarkable conjecture. This is the &lt;strong>Riemann Hypothesis&lt;/strong>.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Riemann Hypothesis&lt;/strong>
All non-trivial zeros of the Riemann Zeta function $\zeta(s)$ lie on the line where the real part is $1/2$ ($\text{Re}(s) = 1/2$).&lt;/p>
&lt;/blockquote>
&lt;p>This line with a real part of $1/2$ is called the &amp;ldquo;Critical line&amp;rdquo;.&lt;/p>
&lt;div class="mermaid">graph TD
A["Riemann Zeta function ζ(s)"] --> B["Extension to the complex plane by analytic continuation"]
B --> C["Trivial zeros (s = -2, -4, -6 ...)"]
B --> D["Non-trivial zeros (0 &lt;= Re(s) &lt;= 1)"]
D --> E["Riemann Hypothesis"]
E --> F["All non-trivial zeros lie on Re(s) = 1/2"]
F --> G["To the proof of the limit of the error term in the prime distribution"]&lt;/div>
&lt;p>Why is the Riemann Hypothesis so important? It is because the zeros of the Zeta function &lt;strong>completely&lt;/strong> determine the distribution of prime numbers.&lt;/p>
&lt;p>Riemann and later the mathematician von Mangoldt derived an &amp;ldquo;Explicit formula&amp;rdquo; that accurately describes the distribution of primes. Using the Chebyshev function $\psi(x)$, it is expressed as follows:&lt;/p>
$$ \psi(x) = x - \sum_{\rho} \frac{x^\rho}{\rho} - \ln(2\pi) - \frac{1}{2}\ln(1 - x^{-2}) $$
&lt;p>Here, $\rho$ runs over all the non-trivial zeros of the Zeta function.
The main term is $x$ (which corresponds to the Prime Number Theorem), and by adding and subtracting wave-like terms depending on the zeros $\rho$, the precise step-like distribution of primes is restored. The non-trivial zeros can be said to represent the &amp;ldquo;frequencies (waves)&amp;rdquo; of the distribution of primes.&lt;/p>
&lt;p>If the Riemann Hypothesis is true, and the real part of all non-trivial zeros $\rho$ is exactly $1/2$, the error term of the Prime Number Theorem would fall within the theoretically smallest possible range.&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>In other words, &lt;strong>if the Riemann Hypothesis is true, it proves that prime numbers are distributed as &amp;ldquo;regularly and beautifully&amp;rdquo; as we can possibly imagine.&lt;/strong>&lt;/p>
&lt;hr>
&lt;h1 id="6-the-inseparable-relationship-between-modern-cryptography-and-prime-numbers">6. The Inseparable Relationship Between Modern Cryptography and Prime Numbers
&lt;/h1>&lt;p>So far, we have been in the realm of profound pure mathematics, but this property of prime numbers fundamentally supports modern digital society. A representative example of this is public-key cryptography, such as &lt;strong>RSA cryptography&lt;/strong>.&lt;/p>
&lt;p>The security of all communications, such as credit card payments on the internet, password transmissions, and electronic signatures in blockchains, relies on &amp;ldquo;prime numbers.&amp;rdquo;&lt;/p>
&lt;h3 id="how-rsa-cryptography-works">How RSA Cryptography Works
&lt;/h3>&lt;p>The security of RSA cryptography is based on the mathematical fact that &amp;ldquo;factorizing a composite number with a large number of digits is extremely difficult&amp;rdquo; (the integer factorization problem).&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Key Generation&lt;/strong>:
Randomly select two gigantic prime numbers $p$ and $q$ (for example, 2048 bits each).
Multiply them to calculate $N = p \times q$. This $N$ becomes a part of the public key.
Using Euler&amp;rsquo;s totient function $\phi(N) = (p-1)(q-1)$, generate a private key $d$:&lt;/p>
$$ e \times d \equiv 1 \pmod{\phi(N)} $$
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Encryption and Decryption&lt;/strong>:
The plaintext $M$ is converted into ciphertext $C$ using the public keys $e, N$:
&lt;/p>
$$ C \equiv M^e \pmod{N} $$
&lt;p>
Only the person possessing the private key $d$ can decrypt it:
&lt;/p>
$$ M \equiv C^d \pmod{N} $$
&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph LR
A["Plaintext"] --> B["Encrypt with public key (e, N)"]
B --> C["Ciphertext"]
C --> D["Decrypt with private key (d)"]
D --> E["Original Plaintext"]
F["Attacker"] -- "Attempts to factorize N" --> C
F -.-> G["d cannot be calculated without knowing p and q"]&lt;/div>
&lt;p>To break RSA cryptography, one must find (factorize) the original primes $p$ and $q$ from a massive $N$. Even using currently mainstream algorithms (such as the General Number Field Sieve, GNFS), factorizing a number with hundreds of digits would take significantly more time than the age of the universe, even with a supercomputer.&lt;/p>
&lt;hr>
&lt;h1 id="7-the-impact-of-the-riemann-hypothesis-on-cryptography">7. The Impact of the Riemann Hypothesis on Cryptography
&lt;/h1>&lt;p>So, how do the &amp;ldquo;Riemann Hypothesis,&amp;rdquo; which sits at the pinnacle of pure mathematics, and &amp;ldquo;cryptography&amp;rdquo; intersect?&lt;/p>
&lt;h3 id="71-prime-generation-algorithms-primality-testing-and-the-generalized-riemann-hypothesis-grh">7.1. Prime Generation Algorithms (Primality Testing) and the Generalized Riemann Hypothesis (GRH)
&lt;/h3>&lt;p>To operate RSA cryptography, gigantic prime numbers $p$ and $q$ must first be generated. However, it is not easy to reliably and quickly determine whether &amp;ldquo;a certain number is prime.&amp;rdquo;&lt;/p>
&lt;p>Currently, what is used practically is a probabilistic algorithm called the &lt;strong>Miller-Rabin primality test&lt;/strong>. Although this algorithm is fast, there is a risk of &amp;ldquo;pseudoprimes,&amp;rdquo; where a composite number is incorrectly identified as a prime number with an extremely low probability.&lt;/p>
&lt;p>However, if we assume the &lt;strong>&amp;ldquo;Generalized Riemann Hypothesis (GRH)&amp;rdquo;&lt;/strong>, which extends the Riemann Hypothesis to Dirichlet L-functions, to be true, the story changes dramatically.
If the GRH is true, an upper bound on the number of tests in the Miller-Rabin test is mathematically guaranteed, and it is &lt;strong>elevated from a probabilistic algorithm to a &amp;ldquo;deterministic polynomial-time algorithm&amp;rdquo;&lt;/strong> (this was a significant fact known even before the discovery of the AKS primality test).&lt;/p>
&lt;p>In short, the Riemann Hypothesis (and its generalization) plays a role in directly validating the foundation of cryptography: &amp;ldquo;Can we generate massive prime numbers quickly and with absolute confidence?&amp;rdquo;&lt;/p>
&lt;h3 id="72-relationship-with-factorization-algorithms">7.2. Relationship with Factorization Algorithms
&lt;/h3>&lt;p>When evaluating the computational complexity of algorithms for breaking codes (such as the General Number Field Sieve), knowledge of the distribution of prime numbers is also essential. Many integer factorization algorithms rely on the distribution of &amp;ldquo;Smooth numbers&amp;rdquo; (numbers that only have small prime factors).&lt;/p>
&lt;p>To strictly evaluate how frequently smooth numbers appear, a deep understanding of the distribution of primes is necessary, and analytic number theory techniques directly connected to the Zeta function and the Riemann Hypothesis are fully utilized here as well. If the Riemann Hypothesis is proven and the error in prime distribution is completely determined, it will become possible to more accurately assess the performance limits of integer factorization algorithms.&lt;/p>
&lt;hr>
&lt;h1 id="8-will-cryptography-be-broken-if-the-riemann-hypothesis-is-proven">8. Will Cryptography be Broken if the Riemann Hypothesis is Proven?
&lt;/h1>&lt;p>There is an urban legend that says, &amp;ldquo;If the Riemann Hypothesis is solved, RSA cryptography will instantly collapse,&amp;rdquo; but &lt;strong>this is mathematically inaccurate&lt;/strong>.&lt;/p>
&lt;p>The proof of the Riemann Hypothesis itself would not immediately yield a magical algorithm that drastically speeds up integer factorization. This is because the Riemann Hypothesis is ultimately a theorem about the &amp;ldquo;macroscopic regularity of the distribution&amp;rdquo; of primes, and it does not directly tell us which primes divide an individual number $N$ (a local property).&lt;/p>
&lt;p>However, the impact is not zero.
This is because, in the process of proving the Riemann Hypothesis, it is extremely likely that &lt;strong>&amp;ldquo;new mathematical tools&amp;rdquo; and &amp;ldquo;unknown analytical methods&amp;rdquo;&lt;/strong> will be discovered. Looking at history, when Fermat&amp;rsquo;s Last Theorem or the Poincaré Conjecture were proven, the new theories developed during the process greatly advanced the entirety of mathematics.&lt;/p>
&lt;p>If unknown algebraic geometry methods or non-commutative geometry methods are established that can completely manipulate the properties of the zeros of the Riemann Zeta function, it cannot be denied that this might ultimately lead to the discovery of a groundbreaking integer factorization algorithm (for example, a classical algorithm that reduces the computational complexity to polynomial time). In that sense, cryptographers can never take their eyes off the developments surrounding the Riemann Hypothesis.&lt;/p>
&lt;h3 id="quantum-computers-and-shors-algorithm">Quantum Computers and Shor&amp;rsquo;s Algorithm
&lt;/h3>&lt;p>A more direct and realistic threat to cryptography is not the proof of the Riemann Hypothesis, but &lt;strong>quantum computers&lt;/strong>. &amp;ldquo;Shor&amp;rsquo;s Algorithm,&amp;rdquo; published by Peter Shor in 1994, proved that integer factorization can be solved in polynomial time if a quantum computer with sufficient performance exists. Consequently, RSA cryptography and Elliptic Curve Cryptography will be fundamentally broken.&lt;/p>
&lt;p>Currently, a transition to &amp;ldquo;Post-Quantum Cryptography (PQC)&amp;rdquo; (such as lattice-based cryptography), which cannot be decrypted even by quantum computers, is progressing worldwide. Cryptography relying on prime numbers may be coming to the end of its golden age in a sense, but the mathematical value of prime numbers themselves will never be lost.&lt;/p>
&lt;hr>
&lt;h1 id="9-conclusion-the-intersection-of-mathematical-abstraction-and-real-society">9. Conclusion: The Intersection of Mathematical Abstraction and Real Society
&lt;/h1>&lt;div class="mermaid">graph TD
A["Exploration of pure mathematics"] --> B["Elucidation of the Riemann Hypothesis"]
B --> C["Complete understanding of prime distribution"]
C --> D["Leap in the development of number theory and algebraic geometry"]
D -.-> E["Possibility of new integer factorization algorithms"]
E -.-> F["Update of security evaluations for cryptography"]
A --> G["Applied mathematics and computer science"]
G --> H["Efficiency in primality testing and cryptographic generation"]
H --> F&lt;/div>
&lt;p>The insatiable exploration of prime numbers that has continued since ancient Greece was elevated by the genius of Riemann into a beautiful symphony (the zeros of the Zeta function) on the complex plane. Amazingly, after several centuries, the crystallization of that purely innocent mathematics is being applied as the strongest shield ensuring the safety of the internet society.&lt;/p>
&lt;p>The Riemann Hypothesis symbolizes both the &amp;ldquo;abstract beauty&amp;rdquo; of mathematics and its &amp;ldquo;astonishing applicability to the physical world and real society.&amp;rdquo;&lt;/p>
&lt;p>When this massive mountain of mathematics, whose peak no one has yet reached, is conquered someday, we will completely understand the universal truth of prime numbers and gain a new perspective on the foundation of our information society. Studying cryptography is, in itself, a journey tracing the history of human wisdom.&lt;/p></description></item><item><title>Fast Primality Testing Algorithm Implemented in C++ (Miller-Rabin, etc.)</title><link>http://kenji.blog/en/p/cpp-fast-prime-testing-miller-rabin/</link><pubDate>Fri, 11 Sep 2026 14:00:00 +0900</pubDate><guid>http://kenji.blog/en/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 Fast Primality Testing Algorithm Implemented in C++ (Miller-Rabin, etc.)" />&lt;h1 id="introduction-why-do-we-need-fast-primality-testing">Introduction: Why Do We Need Fast Primality Testing?
&lt;/h1>&lt;p>In the worlds of computer science, cryptography, and competitive programming, determining whether a given number is prime quickly and accurately is an extremely important and fundamental task. For example, public-key cryptography such as RSA, which underpins the security of modern internet society, relies on the generation of massive prime numbers and the difficulty of factoring their product as the basis of its security. Therefore, it is no exaggeration to say that the technology to instantly identify whether a massive number is prime is a technology that supports the foundation of digital society.&lt;/p>
&lt;p>Also, in competitive programming (such as AtCoder and Codeforces), primality testing is a frequently occurring theme. For massive inputs with constraints like $N \le 10^{18}$, in situations where you need to perform tens of thousands of primality tests within 1 second, traditional, naive algorithms will certainly result in a Time Limit Exceeded (TLE).&lt;/p>
&lt;p>In this article, we will thoroughly explain everything from naive primality testing algorithms to the probabilistic primality testing method &amp;ldquo;Fermat&amp;rsquo;s Primality Test,&amp;rdquo; and the practically strongest fast algorithm that overcomes its weaknesses: the &amp;ldquo;Miller-Rabin Primality Test.&amp;rdquo; We will cover everything from the mathematical background to a highly optimized implementation in C++. In particular, for 64-bit integers ($N &lt; 2^{64}$), we will explain in detail a method that goes beyond probabilistic testing to &amp;ldquo;100% deterministic primality testing&amp;rdquo; and provide C++ source code that you can use directly in practice.&lt;/p>
&lt;hr>
&lt;h1 id="1-the-basics-of-primality-testing-and-trial-division">1. The Basics of Primality Testing and Trial Division
&lt;/h1>&lt;p>A prime number is a natural number greater than 1 that has no positive divisors other than 1 and itself. According strictly to the definition of a prime number, to determine whether a given integer $N$ is prime, you can try dividing $N$ by all integers from $2$ to $N-1$. If it is never divisible, it is a prime number; if it is divisible even once, it is a composite number (not a prime).&lt;/p>
&lt;p>However, the time complexity of this method is $O(N)$. When $N$ is a massive number like $10^{18}$, even modern computers would take an enormous amount of time to calculate it.&lt;/p>
&lt;h2 id="optimizing-trial-division-searching-up-to-sqrtn">Optimizing Trial Division: Searching up to $\sqrt{N}$
&lt;/h2>&lt;p>When a composite number $N$ is expressed as $a \times b = N$ ($a \le b$), it is always true that $a \le \sqrt{N}$. Therefore, the primality testing loop does not need to run up to $N-1$; it is sufficient to check up to $\sqrt{N}$.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Primality testing by trial division (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">// Only check odd numbers from 3 onwards
&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>The time complexity of this algorithm is $O(\sqrt{N})$. If $N \le 10^{12}$, it can be computed instantly, but when $N \approx 10^{18}$, the number of loop iterations is about $10^9$. Even with a C++ runtime, this takes hundreds of milliseconds to several seconds, making it unsuitable for multiple tests.&lt;/p>
&lt;hr>
&lt;h1 id="2-fermats-primality-test-the-dawn-of-probabilistic-primality-testing">2. Fermat&amp;rsquo;s Primality Test: The Dawn of Probabilistic Primality Testing
&lt;/h1>&lt;p>To break through the limitations of trial division, &amp;ldquo;Probabilistic Algorithms&amp;rdquo; using theorems from number theory were devised. A prime example is the &amp;ldquo;Fermat Primality Test,&amp;rdquo; which utilizes Fermat&amp;rsquo;s Little Theorem.&lt;/p>
&lt;h2 id="fermats-little-theorem">Fermat&amp;rsquo;s Little Theorem
&lt;/h2>&lt;p>This theorem, discovered by Pierre de Fermat, states the following:&lt;/p>
&lt;blockquote>
&lt;p>For any prime $p$ and any integer $a$ that is coprime to $p$ (not a multiple of $p$), the following congruence holds:
&lt;/p>
$$ a^{p-1} \equiv 1 \pmod p $$
&lt;/blockquote>
&lt;p>Taking the contrapositive of this theorem, we can say, &amp;ldquo;For a given integer $N$ and an integer $a$ coprime to $N$, if $a^{N-1} \not\equiv 1 \pmod N$, then $N$ is definitely a composite number.&amp;rdquo; The Fermat primality test uses this property by choosing a random base $a$ for the number $N$ to be tested, calculating $a^{N-1} \pmod N$, and checking if it equals $1$.&lt;/p>
&lt;h2 id="fast-modular-exponentiation-binary-exponentiation">Fast Modular Exponentiation (Binary Exponentiation)
&lt;/h2>&lt;p>To perform the Fermat test, we need to quickly compute the massive exponentiation $a^{N-1} \pmod N$. We use &amp;ldquo;Modular Exponentiation / Binary Exponentiation&amp;rdquo; for this. The time complexity is $O(\log N)$, making it extremely fast.&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">// Calculating a^b mod m using binary 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>Note: To prevent overflow here, we use &lt;code>__int128_t&lt;/code> (a 128-bit integer), which is an extension in GCC/Clang, to hold intermediate products.&lt;/li>
&lt;/ul>
&lt;h2 id="pseudoprimes-and-carmichael-numbers">Pseudoprimes and Carmichael Numbers
&lt;/h2>&lt;p>The Fermat test is very powerful, but it has a fatal flaw. There are numbers $N$ that are composite, yet $a^{N-1} \equiv 1 \pmod N$ holds for all $a$ (where $a$ is coprime to $N$).&lt;/p>
&lt;p>Such numbers are called &amp;ldquo;absolute pseudoprimes&amp;rdquo; or &amp;ldquo;Carmichael numbers.&amp;rdquo; The smallest Carmichael number is $561 = 3 \times 11 \times 17$.
Because Carmichael numbers exist, the Fermat test alone cannot provide a &amp;ldquo;100% probability&amp;rdquo; deterministic test. No matter how many different $a$&amp;rsquo;s you try, numbers like $561$ will always pretend to be prime (fooling the test).&lt;/p>
&lt;hr>
&lt;h1 id="3-miller-rabin-primality-test">3. Miller-Rabin Primality Test
&lt;/h1>&lt;p>The &amp;ldquo;Miller-Rabin Primality Test,&amp;rdquo; devised by Gary L. Miller and Michael O. Rabin, brilliantly overcame the weakness of the Fermat test (the existence of Carmichael numbers).
Currently, it is the most widely used practical fast primality testing algorithm in internal libraries of various programming languages and in key generation for cryptographic systems.&lt;/p>
&lt;h2 id="mathematical-principles">Mathematical Principles
&lt;/h2>&lt;p>The Miller-Rabin algorithm uses Fermat&amp;rsquo;s Little Theorem along with the property that &amp;ldquo;in a residue field modulo a prime ($\mathbb{Z}/p\mathbb{Z}$), the only solutions to $x^2 \equiv 1 \pmod p$ are $x \equiv 1$ or $x \equiv -1$&amp;rdquo; (if modulo a composite number, other non-trivial square roots may exist).&lt;/p>
&lt;p>Subtracting $1$ from the odd number $N$ you want to test always results in an even number, $N-1$. We divide $N-1$ by $2$ as many times as possible and express it in the following form:
&lt;/p>
$$ N-1 = d \cdot 2^s $$
&lt;p>
(Where $d$ is odd and $s \ge 1$)&lt;/p>
&lt;p>For any base $a$ ($1 &lt; a &lt; N-1$), we verify whether $a^{N-1} \equiv 1 \pmod N$ according to Fermat&amp;rsquo;s Little Theorem, but we perform the calculation in steps.
Specifically, we repeatedly square it in the order of $a^d, a^{d \cdot 2}, a^{d \cdot 4}, \ldots, a^{d \cdot 2^s}$.&lt;/p>
&lt;p>The conditions for the Miller-Rabin test to determine that $N$ is &amp;ldquo;prime (or probably prime with a high probability)&amp;rdquo; are that &lt;strong>either&lt;/strong> of the following holds true:&lt;/p>
&lt;ol>
&lt;li>$a^d \equiv 1 \pmod N$&lt;/li>
&lt;li>There exists some $r$ ($0 \le r &lt; s$) such that $a^{d \cdot 2^r} \equiv -1 \pmod N$.
&lt;ul>
&lt;li>Note: In C++ modulo arithmetic, $-1 \pmod N$ is $N-1$.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>If $N$ is a prime number, this condition will absolutely be satisfied for any $a$. Conversely, it has been mathematically proven that if $N$ is a composite number, the probability of satisfying this condition (the probability of being fooled) when a random $a$ is chosen is $\frac{1}{4}$ or less.
If we perform $k$ independent tests, the probability of a false positive becomes $\left(\frac{1}{4}\right)^k$ or less, which can practically be considered zero. There are no numbers like Carmichael numbers that can &amp;ldquo;absolutely deceive&amp;rdquo; the test.&lt;/p>
&lt;h2 id="algorithm-flow-of-the-miller-rabin-method-mermaid-flowchart">Algorithm Flow of the Miller-Rabin Method (Mermaid Flowchart)
&lt;/h2>&lt;p>The following diagram shows the logical flow of a single Miller-Rabin primality test (a test for a single base $a$).&lt;/p>
&lt;div class="mermaid">graph TD
Start["Start Test (Input: N, a)"] --> CalcDS["Calculate d (odd) and s such that N-1 = d * 2^s"]
CalcDS --> CalcX["Calculate x = a^d mod N"]
CalcX --> CheckX1{"x == 1 or x == N-1 ?"}
CheckX1 -- "Yes" --> ReturnTrue["Probably Prime"]
CheckX1 -- "No" --> LoopStart["Start loop for r = 1 to s-1"]
LoopStart --> LoopCondition{"r &lt; s ?"}
LoopCondition -- "No" --> ReturnFalse["Definitely Composite"]
LoopCondition -- "Yes" --> SquareX["Calculate x = (x * x) mod N"]
SquareX --> CheckXMinus1{"x == N - 1 ?"}
CheckXMinus1 -- "Yes" --> ReturnTrue
CheckXMinus1 -- "No" --> CheckXOne{"x == 1 ?"}
CheckXOne -- "Yes" --> ReturnFalse
CheckXOne -- "No" --> LoopNext["Increment r by 1 and continue"]
LoopNext --> LoopCondition&lt;/div>
&lt;hr>
&lt;h1 id="4-deterministic-testing-for-64-bit-integers">4. Deterministic Testing for 64-bit Integers
&lt;/h1>&lt;p>The Miller-Rabin primality test is inherently a &amp;ldquo;probabilistic&amp;rdquo; algorithm, but if the upper bound of $N$ is fixed, we can perform a &amp;ldquo;100% deterministic&amp;rdquo; primality test by trying a specific set of multiple $a$&amp;rsquo;s (bases).
This is called the &lt;strong>Deterministic Miller-Rabin Test&lt;/strong>.&lt;/p>
&lt;p>Research by Jim Sinclair and others has shown that for all integers $N &lt; 2^{64}$ (about $1.8 \times 10^{19}$), testing with the following $7$ prime numbers as bases $a$ is sufficient for a completely deterministic test.&lt;/p>
&lt;p>&lt;strong>List of bases $a$ to test:&lt;/strong>
&lt;code>{2, 325, 9375, 28178, 450775, 9780504, 1795265022}&lt;/code>&lt;/p>
&lt;p>Alternatively, another well-known set uses the following $12$ prime numbers, which can also perfectly test up to $N &lt; 2^{64}$.
&lt;code>{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}&lt;/code>&lt;/p>
&lt;p>This time, to enhance the simplicity and reliability of the algorithm, we will adopt the method based on the latter $12$ primes (or the more optimized $7$ bases). In our C++ implementation, we will optimize by dividing the range with conditional branches to minimize the number of tests.&lt;/p>
&lt;hr>
&lt;h1 id="5-highly-optimized-c-implementation">5. Highly Optimized C++ Implementation
&lt;/h1>&lt;p>Now, let&amp;rsquo;s synthesize the mathematical theory and algorithm design up to this point, and present the implementation code for a Miller-Rabin primality testing function that is at the highest level of performance in modern C++.&lt;/p>
&lt;h2 id="key-implementation-points">Key Implementation Points
&lt;/h2>&lt;ol>
&lt;li>
&lt;p>&lt;strong>Avoiding Overflow in 64-bit Integer Multiplication:&lt;/strong>
When $N \approx 10^{18}$, $x \times x$ in modular multiplication can be up to $10^{36}$, easily overflowing the maximum value of a standard 64-bit integer (&lt;code>uint64_t&lt;/code> or &lt;code>long long&lt;/code>), which is $1.8 \times 10^{19}$.
To solve this problem, we use the &lt;code>__int128_t&lt;/code> (or &lt;code>unsigned __int128&lt;/code>) extension type available in GCC and Clang to perform calculations with 128-bit precision before applying the modulo. This allows for fast modular multiplication without needing complex algorithms.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Selecting Deterministic Bases:&lt;/strong>
When the value of $N$ is small, we optimize it so that we only need to test a few bases.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h2 id="complete-c-source-code">Complete C++ Source Code
&lt;/h2>&lt;p>Below is the complete source code ready for practical use. You can copy and use this code directly in environments like competitive programming.&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">// Fast (a * b) mod m using 128-bit integers
&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">// Calculate (base^exp) mod m using binary 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">// Deterministic 64-bit integer test using Miller-Rabin primality test
&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">// Pre-checking boundary values and small primes
&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">// Decompose into the 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">// List of bases to use for testing
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// Optimization to minimize the number of bases tested depending on the size of N
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">uint64_t&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">bases&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">4759123141ULL&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bases&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">7&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">61&lt;/span>&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">1122004669633ULL&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bases&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">13&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">23&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1662803&lt;/span>&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 7 bases that make it deterministic for all numbers N &amp;lt; 2^64
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">bases&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">325&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">9375&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">28178&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">450775&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">9780504&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1795265022&lt;/span>&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Run the test for each base
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">uint64_t&lt;/span> &lt;span class="nl">a&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">bases&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span> &lt;span class="o">%=&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">continue&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// If a is a multiple of n, it is untestable but not a prime
&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">// Passed first condition, move to next base
&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">// Loop s-1 times (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">// Passed second condition, possibly prime
&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">// If it doesn&amp;#39;t satisfy any condition, it is definitely a composite number
&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">// If it passes the conditions for all bases, it is definitely prime
&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">// Test samples
&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">// Famous prime number
&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">// Famous prime number
&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">// Prime number around 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">// Composite number (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 number (composite number)
&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">// One of the largest prime numbers near 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-algorithm-complexity-and-performance-evaluation">6. Algorithm Complexity and Performance Evaluation
&lt;/h1>&lt;p>Let&amp;rsquo;s discuss the performance of the implemented algorithm.&lt;/p>
&lt;h2 id="time-complexity">Time Complexity
&lt;/h2>&lt;ul>
&lt;li>&lt;strong>Trial Division:&lt;/strong> $O(\sqrt{N})$&lt;/li>
&lt;li>&lt;strong>Fermat Test:&lt;/strong> Exponentiation calculation $O(\log N) \times k$ (where $k$ is the number of trials)&lt;/li>
&lt;li>&lt;strong>Miller-Rabin Method:&lt;/strong> Exponentiation calculation and looping $O(\log N) \times k$&lt;/li>
&lt;/ul>
&lt;p>In a 64-bit environment ($N \le 2^{64}$), the deterministic Miller-Rabin method above verifies at most $7$ bases. Therefore, we can treat $k \le 7$ as a constant, and the overall time complexity is strictly $O(\log N)$.
Even in the maximum case ($N \approx 10^{19}$), the number of execution steps is at most $7 \times 64 = 448$ basic operations, and the execution time is less than a few microseconds ($10^{-6}$ seconds). Compared to the $O(\sqrt{N})$ of trial division (loop iterations $\approx 4 \times 10^9$), a &lt;strong>speedup of several million times&lt;/strong> is achieved.&lt;/p>
&lt;h2 id="further-optimization-montgomery-multiplication">Further Optimization: Montgomery Multiplication
&lt;/h2>&lt;p>In the implementation of this article, division (modulo operation &lt;code>%&lt;/code>) is performed using the 128-bit integer extension type &lt;code>__int128_t&lt;/code>. Even on modern CPUs, integer division (DIV instruction) is an expensive instruction that takes tens of cycles compared to addition or multiplication.&lt;/p>
&lt;p>Library creators and competitive programmers seeking ultimate optimization sometimes adopt a method called &lt;strong>Montgomery Multiplication&lt;/strong>. Montgomery multiplication is an astonishing algorithm that maps numbers to a special &amp;ldquo;Montgomery space,&amp;rdquo; replacing expensive modulo operations (divisions) with &amp;ldquo;only bit shifts and multiplications.&amp;rdquo;
By incorporating this into the modular multiplication of the Miller-Rabin test, the execution speed can be further increased by a factor of 2 to 3. This is a very deep topic, so I would like to explain it in detail in another article.&lt;/p>
&lt;hr>
&lt;h1 id="7-conclusion">7. Conclusion
&lt;/h1>&lt;p>In this article, we covered everything from the basics of primality testing to advanced topics all at once.
Let&amp;rsquo;s review the key points.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Trial Division&lt;/strong> is reliable, but its time complexity of $O(\sqrt{N})$ makes it impractical when $N$ exceeds $10^{12}$.&lt;/li>
&lt;li>&lt;strong>Fermat&amp;rsquo;s Primality Test&lt;/strong> is extremely fast at $O(\log N)$, but it has a fatal flaw of being fooled by absolute pseudoprimes like Carmichael numbers.&lt;/li>
&lt;li>The &lt;strong>Miller-Rabin Primality Test&lt;/strong> is a practical and powerful algorithm that eliminates the weaknesses of the Fermat test.&lt;/li>
&lt;li>In the C++ implementation, leveraging &lt;code>__int128_t&lt;/code> allows for safe handling of 64-bit integer multiplication overflows.&lt;/li>
&lt;li>Within the range of 64-bit integers ($N &lt; 2^{64}$), choosing $7$ or $12$ specific primes as bases makes it possible to perform &lt;strong>deterministic (100% accurate) primality testing&lt;/strong>, rather than probabilistic.&lt;/li>
&lt;/ol>
&lt;p>Fast primality testing is an unavoidable technology in calculations dealing with massive numbers. The C++ Miller-Rabin source code provided in this article is robust enough to be used directly in practice. Please try using it in your own projects and algorithmic competitions.&lt;/p>
&lt;div class="mermaid">graph LR
TrialDivision["Trial Division (O(√N))"] --> Fermat["Fermat Test (O(log N), has flaws)"]
Fermat --> MillerRabin["Miller-Rabin Method (O(log N), can be deterministic)"]
MillerRabin --> Montgomery["+ Montgomery Multiplication (Constant factor speedup)"]
style MillerRabin fill:#f9f,stroke:#333,stroke-width:2px&lt;/div>
&lt;p>The world of algorithms, where programming and mathematics intersect, is incredibly beautiful and profound. I hope this helps you in your future studies.&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>[Math Explanation] Explaining How RSA Encryption Works So Even a High Schooler Can Understand</title><link>http://kenji.blog/en/p/rsa-encryption-math-explained-for-beginners/</link><pubDate>Fri, 11 Sep 2026 13:00:00 +0900</pubDate><guid>http://kenji.blog/en/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 [Math Explanation] Explaining How RSA Encryption Works So Even a High Schooler Can Understand" />&lt;p>One of the technologies supporting the safety of our internet society from the ground up is &amp;ldquo;RSA Encryption&amp;rdquo;. Many of the communications we casually use every day, such as credit card payments in online shopping, SNS exchanges with friends, and the transmission/reception of company confidential information, are protected by this RSA encryption and its successor technologies.&lt;/p>
&lt;p>However, when you hear the word &amp;ldquo;cryptography&amp;rdquo;, you might imagine complex cipher machines like those in spy movies, or super advanced mathematics that only a few geniuses can understand. It is true that modern cryptographic theory is based on advanced mathematics, but &lt;strong>the fundamental mechanism of RSA encryption can be fully understood if you have the knowledge of high school mathematics (properties of integers, prime numbers, congruences, etc.)&lt;/strong>.&lt;/p>
&lt;p>In this article, taking high school math knowledge as a starting point, I will thoroughly explain step-by-step the mathematical principles by which RSA encryption operates and why it is so difficult to crack. I will explain carefully with concrete examples so that even those who are not very good at math can understand.&lt;/p>
&lt;hr>
&lt;h2 id="1-symmetric-key-and-public-key-cryptography">1. Symmetric-key and Public-key Cryptography
&lt;/h2>&lt;p>Before getting into the mathematical mechanisms of RSA encryption, let&amp;rsquo;s first organize the basic ideas of cryptography. Cryptographic methods can be broadly divided into two types: &amp;ldquo;Symmetric-key Cryptography&amp;rdquo; and &amp;ldquo;Public-key Cryptography&amp;rdquo;.&lt;/p>
&lt;h3 id="11-limitations-of-symmetric-key-cryptography">1.1 Limitations of Symmetric-key Cryptography
&lt;/h3>&lt;p>Many of the traditionally used ciphers are what is called the &amp;ldquo;Symmetric-key Cryptography&amp;rdquo; method. This is a method that uses &lt;strong>the same key for both &amp;ldquo;encryption (converting a message into secret ciphertext)&amp;rdquo; and &amp;ldquo;decryption (restoring the ciphertext back to the original message)&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;p>For example, suppose Alice sends a secret letter to Bob. Alice uses a padlock (symmetric key) to put the letter in a box and lock it. In order for Bob to open that box, he needs to have the exact same key that Alice used.&lt;/p>
&lt;p>There is a major problem with this method. It is the &amp;ldquo;key distribution problem&amp;rdquo;. When Alice and Bob, who are far apart, communicate for the first time, how should they share the key without it being eavesdropped on? If the key is stolen by a third party while being mailed, all subsequent encrypted communications will be completely leaked.&lt;/p>
&lt;h3 id="12-the-breakthrough-invention-public-key-cryptography">1.2 The Breakthrough Invention: &amp;ldquo;Public-key Cryptography&amp;rdquo;
&lt;/h3>&lt;p>&amp;ldquo;Public-key Cryptography&amp;rdquo; was invented to solve this key distribution problem. RSA encryption is also one of this kind.&lt;/p>
&lt;p>In public-key cryptography, we use &lt;strong>two different keys: a &amp;ldquo;key for encryption (public key)&amp;rdquo; and a &amp;ldquo;key for decryption (private key)&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;ol>
&lt;li>The receiver, Bob, creates a pair of &amp;ldquo;public key&amp;rdquo; and &amp;ldquo;private key&amp;rdquo;.&lt;/li>
&lt;li>Bob publishes the &amp;ldquo;public key&amp;rdquo; to the world (it doesn&amp;rsquo;t matter who gets it).&lt;/li>
&lt;li>The sender, Alice, encrypts her message using Bob&amp;rsquo;s &amp;ldquo;public key&amp;rdquo; and sends it.&lt;/li>
&lt;li>The encrypted message can only be decrypted with the &amp;ldquo;private key&amp;rdquo; that only Bob possesses.&lt;/li>
&lt;/ol>
&lt;p>Comparing this to padlocks, Bob makes many &amp;ldquo;open padlocks (public keys)&amp;rdquo; and scatters them all over the world. Alice puts her message addressed to Bob into a box and snaps it shut using a padlock of Bob&amp;rsquo;s that she picked up. Once the padlock is closed, it can only be opened with the &amp;ldquo;master key (private key)&amp;rdquo; that Bob holds. Even if someone steals the box on the way, they cannot open it because they don&amp;rsquo;t have the master key.&lt;/p>
&lt;div class="mermaid">graph TD
A["Alice (Sender)"] --> B["Plaintext (Message)"]
B --> C["Encryption Process"]
D["Bob's Public Key (Available to anyone)"] --> C
C --> E["Send via Internet: Ciphertext"]
E --> F["Decryption Process"]
G["Bob's Private Key (Held only by Bob)"] --> F
F --> H["Restored Plaintext (Message)"]
H --> I["Bob (Receiver)"]&lt;/div>
&lt;p>In order to realize this epoch-making system, a kind of &lt;strong>&amp;ldquo;one-way function (a one-way mathematical puzzle)&amp;rdquo;&lt;/strong> is necessary, one where &amp;ldquo;encryption with the public key is easy, but decryption without the private key is absolutely impossible.&amp;rdquo; What was focused on as a component of that puzzle was the &amp;ldquo;prime numbers&amp;rdquo; we all know so well.&lt;/p>
&lt;hr>
&lt;h2 id="2-the-mathematical-foundation-supporting-rsa-1-prime-numbers-and-prime-factorization">2. The Mathematical Foundation Supporting RSA 1: Prime Numbers and Prime Factorization
&lt;/h2>&lt;p>The security of RSA encryption is based on the mathematical fact that &lt;strong>&amp;ldquo;prime factorization of huge numbers is extremely difficult.&amp;rdquo;&lt;/strong>&lt;/p>
&lt;h3 id="21-what-are-prime-numbers">2.1 What are Prime Numbers?
&lt;/h3>&lt;p>A prime number is &amp;ldquo;a natural number greater than 1 that can only be divided by 1 and itself.&amp;rdquo;
Example: $2, 3, 5, 7, 11, 13, 17, 19, 23...$&lt;/p>
&lt;p>Prime numbers are like the &amp;ldquo;atoms&amp;rdquo; of all integers. Any natural number can be broken down into the product of prime numbers. This is called &lt;strong>prime factorization&lt;/strong>. For example, it is known as the &amp;ldquo;Fundamental Theorem of Arithmetic&amp;rdquo; that a number can be uniquely factorized into primes (ignoring order), such as $60 = 2^2 \times 3 \times 5$.&lt;/p>
&lt;h3 id="22-the-difficulty-of-prime-factorization-one-way-function">2.2 The Difficulty of Prime Factorization (One-way Function)
&lt;/h3>&lt;p>What&amp;rsquo;s important here is the asymmetry that &lt;strong>&amp;ldquo;multiplication is easy, but prime factorization is difficult.&amp;rdquo;&lt;/strong>&lt;/p>
&lt;p>For example, try doing mental arithmetic for the multiplication of the following two prime numbers.
$11 \times 13 = ?$
This is easy. The answer is $143$.&lt;/p>
&lt;p>Then, how about the following number?
Please prime factorize $323$.
How is it? It should take a little time. (The answer is $17 \times 19$).&lt;/p>
&lt;p>If the numbers are small, humans can manage to calculate them, but as the numbers get larger, it becomes explosively difficult to calculate even using computers. In mainstream RSA encryption today, we use a number $N = p \times q$, which is the product of two incredibly huge prime numbers $p$ and $q$ of 2048 bits (about 600 digits in decimal).&lt;/p>
&lt;p>Given two huge prime numbers $p$ and $q$, it takes an instant (less than a millisecond) for a computer to calculate $N$. However, conversely, given only $N$, finding the original $p$ and $q$ takes so much time that even the current fastest supercomputer could not solve it if it ran for trillions of years.&lt;/p>
&lt;p>This &lt;strong>&amp;ldquo;computational asymmetry (one way is easy, the reverse is difficult)&amp;rdquo;&lt;/strong> is the foundation that creates the relationship between the public key and the private key.&lt;/p>
&lt;hr>
&lt;h2 id="3-the-mathematical-foundation-supporting-rsa-2-congruence-modulo-arithmetic">3. The Mathematical Foundation Supporting RSA 2: Congruence (Modulo Arithmetic)
&lt;/h2>&lt;p>The calculations for RSA encryption are not done with addition or multiplication where numbers grow infinitely like we normally use, but rather in a world of &amp;ldquo;remainders&amp;rdquo; after dividing by a certain number. This is called &lt;strong>congruence (modulo arithmetic)&lt;/strong>.&lt;/p>
&lt;h3 id="31-clock-math">3.1 Clock Math
&lt;/h3>&lt;p>Modulo arithmetic is often compared to &amp;ldquo;clock math&amp;rdquo;. If it is currently 10 o&amp;rsquo;clock, what time will it be 5 hours from now? $10 + 5 = 15$ o&amp;rsquo;clock, but on a normal 12-hour clock, we answer &amp;ldquo;3 o&amp;rsquo;clock&amp;rdquo;. This is because the remainder of 15 divided by 12 is 3.&lt;/p>
&lt;p>In the world of mathematics, this is written as follows:
&lt;/p>
$$ 15 \equiv 3 \pmod{12} $$
&lt;p>
You read this as &amp;ldquo;15 is congruent to 3 modulo 12 (the remainder when divided by 12 is equal).&amp;rdquo;&lt;/p>
&lt;h3 id="32-basic-properties-of-congruences">3.2 Basic Properties of Congruences
&lt;/h3>&lt;p>Congruences have very convenient properties very similar to equalities ($=$). Let the modulus (the divisor) be $N$.
When $a \equiv b \pmod N$ and $c \equiv d \pmod N$, the following hold true:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Addition:&lt;/strong> $a + c \equiv b + d \pmod N$&lt;/li>
&lt;li>&lt;strong>Subtraction:&lt;/strong> $a - c \equiv b - d \pmod N$&lt;/li>
&lt;li>&lt;strong>Multiplication:&lt;/strong> $a \times c \equiv b \times d \pmod N$&lt;/li>
&lt;li>&lt;strong>Exponentiation:&lt;/strong> $a^k \equiv b^k \pmod N$ ($k$ is a natural number)&lt;/li>
&lt;/ol>
&lt;p>Particularly important is the property of &amp;ldquo;exponentiation&amp;rdquo;. This means that &lt;strong>&amp;ldquo;the power of a remainder is equal to the remainder of the power&amp;rdquo;&lt;/strong>.
For example, suppose you want to find the remainder of $7^{100}$ divided by $5$. Multiplying $7$ a hundred times and then dividing by $5$ in earnest is very hard, but if you use the properties of congruences, since $7 \equiv 2 \pmod 5$, it becomes $7^{100} \equiv 2^{100} \pmod 5$, and you can drastically simplify the calculation. This property is indispensable in the world of cryptography because we deal with exponentiations of very large numbers.&lt;/p>
&lt;hr>
&lt;h2 id="4-the-mathematical-foundation-supporting-rsa-3-eulers-totient-function-and-eulers-theorem">4. The Mathematical Foundation Supporting RSA 3: Euler&amp;rsquo;s Totient Function and Euler&amp;rsquo;s Theorem
&lt;/h2>&lt;p>From here on is the magic mathematics that forms the core of RSA encryption. &amp;ldquo;Euler&amp;rsquo;s Theorem&amp;rdquo;, a generalization of &amp;ldquo;Fermat&amp;rsquo;s Little Theorem&amp;rdquo;, makes its appearance.&lt;/p>
&lt;h3 id="41-eulers-totient-function-phin">4.1 Euler&amp;rsquo;s Totient Function $\phi(N)$
&lt;/h3>&lt;p>For a given natural number $N$, Euler&amp;rsquo;s totient function (the $\phi$ function) is a function that returns &lt;strong>&amp;ldquo;the number of natural numbers from 1 to $N$ that are coprime with $N$ (meaning their greatest common divisor is 1).&amp;rdquo;&lt;/strong>&lt;/p>
&lt;p>Let&amp;rsquo;s look at some examples.&lt;/p>
&lt;ul>
&lt;li>$\phi(5)$: Among 1, 2, 3, 4, 5, the numbers coprime with 5 are 1, 2, 3, 4, which is 4 numbers. Therefore, $\phi(5) = 4$.&lt;/li>
&lt;li>$\phi(6)$: Among 1, 2, 3, 4, 5, 6, the numbers coprime with 6 are 1, 5, which is 2 numbers. Therefore, $\phi(6) = 2$.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>[Special Property in the Case of Prime Numbers]&lt;/strong>
If $p$ is a prime number, all numbers from 1 to $p-1$ are coprime with $p$. Therefore,
&lt;/p>
$$ \phi(p) = p - 1 $$
&lt;p>&lt;strong>[Special Property in the Case of the Product of Prime Numbers]&lt;/strong>
For two distinct prime numbers $p$ and $q$, if $N = p \times q$, $\phi(N)$ can be easily calculated as follows.
&lt;/p>
$$ \phi(N) = \phi(p) \times \phi(q) = (p - 1)(q - 1) $$
&lt;p>
This property functions as the &amp;ldquo;secret backdoor (trapdoor)&amp;rdquo; in RSA encryption. The person who knows $p$ and $q$ (the creator of the key) can calculate $\phi(N)$ instantly, but a third party who only knows $N$ cannot determine $\phi(N)$ unless they prime factorize $N$.&lt;/p>
&lt;h3 id="42-eulers-theorem">4.2 Euler&amp;rsquo;s Theorem
&lt;/h3>&lt;p>Leonhard Euler used this $\phi(N)$ to prove the following beautiful theorem.&lt;/p>
&lt;p>&lt;strong>Euler&amp;rsquo;s Theorem:&lt;/strong>
When the integer $a$ and $N$ are coprime, the following congruence holds.
&lt;/p>
$$ a^{\phi(N)} \equiv 1 \pmod N $$
&lt;p>This is an amazing property that says, &amp;ldquo;If you multiply a number $a$ by itself $\phi(N)$ times and divide by $N$, the remainder will always be $1$.&amp;rdquo; (When $N$ is a prime number $p$, it becomes $a^{p-1} \equiv 1 \pmod p$, which is called Fermat&amp;rsquo;s Little Theorem).&lt;/p>
&lt;p>Let&amp;rsquo;s modify this Euler&amp;rsquo;s Theorem. Multiply both sides by $a$ one more time.
&lt;/p>
$$ a^{\phi(N) + 1} \equiv a \pmod N $$
&lt;p>Furthermore, for any integer $k$, since $a^{k \cdot \phi(N)}$ also becomes $1^k = 1$, the following equation holds.
&lt;/p>
$$ a^{k \cdot \phi(N) + 1} \equiv a \pmod N $$
&lt;p>This very equation is the fundamental principle that makes the magic of RSA encryption work: &lt;strong>&amp;ldquo;If you encrypt and then decrypt, it returns to the original.&amp;rdquo;&lt;/strong>&lt;/p>
&lt;hr>
&lt;h2 id="5-the-rsa-algorithm-steps-for-key-generation-encryption-and-decryption">5. The RSA Algorithm: Steps for Key Generation, Encryption, and Decryption
&lt;/h2>&lt;p>Now that we have the basic knowledge, let&amp;rsquo;s finally look at the specific steps of RSA encryption. RSA encryption is roughly divided into three phases: &amp;ldquo;1. Key Generation,&amp;rdquo; &amp;ldquo;2. Encryption,&amp;rdquo; and &amp;ldquo;3. Decryption.&amp;rdquo;&lt;/p>
&lt;div class="mermaid">flowchart TD
A1["1. Choose prime numbers p, q"] --> A2["Calculate N = p × q"]
A1 --> A3["Calculate φ(N) = (p-1)(q-1)"]
A3 --> A4["Choose e coprime with φ(N)"]
A3 --> A5["Calculate d such that e × d ≡ 1 (mod φ(N))"]
A2 --> A6["Public Key (N, e)"]
A4 --> A6
A5 --> A7["Private Key d"]
B1["2. Plaintext message M"] --> B2["Calculate C ≡ M^e (mod N)"]
A6 -.-> B2
B2 --> B3["Send ciphertext C"]
B3 --> C1["3. Received ciphertext C"]
C1 --> C2["Calculate M ≡ C^d (mod N)"]
A7 -.-> C2
C2 --> C3["Obtain original plaintext message M"]&lt;/div>
&lt;h3 id="51-key-generation">5.1 Key Generation
&lt;/h3>&lt;p>The receiver, Bob, generates a &amp;ldquo;public key&amp;rdquo; and a &amp;ldquo;private key&amp;rdquo; for himself.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Choice of Primes:&lt;/strong> Randomly choose two large prime numbers $p$ and $q$.&lt;/li>
&lt;li>&lt;strong>Calculation of Modulus $N$:&lt;/strong> Calculate $N = p \times q$. This $N$ is made public.&lt;/li>
&lt;li>&lt;strong>Calculation of $\phi(N)$:&lt;/strong> Calculate Euler&amp;rsquo;s function $\phi(N) = (p - 1)(q - 1)$. This is a secret number only Bob knows.&lt;/li>
&lt;li>&lt;strong>Choice of Public Key $e$:&lt;/strong> Choose an integer $e$ such that $1 &lt; e &lt; \phi(N)$ and $e$ is coprime with $\phi(N)$.&lt;/li>
&lt;li>&lt;strong>Calculation of Private Key $d$:&lt;/strong> Find an integer $d$ that satisfies the following condition.
$$ e \times d \equiv 1 \pmod{\phi(N)} $$
In other words, this is &amp;ldquo;a number $d$ such that the remainder is $1$ when $e \times d$ is divided by $\phi(N)$.&amp;rdquo;&lt;/li>
&lt;/ol>
&lt;p>Now the key preparation is complete.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Public Key:&lt;/strong> The pair $(N, e)$. It is published to the whole world.&lt;/li>
&lt;li>&lt;strong>Private Key:&lt;/strong> $d$. Never tell anyone under any circumstances.&lt;/li>
&lt;/ul>
&lt;h3 id="52-encryption">5.2 Encryption
&lt;/h3>&lt;p>Suppose Alice wants to send a secret message $M$ to Bob. (Let $M$ be a number formed by digitizing characters, and assume $0 \le M &lt; N$). Alice calculates as follows using Bob&amp;rsquo;s public key $(N, e)$.&lt;/p>
$$ C \equiv M^e \pmod N $$
&lt;p>She calculates &amp;ldquo;the remainder $C$ when message $M$ is raised to the power of $e$, divided by $N$&amp;rdquo;. This $C$ is the ciphertext.&lt;/p>
&lt;h3 id="53-decryption">5.3 Decryption
&lt;/h3>&lt;p>Bob receives the ciphertext $C$. Bob calculates as follows using his private key $d$.&lt;/p>
$$ M \equiv C^d \pmod N $$
&lt;p>By calculating &amp;ldquo;the remainder when ciphertext $C$ is raised to the power of $d$, divided by $N$&amp;rdquo;, amazingly, the original message $M$ is restored!&lt;/p>
&lt;hr>
&lt;h2 id="6-why-does-decryption-revert-it-to-the-original-mathematical-proof">6. Why Does Decryption Revert it to the Original? (Mathematical Proof)
&lt;/h2>&lt;p>You might be wondering, &amp;ldquo;Why does simply raising $C$ to the power of $d$ return it to the original $M$?&amp;rdquo; This is where the aforementioned &amp;ldquo;Euler&amp;rsquo;s Theorem&amp;rdquo; demonstrates its power.&lt;/p>
&lt;p>Let&amp;rsquo;s substitute the encryption formula $C = M^e$ into the decryption calculation formula $C^d \pmod N$.
&lt;/p>
$$ C^d \equiv (M^e)^d \equiv M^{ed} \pmod N $$
&lt;p>Here, recall Step 5 of the key generation. When Bob made $d$, he chose it so that $e \times d \equiv 1 \pmod{\phi(N)}$. This means &amp;ldquo;the number $ed$ is a multiple of $\phi(N)$ plus $1$.&amp;rdquo; Using an integer $k$, it can be written as follows:
&lt;/p>
$$ ed = k \cdot \phi(N) + 1 $$
&lt;p>Substitute this into the exponent part, and decompose it using exponent rules.
&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>Here, assuming that the message $M$ and $N$ are coprime, from &lt;strong>Euler&amp;rsquo;s Theorem&lt;/strong>, we get $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>Therefore, the following formula beautifully holds true.
&lt;/p>
$$ C^d \equiv M \pmod N $$
&lt;p>Alice does not know $d$, and an eavesdropper does not know $d$ either, so only Bob, who has $d$, can extract $M$ from $C$.&lt;/p>
&lt;hr>
&lt;h2 id="7-concrete-example-experiencing-rsa-by-hand-calculation-using-small-primes">7. Concrete Example: Experiencing RSA by Hand Calculation Using Small Primes
&lt;/h2>&lt;p>Let&amp;rsquo;s actually try encrypted communication from Alice to Bob using small numbers (prime numbers).&lt;/p>
&lt;p>&lt;strong>[Bob&amp;rsquo;s Key Generation Phase]&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>Choose two prime numbers $p=11$, $q=13$.&lt;/li>
&lt;li>Calculate $N = 11 \times 13 = 143$.&lt;/li>
&lt;li>Calculate $\phi(N) = (11 - 1) \times (13 - 1) = 10 \times 12 = 120$.&lt;/li>
&lt;li>Choose a public key $e$ that is coprime with $\phi(N)=120$. Here we will use $e=7$.&lt;/li>
&lt;li>Find the private key $d$. Look for $d$ such that $7 \times d \equiv 1 \pmod{120}$.
In the equation $7d = 120k + 1$, when $k=6$, it becomes $721$, and $721 \div 7 = 103$.
Therefore, $d = 103$.&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>Public Key: $(N=143, e=7)$&lt;/li>
&lt;li>Private Key: $d=103$&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>[Alice&amp;rsquo;s Encryption Phase]&lt;/strong>
Suppose she wants to send the message $M = 9$.
Formula: $C \equiv 9^7 \pmod{143}$
$9^7 = 4,782,969$. Dividing this by 143 gives $33447$ with a remainder of $48$.
The ciphertext became $C = 48$.&lt;/p>
&lt;p>&lt;strong>[Bob&amp;rsquo;s Decryption Phase]&lt;/strong>
Bob receives the ciphertext $C = 48$ and decrypts it using his private key $d = 103$.
Formula: $M \equiv 48^{103} \pmod{143}$
If you run &lt;code>(48 ** 103) % 143&lt;/code> on a calculator, the result wonderfully turns out to be &amp;ldquo;&lt;strong>9&lt;/strong>&amp;rdquo;! The original message was successfully received.&lt;/p>
&lt;hr>
&lt;h2 id="8-how-to-find-the-private-key-d-extended-euclidean-algorithm">8. How to Find the Private Key $d$: Extended Euclidean Algorithm
&lt;/h2>&lt;p>In the hand calculation example, we found $d=103$ by guessing to find $k$, but this method is impossible when the numbers are hundreds of digits long. In actual programs, an algorithm called the &lt;strong>&amp;ldquo;Extended Euclidean Algorithm&amp;rdquo;&lt;/strong> is used.&lt;/p>
&lt;p>Solving $7d \equiv 1 \pmod{120}$ is the same as finding integers $d, y$ that satisfy $7d + 120y = 1$. By working backwards through the Euclidean Algorithm, this can be calculated mechanically.&lt;/p>
&lt;ol>
&lt;li>$120 \div 7 = 17$ remainder $1$&lt;/li>
&lt;li>Transforming this, $1 = 120 - 17 \times 7$&lt;/li>
&lt;li>In other words, $-17 \times 7 \equiv 1 \pmod{120}$&lt;/li>
&lt;/ol>
&lt;p>In the world of modulo $120$, $-17$ has the same meaning as $120 - 17 = 103$. Therefore, $d = 103$ is found in an instant. This method can calculate very quickly no matter how huge the numbers are.&lt;/p>
&lt;hr>
&lt;h2 id="9-another-face-of-rsa-encryption-digital-signatures">9. Another Face of RSA Encryption: Digital Signatures
&lt;/h2>&lt;p>The wonderful thing about RSA encryption is that it can also be used as a &lt;strong>&amp;ldquo;digital signature&amp;rdquo;&lt;/strong> by reversing the roles of the public and private keys.&lt;/p>
&lt;p>When encrypting, it was &amp;ldquo;Encrypt with public key $\Rightarrow$ Decrypt with private key&amp;rdquo;, but
for digital signatures, it takes the steps &amp;ldquo;Encrypt with private key $\Rightarrow$ Decrypt with public key&amp;rdquo;.&lt;/p>
&lt;div class="mermaid">flowchart TD
A1["1. Alice creates a signature with her private key"] --> A2["S ≡ M^d (mod N)"]
A2 --> A3["Sends the message M and signature S"]
A3 --> B1["2. Bob verifies the signature with the public key"]
B1 --> B2["Calculates M' ≡ S^e (mod N)"]
B2 --> B3["Checks if M' matches M"]&lt;/div>
&lt;p>Alice transforms the message using her own private key $d$ (this is the signature $S$), and sends it to Bob. Bob performs the verification calculation using Alice&amp;rsquo;s public key $e$. If the calculation result matches the original message, it simultaneously proves that &amp;ldquo;it is data that could only be created with Alice&amp;rsquo;s private key&amp;rdquo; and that &amp;ldquo;the message has not been tampered with along the way&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="10-experiencing-rsa-encryption-with-programming">10. Experiencing RSA Encryption with Programming
&lt;/h2>&lt;p>Exponentiation calculations that are tough by hand can be implemented very easily using Python. Below is a Python code that lets you experience the core logic of RSA encryption.&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;Find the greatest common divisor&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;Find the private key d (using built-in feature in 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. Key Generation&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;Public Key: (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">), Private Key: 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. Encryption&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;Ciphertext: &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. Decryption&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;Decrypted Message: &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>Python&amp;rsquo;s &lt;code>pow(base, exp, mod)&lt;/code> function internally uses a fast algorithm called &amp;ldquo;Exponentiation by squaring&amp;rdquo;, so calculations finish in an instant even for numbers with hundreds of digits.&lt;/p>
&lt;hr>
&lt;h2 id="11-conclusion-and-future-cryptographic-technology">11. Conclusion and Future Cryptographic Technology
&lt;/h2>&lt;p>Based on the knowledge of high school mathematics, we have uncovered how RSA encryption works.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Difficulty of Prime Factorization:&lt;/strong> $p \times q = N$ is easy, but finding $p, q$ from $N$ is extremely difficult.&lt;/li>
&lt;li>&lt;strong>Congruence and Euler&amp;rsquo;s Theorem:&lt;/strong> With the rule $a^{\phi(N)} \equiv 1 \pmod N$, the magic trapdoor &amp;ldquo;raising to a certain power brings it back to the original&amp;rdquo; is completed.&lt;/li>
&lt;li>&lt;strong>Public and Private Keys:&lt;/strong> Anyone can encrypt, but only the legitimate receiver can decrypt.&lt;/li>
&lt;/ol>
&lt;p>The $N$ in currently used RSA encryption has over 600 digits, and even mobilizing all the supercomputers in the world, prime factorization would take more time than the age of the universe. However, when the &amp;ldquo;quantum computers&amp;rdquo; currently being researched become practical in the future, there is a possibility that this prime factorization will be solved in an instant by &amp;ldquo;Shor&amp;rsquo;s algorithm&amp;rdquo;. For this reason, the development of &amp;ldquo;Post-quantum cryptography&amp;rdquo; that cannot be cracked even by quantum computers is progressing rapidly worldwide.&lt;/p>
&lt;p>Advanced mathematics, which is often thought of as &amp;ldquo;useless,&amp;rdquo; is actually protecting our daily lives from the ground up. RSA encryption is the best teaching material to show us the depth and beauty of such mathematics. I hope this article has helped you feel the fascination of cryptography and mathematics, even just a little.&lt;/p></description></item><item><title>What is Fully Homomorphic Encryption (FHE)? Explaining the Keystone of Next-Generation Security</title><link>http://kenji.blog/en/p/fully-homomorphic-encryption-fhe-explained/</link><pubDate>Fri, 11 Sep 2026 11:00:00 +0900</pubDate><guid>http://kenji.blog/en/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 What is Fully Homomorphic Encryption (FHE)? Explaining the Keystone of Next-Generation Security" />&lt;p>As cloud computing and AI technologies become established as societal infrastructure, the tradeoff between &amp;ldquo;data privacy&amp;rdquo; and &amp;ldquo;data utilization&amp;rdquo; has become one of the most critical challenges. While there is a growing demand to have AI analyze highly sensitive data—such as medical records, financial information, and personal biometric data—on the cloud, many companies hesitate to send data externally due to security concerns.&lt;/p>
&lt;p>Traditional encryption technologies (like AES and RSA) excel at protecting data stored in storage (Data at Rest) and data flowing over networks (Data in Transit). However, &lt;strong>when performing processing (computations) such as searching or machine learning on the server side (Data in Use), the ciphertext must first be decrypted back into plaintext&lt;/strong>. If the server is hacked at this decrypted moment, or if a malicious internal administrator peeks at the data, it directly leads to information leakage.&lt;/p>
&lt;p>The dream technology that overcomes this fundamental weakness of &amp;ldquo;decryption during processing&amp;rdquo; is &lt;strong>Fully Homomorphic Encryption (FHE)&lt;/strong>. By using FHE, it becomes possible to perform computational processing while keeping the data encrypted, without ever decrypting it, and returning only the resulting ciphertext to the client.&lt;/p>
&lt;p>In this article, we will thoroughly and deeply explain FHE, the keystone of next-generation security, covering everything from its concept and history, the groundbreaking breakthrough by Craig Gentry, mathematical foundations (such as Ring-LWE), its biggest challenge &amp;ldquo;noise&amp;rdquo; and its solution (bootstrapping), up to the latest implementation libraries.&lt;/p>
&lt;hr>
&lt;h2 id="1-what-is-homomorphic-encryption-basic-concepts">1. What is Homomorphic Encryption? Basic Concepts
&lt;/h2>&lt;p>&amp;ldquo;Homomorphic&amp;rdquo; is an algebraic term referring to the property where mappings can be made between sets with a certain structure while preserving the structure of the operations. &amp;ldquo;Homomorphism&amp;rdquo; in cryptography is the property where &lt;strong>operations in the plaintext space correspond to operations in the ciphertext space&lt;/strong>.&lt;/p>
&lt;p>Expressed in simple formulas, let $m_1$ and $m_2$ be plaintexts, $E(\cdot)$ be the encryption function, and $D(\cdot)$ be the decryption function. If we let $\circ$ be an operation on the plaintext (such as addition or multiplication) and $\diamond$ be an operation on the ciphertext, the following relationship holds:&lt;/p>
$$ D(E(m_1) \diamond E(m_2)) = m_1 \circ m_2 $$
&lt;p>In other words, if you decrypt the result of applying some operation $\diamond$ to the ciphertexts $E(m_1)$ and $E(m_2)$, it matches the result of operating $\circ$ on the original plaintexts.&lt;/p>
&lt;h3 id="data-flow-in-cloud-computing">Data Flow in Cloud Computing
&lt;/h3>&lt;p>The architecture of cloud processing using FHE is completely different from traditional ones. The following diagram shows the flow of secure data processing utilizing FHE.&lt;/p>
&lt;div class="mermaid">graph TD
A["Client (Holds secret key)"] -->|1. Encrypt plaintext x: E(x)| B["Cloud Server (Encrypted data only)"]
B -->|2. Apply function f to ciphertext: E(f(x))| B
B -->|3. Ciphertext of calculation result E(y)| A
A -->|4. Decrypt with secret key: y = f(x)| A
style A fill:#d4edda,stroke:#28a745
style B fill:#f8d7da,stroke:#dc3545&lt;/div>
&lt;p>The server receives the encrypted data $E(x)$, but since it does not have the secret key, it can never know the contents of the data. However, by utilizing the properties of FHE, it can apply a function $f$ (for example, an inference model for machine learning) to the ciphertext and generate $E(f(x))$. The client receives this and decrypts it with their own secret key to obtain the desired result $y = f(x)$.&lt;/p>
&lt;hr>
&lt;h2 id="2-history-of-homomorphic-encryption-evolution-phe-she-fhe">2. History of Homomorphic Encryption Evolution: PHE, SHE, FHE
&lt;/h2>&lt;p>Homomorphic encryption did not reach its current &amp;ldquo;fully&amp;rdquo; form all at once. It is broadly classified into three stages depending on the types and number of operations it can achieve.&lt;/p>
&lt;h3 id="partially-homomorphic-encryption-phe">Partially Homomorphic Encryption (PHE)
&lt;/h3>&lt;p>PHE is an encryption scheme that can perform &lt;strong>only one of either&lt;/strong> addition or multiplication indefinitely. In fact, ciphers with this property have existed for a long time.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>RSA Encryption (Homomorphism for multiplication)&lt;/strong>
RSA encryption unintentionally possessed a multiplicative homomorphic property. Given plaintexts $m_1, m_2$ and a public key $(e, N)$:
$$ E(m_1) = m_1^e \pmod N $$
$$ E(m_2) = m_2^e \pmod N $$
Multiplying these gives:
$$ E(m_1) \times E(m_2) = (m_1 \cdot m_2)^e \pmod N = E(m_1 \times m_2) $$
Thus, the multiplication of ciphertexts corresponds to the multiplication of plaintexts.&lt;/li>
&lt;li>&lt;strong>Paillier Encryption (Homomorphism for addition)&lt;/strong>
The Paillier cryptosystem, invented in 1999, has an additive homomorphic property. It has been put to practical use in applications like electronic voting (aggregating encrypted votes and decrypting only the final result).&lt;/li>
&lt;/ul>
&lt;h3 id="somewhat-homomorphic-encryption-she">Somewhat Homomorphic Encryption (SHE)
&lt;/h3>&lt;p>This scheme can execute &lt;strong>both&lt;/strong> addition and multiplication, but there is a &lt;strong>limit to the number of operations (circuit depth)&lt;/strong> that can be performed. Due to the accumulation of &amp;ldquo;noise,&amp;rdquo; which will be discussed later, decryption becomes impossible after a certain number of multiplications. The BGN (Boneh-Goh-Nissim) cryptosystem of 2005 falls under this category, but it had limitations in performing practical, complex computations (like deep learning).&lt;/p>
&lt;h3 id="fully-homomorphic-encryption-fhe">Fully Homomorphic Encryption (FHE)
&lt;/h3>&lt;p>This is an encryption scheme that can execute both addition and multiplication an &lt;strong>unlimited number of times&lt;/strong>. Similar to Turing completeness in information theory, if addition (equivalent to XOR) and multiplication (equivalent to AND) can be combined infinitely, it means that in principle, any computable function or algorithm can be executed while remaining encrypted.&lt;/p>
&lt;p>FHE was long called the &amp;ldquo;holy grail of cryptography&amp;rdquo; and was even said to be impossible to realize. However, in 2009, &lt;strong>Craig Gentry&lt;/strong>, who was a doctoral student at Stanford University at the time, proposed the first FHE scheme using Ideal Lattices, sending shockwaves through the world.&lt;/p>
&lt;hr>
&lt;h2 id="3-mathematical-foundations-of-fhe-the-lwe-problem-and-ring-lwe">3. Mathematical Foundations of FHE: The LWE Problem and Ring-LWE
&lt;/h2>&lt;p>Many of the current mainstream FHE schemes are based on the &lt;strong>LWE (Learning With Errors) problem&lt;/strong>, a mathematical hard problem in &amp;ldquo;Lattice-based Cryptography,&amp;rdquo; which is also known as Post-Quantum Cryptography.&lt;/p>
&lt;h3 id="intuitive-understanding-of-the-lwe-problem">Intuitive Understanding of the LWE Problem
&lt;/h3>&lt;p>Solving a system of linear equations is easy if you use methods like Gaussian elimination.&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>However, what happens if we add a very small &amp;ldquo;random error (noise)&amp;rdquo; $e$ to the results of these equations?&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>With just the addition of this error $e$, the problem of finding the secret variable vector $\vec{s}$ transforms into an NP-hard problem that is difficult to decipher even using current supercomputers or quantum computers. This is the LWE problem.&lt;/p>
&lt;h3 id="ring-lwe-problem-rlwe">Ring-LWE Problem (RLWE)
&lt;/h3>&lt;p>The standard LWE problem involves matrix operations, which means the key size is extremely large (sometimes in gigabytes) and computational efficiency is poor. To solve this, the &lt;strong>Ring-LWE (RLWE) problem&lt;/strong>, which uses operations over polynomial rings, was introduced.&lt;/p>
&lt;p>In RLWE, elements belong to the polynomial ring $R_q = \mathbb{Z}_q[x] / (x^N + 1)$ (where $N$ is a power of 2, and $q$ is the modulus prime).
Let the secret key be a polynomial $s(x)$, and with a random polynomial $a(x)$ and a small noise polynomial $e(x)$, the public key becomes the following pair:&lt;/p>
$$ (a(x), b(x)) \quad \text{where} \quad b(x) = -a(x) \cdot s(x) + e(x) \pmod q $$
&lt;p>During encryption, the plaintext $m(x)$ is encoded using the properties of this polynomial to generate the ciphertext.&lt;/p>
&lt;hr>
&lt;h2 id="4-the-biggest-barrier-noise-and-gentrys-bootstrapping">4. The Biggest Barrier &amp;ldquo;Noise&amp;rdquo; and Gentry&amp;rsquo;s Bootstrapping
&lt;/h2>&lt;p>The most important concept in understanding FHE is &lt;strong>&amp;ldquo;noise management.&amp;rdquo;&lt;/strong>&lt;/p>
&lt;p>In LWE/RLWE-based cryptography, small &amp;ldquo;noise (errors)&amp;rdquo; are intentionally included to ensure security.
The process of decrypting a ciphertext $c$ of a plaintext $m$ can be roughly represented by the following formula:&lt;/p>
$$ D(c) = (c \cdot s) \pmod q = m + \text{noise} $$
&lt;p>During decryption, this &lt;code>noise&lt;/code> is removed through rounding processes or similar to obtain the correct plaintext $m$. However, when homomorphic operations (especially multiplication) are performed between ciphertexts, this noise is dramatically amplified.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Homomorphic Addition&lt;/strong>: Noise increases additively ($e_1 + e_2$). This is a relatively gradual increase.&lt;/li>
&lt;li>&lt;strong>Mathematical Representation of Homomorphism by Homomorphic Addition&lt;/strong>:
$$ E(m_1) \oplus E(m_2) = E(m_1 + m_2) $$&lt;/li>
&lt;li>&lt;strong>Homomorphic Multiplication&lt;/strong>: Noise explodes multiplicatively (because it includes terms like $e_1 \times e_2$). After just a few multiplications, the noise exceeds the threshold $q/2$, preventing correct rounding and causing decryption to fail.&lt;/li>
&lt;li>&lt;strong>Mathematical Representation of Homomorphism by Homomorphic Multiplication&lt;/strong>:
$$ E(m_1) \otimes E(m_2) = E(m_1 \times m_2) $$&lt;/li>
&lt;/ul>
&lt;p>This is the reason why FHE could not be realized for a long time and remained at the level of SHE (with a limited number of operations).&lt;/p>
&lt;h3 id="the-magic-of-bootstrapping">The Magic of Bootstrapping
&lt;/h3>&lt;p>Craig Gentry&amp;rsquo;s genius contribution was inventing a noise reduction technique called &lt;strong>&amp;ldquo;bootstrapping.&amp;rdquo;&lt;/strong> This was a paradigm shift in cryptography.&lt;/p>
&lt;p>Intuitively, it is the operation of &amp;ldquo;&amp;lsquo;decrypting&amp;rsquo; the ciphertext to clean it while it remains encrypted, and putting it into a new ciphertext before it becomes too noisy and breaks.&amp;rdquo;&lt;/p>
&lt;ol>
&lt;li>Suppose we have a highly noisy ciphertext $C_{noisy}$.&lt;/li>
&lt;li>The client provides the server in advance with the secret key $sk$ &amp;ldquo;encrypted with the public key,&amp;rdquo; $E_{pk}(sk)$ (this is called the bootstrapping key).&lt;/li>
&lt;li>The server runs a &lt;strong>Decryption Circuit&lt;/strong> homomorphically on $C_{noisy}$.&lt;/li>
&lt;li>Specifically, it performs a &amp;ldquo;decryption within the encrypted space&amp;rdquo; on $E_{pk}(C_{noisy})$ using $E_{pk}(sk)$.&lt;/li>
&lt;li>Since this decryption circuit itself is a homomorphic operation, it generates new noise, but the noise of the newly output ciphertext $C_{fresh}$ is reset to a fixed &amp;ldquo;constant level.&amp;rdquo;&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph LR
A["High noise ciphertext C_noisy"] --> B["Homomorphic decryption circuit (Eval_Dec)"]
C["Encrypted secret key E(sk)"] --> B
B --> D["Low noise ciphertext C_fresh"]
style B fill:#ffeeba,stroke:#ffc107&lt;/div>
&lt;p>By executing this bootstrapping periodically during computation, it theoretically became possible to compute circuits of infinite depth (achieving FHE). However, Gentry&amp;rsquo;s early scheme was desperately expensive computationally, with a single bootstrapping operation taking anywhere from tens of minutes to hours.&lt;/p>
&lt;hr>
&lt;h2 id="5-generations-of-fhe-and-the-evolution-of-major-schemes">5. Generations of FHE and the Evolution of Major Schemes
&lt;/h2>&lt;p>In the race toward practical FHE, cryptographers around the world have competed to improve the algorithms. Currently, FHE is mainly classified into four generations or families.&lt;/p>
&lt;h3 id="2nd-generation-exact-integer-arithmetic-bgv-bfv">2nd Generation: Exact Integer Arithmetic (BGV, BFV)
&lt;/h3>&lt;p>The &lt;strong>BGV (Brakerski-Gentry-Vaikuntanathan)&lt;/strong> and &lt;strong>BFV (Brakerski/Fan-Vercauteren)&lt;/strong> schemes appeared between 2011 and 2012. These are based on RLWE and are suitable for integer modular arithmetic (exact calculations).
They support batching techniques like SIMD (Single Instruction, Multiple Data), characterized by the ability to pack thousands of data slots into a single large polynomial ciphertext and compute them in parallel all at once.&lt;/p>
&lt;h3 id="3rd-generation-accelerated-bootstrapping-gsw-fhew-tfhe">3rd Generation: Accelerated Bootstrapping (GSW, FHEW, TFHE)
&lt;/h3>&lt;p>The &lt;strong>GSW (Gentry-Sahai-Waters)&lt;/strong> scheme of 2013 made the structure of FHE simpler. This was developed further into &lt;strong>TFHE (Fast Fully Homomorphic Encryption over the Torus)&lt;/strong>, one of the mainstream schemes today.
The hallmark of TFHE is its extremely fast bootstrapping (on the order of milliseconds). It excels at gate-level operations (logic circuits like AND, XOR), and since the ciphertext size is relatively small, it is suited for fast evaluation of arbitrary logic circuits.&lt;/p>
&lt;h3 id="4th-generation-specialization-for-approximate-calculation-and-machine-learning-ckks">4th Generation: Specialization for Approximate Calculation and Machine Learning (CKKS)
&lt;/h3>&lt;p>The &lt;strong>CKKS (Cheon-Kim-Kim-Song)&lt;/strong> scheme proposed by Cheon et al. in 2017 can be called the definitive technology for privacy protection in current AI and machine learning.
While previous FHEs insisted on &amp;ldquo;exact integer calculations,&amp;rdquo; CKKS supports &lt;strong>&amp;ldquo;approximate calculations of floating-point numbers&amp;rdquo;&lt;/strong> while remaining encrypted. It demonstrates overwhelming performance in real number calculations where small errors are tolerable, such as the training and inference of neural networks.&lt;/p>
&lt;p>The table below summarizes how to choose a scheme by purpose.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Scheme Name&lt;/th>
&lt;th style="text-align:left">Preferred Data Type&lt;/th>
&lt;th style="text-align:left">Recommended Use Cases&lt;/th>
&lt;th style="text-align:left">Features&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">Integer&lt;/td>
&lt;td style="text-align:left">Exact statistical calculations, financial data aggregation, DB queries&lt;/td>
&lt;td style="text-align:left">High throughput via 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">Real/Complex&lt;/td>
&lt;td style="text-align:left">Machine learning (DNN, logistic regression), signal processing&lt;/td>
&lt;td style="text-align:left">Acceleration via approximate calculation, rescaling&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">Boolean&lt;/td>
&lt;td style="text-align:left">Arbitrary logic circuits, string search, evaluation of non-linear functions&lt;/td>
&lt;td style="text-align:left">Ultra-fast bootstrapping (millisecond range)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="6-practice-fhe-libraries-and-conceptual-code">6. Practice: FHE Libraries and Conceptual Code
&lt;/h2>&lt;p>Today, many open-source libraries are provided that allow you to use FHE without deep cryptographic knowledge.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Microsoft SEAL (Simple Encrypted Arithmetic Library)&lt;/strong>: A C++ library supporting BFV, BGV, and CKKS. One of the industry standards. Its Python binding, &lt;strong>TenSEAL&lt;/strong>, is popular among AI engineers.&lt;/li>
&lt;li>&lt;strong>Zama (Concrete)&lt;/strong>: A framework based on TFHE. You can write in Rust/Python, and it provides functionality (Concrete ML) to compile existing PyTorch models and run them on FHE.&lt;/li>
&lt;li>&lt;strong>OpenFHE&lt;/strong>: The successor to PALISADE, a comprehensive C++ library supporting all major schemes.&lt;/li>
&lt;/ul>
&lt;h3 id="example-of-fhe-programming-using-python-tenseal">Example of FHE Programming using Python (TenSEAL)
&lt;/h3>&lt;p>Here, we show a conceptual Python code example using the CKKS scheme to add and multiply real number vectors while they remain encrypted.&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. Context setup (including key generation)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Use CKKS scheme, set polynomial degree to 8192&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">context&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">context&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">SCHEME_TYPE&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CKKS&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">poly_modulus_degree&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">8192&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">coeff_mod_bit_sizes&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">60&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">40&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">40&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">60&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">context&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">generate_galois_keys&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">context&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">global_scale&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="mi">40&lt;/span> &lt;span class="c1"># Scaling factor for real numbers&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 side: Data encryption&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"># Convert plaintext vectors to ciphertexts (should be executed on the client side)&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 side: Computations while encrypted (Protection of Data in Use)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># The server does not know the plaintexts but can perform addition and multiplication&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 side: Decryption of results&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Only the client with the secret key can view the results&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;Decrypted addition result: &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"># Example output: [3.5000001, 5.5000001, 7.5000002] (Includes minute errors due to approximate calculation)&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;Decrypted multiplication result: &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"># Example output: [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>As you can see from the code above, you can intuitively describe computations between ciphertexts by overloading normal Python operators, such as &lt;code>enc_v1 + enc_v2&lt;/code>. On the server side, vector operations are completed without knowing the contents of the vectors.&lt;/p>
&lt;hr>
&lt;h2 id="7-fhe-challenges-performance-and-hardware-acceleration">7. FHE Challenges: Performance and Hardware Acceleration
&lt;/h2>&lt;p>While FHE provides theoretically perfect security, its biggest challenge for practical use is &lt;strong>&amp;ldquo;performance overhead.&amp;rdquo;&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Computational Overhead&lt;/strong>: Compared to computing in plaintext, computing in ciphertext is thousands to tens of thousands of times slower on a CPU. Polynomial multiplications and bootstrapping require massive amounts of FFT (Fast Fourier Transform) or NTT (Number Theoretic Transform) calculations.&lt;/li>
&lt;li>&lt;strong>Ciphertext Expansion&lt;/strong>: A few bytes of plaintext can expand to several megabytes when encrypted. This puts severe pressure on memory bandwidth and network bandwidth.&lt;/li>
&lt;/ol>
&lt;h3 id="approaches-to-hardware-solutions">Approaches to Hardware Solutions
&lt;/h3>&lt;p>To overcome this overhead, the development of dedicated FHE hardware accelerators (ASIC, FPGA, GPU support) is progressing worldwide.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>GPU Acceleration&lt;/strong>: Efforts are underway to parallelize NTT operations and bootstrapping using powerful GPUs from NVIDIA and others, with reports of speeds tens of times faster than software implementations (e.g., 100x.ai, Zama&amp;rsquo;s TFHE-rs CUDA backend).&lt;/li>
&lt;li>&lt;strong>DARPA DPRIVE Project&lt;/strong>: The US Defense Advanced Research Projects Agency (DARPA) is promoting the &amp;ldquo;DPRIVE (Data Protection in Virtual Environments)&amp;rdquo; project to develop dedicated hardware to bring the computational speed of FHE to parity with plaintext processing (within a 10x overhead). Intel, Microsoft, and Intellectual Ventures are participating.&lt;/li>
&lt;li>&lt;strong>Emergence of FPUs (FHE Processing Units)&lt;/strong>: Startups like Cornami and Optalysys are embarking on the development of FHE-specific chips using optical computing and specialized silicon architectures.&lt;/li>
&lt;/ul>
&lt;p>In the near future, an era may come where &amp;ldquo;FPUs&amp;rdquo; become a standard feature in server and cloud infrastructure, just like NPUs (Neural Processing Units) in AI.&lt;/p>
&lt;hr>
&lt;h2 id="8-expected-use-cases">8. Expected Use Cases
&lt;/h2>&lt;p>Now that FHE is approaching practical speeds, disruptive innovations are expected in areas such as:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Privacy Protection in Medical and Genomic Analysis&lt;/strong>:
By having a cloud AI learn from patients&amp;rsquo; medical records and DNA data held by multiple hospitals while keeping it encrypted with FHE, highly accurate cancer diagnostic models and new drug development can be performed without violating privacy laws (like HIPAA or GDPR).&lt;/li>
&lt;li>&lt;strong>Fraud Detection and Anti-Money Laundering (AML) for Financial Institutions&lt;/strong>:
Competing banks can cross-analyze data in an encrypted state to detect massive illegal money transfer networks, without revealing customer account information or transaction histories to each other.&lt;/li>
&lt;li>&lt;strong>Secure AI Inference APIs (MaaS: Model as a Service)&lt;/strong>:
Users encrypt their voice, facial images, and prompts before sending them to AI services (like LLMs such as ChatGPT). The AI provider generates the answer without ever knowing the user&amp;rsquo;s input and returns it as a ciphertext. This completely dispels the concern of &amp;ldquo;AI learning or peeking at personal information.&amp;rdquo;&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="9-conclusion-the-future-of-cryptography-is-unseen-computation">9. Conclusion: The Future of Cryptography is &amp;ldquo;Unseen Computation&amp;rdquo;
&lt;/h2>&lt;p>Just as the invention of public key cryptography (RSA) in the 1970s enabled secure communication on the Internet (such as HTTPS), Craig Gentry&amp;rsquo;s invention of FHE is one of the most important milestones in the history of cryptography.&lt;/p>
&lt;p>Today, Fully Homomorphic Encryption (FHE) has leapt from the theories of laboratories into the stage where Microsoft, IBM, Intel, Google, and many startups are fiercely competing toward practical application. While challenges regarding computational cost and data size still exist, thanks to the refinement of algorithms and the evolution of hardware accelerators, performance improvements continue at a pace exceeding Moore&amp;rsquo;s Law.&lt;/p>
&lt;p>In a few years, &amp;ldquo;computing data while keeping it encrypted&amp;rdquo; will not be something special, but will likely become the standard data protection best practice in cloud services. FHE is the keystone of next-generation security, realizing the &lt;strong>ultimate combination of privacy and data utilization&lt;/strong> in a data-driven society.&lt;/p></description></item><item><title>Mathematical Foundations of Elliptic Curve Cryptography (ECC) and Implementation in C++</title><link>http://kenji.blog/en/p/elliptic-curve-cryptography-math-cpp/</link><pubDate>Fri, 11 Sep 2026 10:00:00 +0900</pubDate><guid>http://kenji.blog/en/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 Mathematical Foundations of Elliptic Curve Cryptography (ECC) and Implementation in C++" />&lt;h1 id="mathematical-foundations-of-elliptic-curve-cryptography-ecc-and-implementation-in-c">Mathematical Foundations of Elliptic Curve Cryptography (ECC) and Implementation in C++
&lt;/h1>&lt;p>In modern cryptographic technology, &lt;strong>Elliptic Curve Cryptography (ECC)&lt;/strong> plays a tremendously important role. It is no exaggeration to say that the foundation of trust in our modern digital society—from everyday Internet communications (HTTPS/TLS) and smartphone secure enclaves, to server authentication via SSH, passwordless authentication like FIDO, and even crypto assets like Bitcoin and Ethereum—is supported by ECC.&lt;/p>
&lt;p>In this article, we will thoroughly explain how elliptic curve cryptography works, starting from the beautiful yet complex mathematical theory behind it (algebraic geometry over finite fields), to actual implementation methods in C++, and even secure coding techniques to prevent side-channel attacks (timing attacks), with an overwhelming volume of detail.&lt;/p>
&lt;hr>
&lt;h2 id="1-why-elliptic-curve-cryptography-comparison-with-rsa">1. Why Elliptic Curve Cryptography? (Comparison with RSA)
&lt;/h2>&lt;p>For a long time, &lt;strong>RSA cryptography&lt;/strong> was synonymous with public-key cryptography. The security of RSA relies on the &amp;ldquo;difficulty of factoring large composite numbers.&amp;rdquo; However, as the computational power of computers has increased, it has become necessary to continuously lengthen the RSA key size (number of modulus bits) to maintain security. Currently, a key size of at least 2048 bits is recommended, and 3072 or 4096 bits if greater security is desired.&lt;/p>
&lt;p>In contrast, Elliptic Curve Cryptography (ECC) bases its security on a different mathematical difficulty: the &lt;strong>&amp;ldquo;Elliptic Curve Discrete Logarithm Problem (ECDLP)&amp;rdquo;&lt;/strong>. To this day, no efficient algorithms (such as sub-exponential time algorithms) for solving the ECDLP have been discovered, and even the most efficient known attack methods require exponential time.&lt;/p>
&lt;p>Because of this property, ECC has the decisive advantage of being able to &lt;strong>achieve security strength equivalent to RSA with significantly shorter key lengths&lt;/strong>.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:center">Security Strength (bits)&lt;/th>
&lt;th style="text-align:center">RSA Key Length (bits)&lt;/th>
&lt;th style="text-align:center">ECC Key Length (bits)&lt;/th>
&lt;th style="text-align:center">Key Length Ratio&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>As shown in the table above, to achieve a security strength of 128 bits (currently a standard strength), RSA requires a 3072-bit key, whereas ECC requires only 256 bits. This reduces computational complexity, lowers memory usage, and saves network bandwidth, making ECC overwhelmingly superior, especially in resource-constrained IoT devices and smart card environments.&lt;/p>
&lt;hr>
&lt;h2 id="2-mathematical-preparation-the-world-of-group-theory-and-finite-fields">2. Mathematical Preparation: The World of Group Theory and Finite Fields
&lt;/h2>&lt;p>To truly understand elliptic curve cryptography, it is necessary to grasp the basic concepts of abstract algebra (group theory and field theory). Here, we briefly summarize the prerequisite knowledge for constructing ECC.&lt;/p>
&lt;h3 id="21-groups-and-abelian-groups">2.1. Groups and Abelian Groups
&lt;/h3>&lt;p>A &lt;strong>Group&lt;/strong> is a pair consisting of a set $G$ and a binary operation on that set (here we&amp;rsquo;ll use addition $+$), denoted as $(G, +)$, which satisfies the following four axioms:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Closure&lt;/strong>: For any $a, b \in G$, $a + b \in G$.&lt;/li>
&lt;li>&lt;strong>Associativity&lt;/strong>: For any $a, b, c \in G$, $(a + b) + c = a + (b + c)$.&lt;/li>
&lt;li>&lt;strong>Identity element&lt;/strong>: There exists an element $e \in G$ such that for any $a \in G$, $a + e = e + a = a$. For additive groups, this identity element is usually denoted as $0$ or $\mathcal{O}$.&lt;/li>
&lt;li>&lt;strong>Inverse element&lt;/strong>: For any $a \in G$, there exists an element $b \in G$ such that $a + b = b + a = e$. This $b$ is denoted as $-a$.&lt;/li>
&lt;/ol>
&lt;p>Furthermore, a group that satisfies the following condition, where the result does not change even if the order of the operation is swapped, is called an &lt;strong>Abelian group (commutative group)&lt;/strong>.&lt;/p>
&lt;ol start="5">
&lt;li>&lt;strong>Commutativity&lt;/strong>: For any $a, b \in G$, $a + b = b + a$.&lt;/li>
&lt;/ol>
&lt;p>The set of points on an elliptic curve, by defining a specific addition rule, constitutes this &lt;strong>Abelian group&lt;/strong>.&lt;/p>
&lt;h3 id="22-finite-fields">2.2. Finite Fields
&lt;/h3>&lt;p>In cryptography, we do not use fields with continuous and infinite elements like real or complex numbers, but rather &lt;strong>Finite Fields&lt;/strong> (or Galois Fields), which have a finite number of elements.&lt;/p>
&lt;p>The most basic finite field is the &lt;strong>prime field $\mathbb{F}_p$&lt;/strong> using a prime number $p$. This defines the four basic arithmetic operations (addition, subtraction, multiplication, division) modulo $p$ (the remainder when divided by $p$) on the set of integers $\{0, 1, 2, \dots, p-1\}$.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Addition&lt;/strong>: $(a + b) \pmod p$&lt;/li>
&lt;li>&lt;strong>Subtraction&lt;/strong>: $(a - b) \pmod p$&lt;/li>
&lt;li>&lt;strong>Multiplication&lt;/strong>: $(a \times b) \pmod p$&lt;/li>
&lt;li>&lt;strong>Division&lt;/strong>: $a \times b^{-1} \pmod p$ (where $b^{-1}$ is the modular multiplicative inverse of $b$ modulo $p$)&lt;/li>
&lt;/ul>
&lt;p>Calculating the &lt;strong>Modular Multiplicative Inverse&lt;/strong> is extremely important in cryptographic implementations. To find $b^{-1}$ satisfying $b \times b^{-1} \equiv 1 \pmod p$, the following two main algorithms are used:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Extended Euclidean Algorithm&lt;/strong>: Fast, but depending on the implementation, the processing time can depend on the input values, leading to a risk of timing attacks.&lt;/li>
&lt;li>&lt;strong>Fermat&amp;rsquo;s Little Theorem&lt;/strong>: When $p$ is prime and $b \neq 0$, $b^{p-1} \equiv 1 \pmod p$ holds. Dividing both sides by $b$ yields $b^{p-2} \equiv b^{-1} \pmod p$. That is, the inverse is found by raising $b$ to the power of $p-2$. Exponentiation is easier to implement in constant time, so this method is preferred in cryptographic implementations.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="3-elliptic-curve-equations-and-geometry">3. Elliptic Curve Equations and Geometry
&lt;/h2>&lt;h3 id="31-weierstrass-normal-form">3.1. Weierstrass Normal Form
&lt;/h3>&lt;p>An &lt;strong>Elliptic Curve&lt;/strong> is generally a plane curve defined by the following equation, known as the &lt;strong>Weierstrass normal form&lt;/strong>.&lt;/p>
$$ y^2 = x^3 + ax + b $$
&lt;p>Here, $a$ and $b$ are constants, and as a condition for the curve to have no singular points (self-intersections or cusps) (i.e., to be a smooth curve), the following &lt;strong>Discriminant $\Delta$&lt;/strong> must not be zero.&lt;/p>
$$ \Delta = -16(4a^3 + 27b^2) \neq 0 $$
&lt;p>Since curves with singular points compromise cryptographic security, coefficients $a, b$ that satisfy this condition are always chosen.&lt;/p>
&lt;h3 id="32-point-at-infinity">3.2. Point at Infinity
&lt;/h3>&lt;p>To make an elliptic curve a mathematically complete group, a virtual point called the &lt;strong>&amp;ldquo;Point at Infinity&amp;rdquo;&lt;/strong> is introduced in addition to the points on the plane. This is denoted as $\mathcal{O}$.&lt;/p>
&lt;p>The point at infinity $\mathcal{O}$ is defined as the point where all vertical lines intersect infinitely far away. In group theory, this point at infinity $\mathcal{O}$ functions as the &lt;strong>identity element&lt;/strong> (zero) for addition.&lt;/p>
&lt;p>In other words, for any point $P$ on the curve, the following holds:
&lt;/p>
$$ P + \mathcal{O} = \mathcal{O} + P = P $$
&lt;p>Also, the inverse $-P$ of point $P = (x, y)$ is defined as the point symmetrical with respect to the x-axis, $(x, -y)$. Therefore:
&lt;/p>
$$ P + (-P) = \mathcal{O} $$
&lt;p>
holds.&lt;/p>
&lt;hr>
&lt;h2 id="4-group-operations-on-elliptic-curves-point-addition-and-point-doubling">4. Group Operations on Elliptic Curves (Point Addition and Point Doubling)
&lt;/h2>&lt;p>The core of elliptic curve cryptography is the operation called &lt;strong>&amp;ldquo;Addition&amp;rdquo;&lt;/strong> between points on the curve. This is different from the addition of ordinary integers and is defined based on geometric operations.&lt;/p>
&lt;h3 id="41-geometric-addition-tangent-and-chord-method">4.1. Geometric Addition (Tangent and Chord Method)
&lt;/h3>&lt;p>The procedure for finding a new point $R$ ($R = P + Q$) by adding two distinct points $P$ and $Q$ on the curve is as follows:&lt;/p>
&lt;ol>
&lt;li>Draw a straight line (chord) connecting point $P$ and point $Q$.&lt;/li>
&lt;li>This straight line will definitely intersect the elliptic curve at a third point (let&amp;rsquo;s call it $-R$). (*Based on a theorem in algebraic geometry)&lt;/li>
&lt;li>The point $R$ we are looking for is the point obtained by reflecting the intersection point $-R$ symmetrically across the x-axis (the point with the inverted sign of the y-coordinate).&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph TD
Step1["Draw a line connecting P(x1, y1) and Q(x2, y2)"] --> Step2["Find the 3rd intersection -R with the curve"]
Step2 --> Step3["Reflect -R across the x-axis to get R(x3, y3)"]
Step3 -.-> Result["This is R = P + Q"]&lt;/div>
&lt;h3 id="42-point-doubling">4.2. Point Doubling
&lt;/h3>&lt;p>When adding the same point $P$ to point $P$ ($P + P = 2P$), we cannot draw a line connecting two points. In this case, we draw the &lt;strong>tangent line to the curve at point $P$&lt;/strong>.&lt;/p>
&lt;ol>
&lt;li>Draw the tangent line to the curve at point $P$.&lt;/li>
&lt;li>This tangent line intersects the curve at another point $-R$.&lt;/li>
&lt;li>The point $R = 2P$ we are looking for is obtained by reflecting the intersection symmetrically across the x-axis.&lt;/li>
&lt;/ol>
&lt;h3 id="43-algebraic-calculation-formulas">4.3. Algebraic Calculation Formulas
&lt;/h3>&lt;p>We translate the geometric operations into algebraic formulas so they can be computed by a computer.
All operations are performed &lt;strong>over the finite field $\mathbb{F}_p$ (modulo $p$)&lt;/strong>.&lt;/p>
&lt;p>Let point $P = (x_1, y_1)$ and point $Q = (x_2, y_2)$.
Also, let the resulting point be $R = P + Q = (x_3, y_3)$.&lt;/p>
&lt;p>Let the slope of the line be $\lambda$ (lambda).&lt;/p>
&lt;p>&lt;strong>[Case 1: When $P \neq Q$ (Point Addition)]&lt;/strong>
The slope $\lambda$ is the rate of change between the two points.
&lt;/p>
$$ \lambda \equiv \frac{y_2 - y_1}{x_2 - x_1} \pmod p $$
$$ \lambda \equiv (y_2 - y_1) \cdot (x_2 - x_1)^{-1} \pmod p $$
&lt;p>Using this $\lambda$, $x_3, y_3$ are found as follows:
&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>[Case 2: When $P = Q$ (Point Doubling)]&lt;/strong>
The slope $\lambda$ becomes the slope of the tangent line obtained by differentiation. (We implicitly differentiate $y^2 = x^3 + ax + b$)
&lt;/p>
$$ 2y \cdot y' = 3x^2 + a \implies y' = \frac{3x^2 + a}{2y} $$
&lt;p>
Therefore,
&lt;/p>
$$ \lambda \equiv (3x_1^2 + a) \cdot (2y_1)^{-1} \pmod p $$
&lt;p>The formulas for $x_3, y_3$ take the same form as addition, but since $x_2 = x_1$, they are as follows:
&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]
These formulas include &lt;strong>division (calculation of modular inverses)&lt;/strong>, such as $(x_2 - x_1)^{-1}$ and $(2y_1)^{-1}$. Since calculating modular inverses incurs a very high computational cost, practical implementations generally use projective coordinate systems like &lt;strong>&amp;ldquo;Jacobian Coordinates&amp;rdquo;&lt;/strong>, which delay division.&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h2 id="5-scalar-multiplication-and-the-elliptic-curve-discrete-logarithm-problem-ecdlp">5. Scalar Multiplication and the Elliptic Curve Discrete Logarithm Problem (ECDLP)
&lt;/h2>&lt;p>In elliptic curve cryptography, the operation that requires the most computation and forms the core of its security is &lt;strong>Scalar Multiplication&lt;/strong>.&lt;/p>
&lt;h3 id="51-what-is-scalar-multiplication">5.1. What is Scalar Multiplication?
&lt;/h3>&lt;p>The operation of adding a point $P$ to itself $k$ times is called scalar multiplication, denoted as $kP$.
&lt;/p>
$$ kP = \underbrace{P + P + \dots + P}_{k \text{ times}} $$
&lt;p>Here, $k$ is a very large integer (for example, a 256-bit integer).&lt;/p>
&lt;h3 id="52-elliptic-curve-discrete-logarithm-problem-ecdlp">5.2. Elliptic Curve Discrete Logarithm Problem (ECDLP)
&lt;/h3>&lt;p>The security of elliptic curve cryptography depends on the difficulty of the following problem.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Elliptic Curve Discrete Logarithm Problem (ECDLP)&lt;/strong>
Given a known point $P$ (base point) and the resulting point $Q$, find the scalar $k$ that satisfies $Q = kP$.&lt;/p>
&lt;/blockquote>
&lt;p>Calculating $Q$ from $k$ and $P$ (forward direction) is easy (polynomial time) using the algorithm described below, but inversely calculating $k$ from $P$ and $Q$ (reverse direction) is practically impossible as there is no efficient solution other than exhaustive search (a one-way function).
In cryptographic protocols, &lt;strong>$k$ corresponds to the &amp;ldquo;private key&amp;rdquo; and $Q$ to the &amp;ldquo;public key&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;h3 id="53-double-and-add-algorithm">5.3. Double-and-Add Algorithm
&lt;/h3>&lt;p>When $k$ is a huge number (e.g., $2^{256}$), naively adding $P$ for $k$ times will not finish even if the life of the universe ends. Therefore, to perform scalar multiplication quickly, the &lt;strong>Double-and-Add method (binary method)&lt;/strong> is used.&lt;/p>
&lt;p>This is the elliptic curve version of the &amp;ldquo;exponentiation by squaring&amp;rdquo; method used for rapid calculation of integer powers. The scalar $k$ is represented in binary, and processed sequentially starting from the most significant bit.&lt;/p>
&lt;ol>
&lt;li>Initialize the point $R$ holding the result to $\mathcal{O}$.&lt;/li>
&lt;li>Repeat the following from the most significant bit to the least significant bit of $k$:
&lt;ul>
&lt;li>Double $R$ (Point Doubling: $R = 2R$)&lt;/li>
&lt;li>If the current bit is &lt;code>1&lt;/code>, add $P$ to $R$ (Point Addition: $R = R + P$)&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>With this algorithm, the computational complexity is dramatically reduced from $O(k)$ to $O(\log_2 k)$, enabling calculation in a realistic amount of time (milliseconds).&lt;/p>
&lt;hr>
&lt;h2 id="6-elliptic-curve-diffie-hellman-ecdh-key-exchange">6. Elliptic Curve Diffie-Hellman (ECDH) Key Exchange
&lt;/h2>&lt;p>Here, we explain the mechanics of the &lt;strong>ECDH (Elliptic Curve Diffie-Hellman) key exchange protocol&lt;/strong>, which is the most representative application of ECC. ECDH is a mechanism for Alice and Bob to securely generate and share a common secret key (session key) over a communication channel that could be wiretapped (it is the core of the TLS handshake).&lt;/p>
&lt;p>&lt;strong>[Prerequisite Parameters (Domain Parameters)]&lt;/strong>
Both parties share the elliptic curve $E$, a prime number $p$, and a base point $G$ to be used beforehand. (e.g., NIST P-256 or secp256k1)&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant Alice as "Alice"
participant Bob as "Bob"
Note over Alice,Bob: "Public parameters: Curve E, Base point G, Prime p"
Alice->>Alice: "Generate private key d_A (random integer)"
Alice->>Alice: "Calculate public key Q_A = d_A * G"
Bob->>Bob: "Generate private key d_B (random integer)"
Bob->>Bob: "Calculate public key Q_B = d_B * G"
Alice->>Bob: "Send public key Q_A (plaintext)"
Bob->>Alice: "Send public key Q_B (plaintext)"
Alice->>Alice: "Calculate shared secret S = d_A * Q_B"
Bob->>Bob: "Calculate shared secret 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: "Both parties' calculation results S perfectly match!"&lt;/div>
&lt;p>An eavesdropper (Eve) can intercept $G$, $Q_A$, and $Q_B$ flowing over the communication path, but due to the difficulty of the ECDLP, she cannot determine Alice&amp;rsquo;s private key $d_A$ from $Q_A = d_A \cdot G$. Also, even if she multiplies $Q_A$ and $Q_B$, it will not result in the shared key $S$, so the eavesdropper cannot calculate $S$.&lt;/p>
&lt;hr>
&lt;h2 id="7-implementation-pitfalls-side-channel-attacks-and-countermeasures">7. Implementation Pitfalls: Side-Channel Attacks and Countermeasures
&lt;/h2>&lt;p>Even a theoretically perfect cryptographic algorithm can harbor vulnerabilities introduced during the process of implementing it as a program. This is known as a &lt;strong>&amp;ldquo;Side-Channel Attack&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;h3 id="71-timing-attack">7.1. Timing Attack
&lt;/h3>&lt;p>Let&amp;rsquo;s look back at the Double-and-Add algorithm mentioned earlier.&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">// Vulnerable pseudo-code for 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">// Always executed
&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">// Executed ONLY when bit is 1!
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>This implementation has a fatal flaw. Because Point Addition is executed when the bit is &lt;code>1&lt;/code>, the calculation time is &lt;strong>slightly longer&lt;/strong> than when the bit is &lt;code>0&lt;/code>. Also, the behavior of the processor&amp;rsquo;s branch prediction and cache memory will change.
By statistically observing this minute difference in calculation time (or power consumption) thousands of times, an attacker can &lt;strong>completely recover the bit sequence of the private key $k$, one bit at a time&lt;/strong>. This is a timing attack.&lt;/p>
&lt;h3 id="72-constant-time-implementation-montgomery-ladder">7.2. Constant-Time Implementation: Montgomery Ladder
&lt;/h3>&lt;p>To prevent timing attacks, it is necessary to adopt algorithms where &lt;strong>the sequence of executed instructions and the calculation time are always constant (Constant-Time), regardless of the bit values of the private key&lt;/strong>.&lt;/p>
&lt;p>A representative example of this is the &lt;strong>Montgomery Ladder&lt;/strong>.&lt;/p>
&lt;div class="mermaid">graph TD
Start["Initialization: R0 = O, R1 = P"] --> LoopStart["For each bit i (from MSB)"]
LoopStart --> Cond{"Value of 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["Next bit"]
Branch1 --> LoopEnd
LoopEnd --> LoopStart
LoopStart -.->|"All bits processed"| End["End: R0 is the result (kP)"]&lt;/div>
&lt;p>The beauty of the Montgomery Ladder is that whether the bit is &lt;code>0&lt;/code> or &lt;code>1&lt;/code>, &lt;strong>&amp;ldquo;exactly one Point Addition and one Point Doubling&amp;rdquo;&lt;/strong> are always executed. This completely eliminates the data dependency of the computation time.&lt;/p>
&lt;p>However, if a branch (&lt;code>if (k_i == 0)&lt;/code>) itself exists, the risk of execution time fluctuating due to compiler optimization and CPU branch prediction remains. Therefore, in actual Constant-Time implementations, conditional branches (&lt;code>if&lt;/code> statements) are eliminated, and a &lt;strong>Conditional Swap using bitwise operations&lt;/strong> is utilized.&lt;/p>
&lt;hr>
&lt;h2 id="8-implementation-of-elliptic-curve-cryptography-in-c">8. Implementation of Elliptic Curve Cryptography in C++
&lt;/h2>&lt;p>From here, we will translate the theory into C++ code. While practical cryptographic libraries (like OpenSSL or libsodium) use highly advanced assembly optimizations and Jacobian coordinates, we present the skeleton of an &lt;strong>easy-to-understand Constant-Time implementation using affine coordinates&lt;/strong> to deepen mathematical understanding.&lt;/p>
&lt;p>We assume the use of &lt;code>boost::multiprecision::cpp_int&lt;/code> for operations on huge integers.&lt;/p>
&lt;h3 id="81-modular-arithmetic-and-inverses">8.1. Modular Arithmetic and Inverses
&lt;/h3>&lt;p>First, we define helper functions for operations over finite fields. We implement inverse calculation using Fermat&amp;rsquo;s Little Theorem.&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">// Prime p and parameters for secp256k1 as an example
&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 returning a positive remainder
&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">// Modular 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">// Modular inverse using Fermat&amp;#39;s Little Theorem
&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">// Assuming m is prime: 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-point-representation-and-group-operations-additiondoubling">8.2. Point Representation and Group Operations (Addition/Doubling)
&lt;/h3>&lt;p>We implement the &lt;code>Point&lt;/code> structure, which manages the point at infinity with a flag, and the addition formulas.&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">// Creation of the point at infinity
&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">// Creation of a normal point
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">isInfinity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">false&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Addition of points on the elliptic curve (R = P + Q)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="nf">pointAdd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isInfinity&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isInfinity&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// P + (-P) = Point at infinity
&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 (when 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 (when 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-implementation-of-constant-time-conditional-swap">8.3. Implementation of Constant-Time Conditional Swap
&lt;/h3>&lt;p>When swapping the contents of variables based on the bit value of the private key, we use only bitwise operations (masks) without using an &lt;code>if&lt;/code> statement. This ensures the execution path is completely constant.&lt;/p>
&lt;blockquote>
&lt;p>[!TIP]
In an actual implementation, dynamically allocated multiple-precision integer classes like &lt;code>cpp_int&lt;/code> are not suitable for Constant-Time processing. This is because timing information leaks due to variations in memory allocation and array sizes. Practical libraries represent them with fixed lengths (for example, an array of 4 uint64_t elements) and implement bit-level masking. The following is a conceptual example.&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">// Conceptual Constant-Time Swap (assuming fixed-length integers)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// If bit is 1, swap P1 and P2; if 0, do not swap
&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 is 0 or 1. Mask is all 1s (0xFF..) if bit=1, all 0s if 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">// (Here we assume each word of a fixed-length BigInt class is w for explanation)
&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"> // Process y-coordinate and isInfinity flag similarly
&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">// * Perfect constant-time swapping is difficult with boost::multiprecision,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// so here we limit it to simulating with a branch for the sake of understanding the logic.
&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-scalar-multiplication-using-the-montgomery-ladder">8.4. Scalar Multiplication using the Montgomery Ladder
&lt;/h3>&lt;p>We combine the aforementioned &lt;code>pointAdd&lt;/code> and &lt;code>cswap&lt;/code> to implement secure scalar multiplication.&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">// Scalar multiplication k * P (Montgomery Ladder method)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="nf">scalarMultiply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">k&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Point&lt;/span> &lt;span class="n">R0&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// Point at infinity
&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">// Get the bit length of k (256 bits for 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">// Get the value of the i-th bit (0 or 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">// Swap R0 and R1 if bit == 1
&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">// Always execute the same operations (Point Addition and 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">// Swap back to restore state if bit == 1
&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>With this implementation logic, whether each bit of the scalar $k$ is &lt;code>0&lt;/code> or &lt;code>1&lt;/code>, the operations executed within each loop iteration (&lt;code>cswap&lt;/code> $\to$ &lt;code>pointAdd&lt;/code> $\to$ &lt;code>pointAdd&lt;/code> $\to$ &lt;code>cswap&lt;/code>) follow the exact same flow. This powerfully prevents the leakage of secret information through differences in timing or cache access patterns.&lt;/p>
&lt;hr>
&lt;h2 id="9-conclusion">9. Conclusion
&lt;/h2>&lt;p>At first glance, Elliptic Curve Cryptography (ECC) might seem puzzling: &amp;ldquo;Why does a geometric operation like drawing a line and reflecting the intersection point become cryptography?&amp;rdquo; However, by mapping it to the discrete world of finite fields, an excellent one-way function (the discrete logarithm problem) can be constructed, making it a product of the miraculous fusion of mathematics and cryptography.&lt;/p>
&lt;p>In this article, we covered the following key points:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Superiority over RSA&lt;/strong>: Provides strong security with very short key lengths, making it ideal for the modern mobile and IoT era.&lt;/li>
&lt;li>&lt;strong>Basics of Group Theory and Finite Fields&lt;/strong>: The mathematical structure that forms the foundation of ECC.&lt;/li>
&lt;li>&lt;strong>Addition and Doubling Formulas&lt;/strong>: Implementation methods of algebraic group operations using Weierstrass equations.&lt;/li>
&lt;li>&lt;strong>Threat of Side-Channel Attacks&lt;/strong>: Conditional branches dependent on private key bits create fatal vulnerabilities.&lt;/li>
&lt;li>&lt;strong>Constant-Time Implementation&lt;/strong>: C++ coding techniques that uniformize hardware-level behavior using the Montgomery Ladder and Conditional Swap to prevent attacks.&lt;/li>
&lt;/ol>
&lt;p>Writing your own cryptographic library to run in a production environment is highly discouraged (&amp;ldquo;Don&amp;rsquo;t roll your own crypto&amp;rdquo;) because the security risks are extremely high. However, deeply understanding the underlying algorithms and mathematical background should serve as an invaluable and powerful weapon for engineers designing and operating more secure and performant systems.&lt;/p>
&lt;p>In the next article, we would like to dig even deeper into the mechanics of the &lt;strong>ECDSA (Elliptic Curve Digital Signature Algorithm)&lt;/strong>, which is a digital signature algorithm using these elliptic curves, as well as &lt;strong>Schnorr signatures&lt;/strong>, which are adopted in Bitcoin.&lt;/p></description></item><item><title>Is There an Algorithm Beyond GNFS (General Number Field Sieve)?</title><link>http://kenji.blog/en/p/beyond-gnfs-integer-factorization-algorithms/</link><pubDate>Fri, 11 Sep 2026 09:00:00 +0900</pubDate><guid>http://kenji.blog/en/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 Is There an Algorithm Beyond GNFS (General Number Field Sieve)?" />&lt;h2 id="1-introduction-integer-factorization-and-the-foundation-of-modern-cryptography">1. Introduction: Integer Factorization and the Foundation of Modern Cryptography
&lt;/h2>&lt;p>The security of internet communication in modern society heavily relies on the security of the RSA cryptosystem, a public-key encryption. And the security of RSA is based on the mathematical assumption of &amp;ldquo;the difficulty of factoring huge composite numbers&amp;rdquo;. If an extremely efficient integer factorization algorithm were discovered, the world&amp;rsquo;s communication infrastructure would collapse from its foundation.&lt;/p>
&lt;p>Currently, the &lt;strong>General Number Field Sieve (GNFS)&lt;/strong> reigns as the fastest and strongest algorithm for factoring huge integers using classical computers. GNFS was born as an extension of the Special Number Field Sieve (SNFS) proposed in the late 1980s, and to this day, it has established factorization records for huge composite numbers such as RSA-768 and RSA-250.&lt;/p>
&lt;p>However, cryptographers and mathematicians always harbor the following questions: &amp;ldquo;Is there a classical algorithm that surpasses GNFS?&amp;rdquo; &amp;ldquo;Where are the limits of classical computers?&amp;rdquo; And, &amp;ldquo;How will quantum computers break through this situation?&amp;rdquo;&lt;/p>
&lt;p>In this article, we thoroughly dissect the profound mathematical structures behind GNFS and conduct a detailed technical analysis of polynomial selection, the sieving phase, and the linear algebra step using the block Wiedemann method. Furthermore, we consider extension methods of GNFS such as Coppersmith&amp;rsquo;s improvements, and compare and explain the decisive differences between classical sub-exponential time algorithms and quantum polynomial time algorithms from a mathematical perspective.&lt;/p>
&lt;hr>
&lt;h2 id="2-asymptotic-complexity-and-l-notation">2. Asymptotic Complexity and L-notation
&lt;/h2>&lt;p>When evaluating the computational complexity of integer factorization algorithms, instead of standard polynomial time notation (such as $O(n^k)$), &lt;strong>L-notation&lt;/strong> is used to express the sub-exponential time relative to the number of digits of the input $n$. L-notation is defined as follows:&lt;/p>
$$
L_n[\alpha, c] = \exp \left( (c + o(1)) (\ln n)^\alpha (\ln \ln n)^{1-\alpha} \right)
$$
&lt;p>Here, $n$ is the integer to be factored, and $\ln n$ is the natural logarithm, which is proportional to the bit length of $n$.&lt;/p>
&lt;ul>
&lt;li>When $\alpha = 0$: $L_n[0, c] = \exp(c \ln \ln n) = (\ln n)^c$, representing &lt;strong>polynomial time&lt;/strong> relative to the bit length.&lt;/li>
&lt;li>When $\alpha = 1$: $L_n[1, c] = \exp(c \ln n) = n^c$, representing &lt;strong>exponential time&lt;/strong> relative to the bit length.&lt;/li>
&lt;li>When $0 &lt; \alpha &lt; 1$: It becomes &lt;strong>sub-exponential time&lt;/strong>, positioned between polynomial time and exponential time.&lt;/li>
&lt;/ul>
&lt;p>The history of the evolution of past integer factorization algorithms has also been a history of gradually reducing this value of $\alpha$.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Continued Fraction Factorization (CFRAC) and Multiple Polynomial Quadratic Sieve (MPQS)&lt;/strong>: Belong to the class of $\alpha = 1/2$, with a complexity of around $L_n[1/2, 1]$.&lt;/li>
&lt;li>&lt;strong>General Number Field Sieve (GNFS)&lt;/strong>: Achieved $\alpha = 1/3$, boasting a complexity of $L_n[1/3, (64/9)^{1/3}]$, the fastest among currently known classical algorithms.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="3-the-full-picture-and-mathematical-structure-of-the-gnfs-algorithm">3. The Full Picture and Mathematical Structure of the GNFS Algorithm
&lt;/h2>&lt;p>GNFS has a very complex and advanced mathematical foundation. The basic idea is an extension of Fermat&amp;rsquo;s Little Theorem and the Quadratic Sieve (QS), finding a non-trivial pair $(X, Y)$ that satisfies the congruence $X^2 \equiv Y^2 \pmod n$ and $X \not\equiv \pm Y \pmod n$, thereby deriving the factor $\gcd(X-Y, n)$ of $n$.&lt;/p>
&lt;p>However, the essence of GNFS is that it does not do this only in the rational number field $\mathbb{Q}$, but simultaneously searches for &amp;ldquo;smooth numbers&amp;rdquo; in both an extension field called an Algebraic Number Field $\mathbb{Q}(\alpha)$ and the rational number field, building congruence relations through homomorphisms.&lt;/p>
&lt;p>The GNFS process is broadly divided into five phases.&lt;/p>
&lt;div class="mermaid">graph TD
A["Integer Factorization Problem (Input n)"] --> B["1. Polynomial Selection"]
B --> C["2. Sieving Phase"]
C --> D["3. Filtering Phase"]
D --> E["4. Linear Algebra Phase"]
E --> F["5. Square Root Phase"]
F --> G["Output prime factors p, q"]&lt;/div>
&lt;h3 id="31-phase-1-polynomial-selection">3.1 Phase 1: Polynomial Selection
&lt;/h3>&lt;p>The success of GNFS heavily depends on the selection of appropriate polynomials. The goal is to find two irreducible polynomials $f_1(x)$ (rational side) and $f_2(x)$ (algebraic side) that share a common root $m$. That is, it satisfies:
$f_1(m) \equiv f_2(m) \equiv 0 \pmod n$&lt;/p>
&lt;p>Usually, a polynomial of degree 1 is chosen for the rational side, $f_1(x) = x - m$, and a monic polynomial of degree $d$ (typically 5 or 6) is chosen for the algebraic side, $f_2(x)$. The most classical approach is the &lt;strong>Base-$m$ method&lt;/strong>.
Choose an integer $m = \lfloor n^{1/(d+1)} \rfloor$ close to the $1/(d+1)$ power of $n$, and expand $n$ in base $m$.
$n = c_d m^d + c_{d-1} m^{d-1} + \dots + c_1 m + c_0$
This gives the polynomial $f_2(x) = c_d x^d + c_{d-1} x^{d-1} + \dots + c_0$. Obviously, $f_2(m) = n \equiv 0 \pmod n$.&lt;/p>
&lt;p>However, in modern implementations, &lt;strong>Kleinjung&amp;rsquo;s algorithm&lt;/strong> is used. This optimizes algebraic properties (Murphy&amp;rsquo;s $E$ value and $\alpha$-value) while preventing the coefficients of the polynomial from becoming extremely large (optimizing skewness), exploring polynomials that are likely to generate smooth numbers during the sieving phase. A massive amount of computational resources is invested in this step alone.&lt;/p>
&lt;h3 id="32-phase-2-sieving-phase">3.2 Phase 2: Sieving Phase
&lt;/h3>&lt;p>Once the polynomials are determined, the algorithm enters the &amp;ldquo;Sieving&amp;rdquo; phase, which has the highest computational load. Here, we search for pairs $(a, b)$. This pair is coprime, and the following two values are simultaneously required to be &amp;ldquo;smooth&amp;rdquo;.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Norm on the rational side&lt;/strong>: $F_1(a, b) = b \cdot f_1(a/b) = a - bm$&lt;/li>
&lt;li>&lt;strong>Norm on the algebraic side&lt;/strong>: $F_2(a, b) = b^d \cdot f_2(a/b)$&lt;/li>
&lt;/ol>
&lt;p>&amp;ldquo;Smooth&amp;rdquo; means that it can be factored only by primes up to a specified limit (Sieve bound). A prime base (Factor base) for the rational side and a prime base for the algebraic side are prepared, and smooth numbers are efficiently found over a huge search space using an approach similar to the Sieve of Eratosthenes.
Currently, a method called &lt;strong>Lattice Sieving&lt;/strong> is mainstream. By fixing a specific prime $q$ and sieving only the $(a, b)$ pairs on a sublattice where both the rational side and the algebraic side become multiples of $q$, extremely high efficiency is realized.&lt;/p>
&lt;h3 id="33-phase-3-filtering-phase">3.3 Phase 3: Filtering Phase
&lt;/h3>&lt;p>The number of smooth relations found in the sieving phase reaches hundreds of millions to billions. However, these also contain a lot of useless information.
The purpose of filtering is to construct a huge sparse matrix while reducing its dimensions as much as possible.&lt;/p>
&lt;p>Specifically, operations such as the following are performed.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Singleton removal&lt;/strong>: Remove relations that contain a prime factor that appears only once.&lt;/li>
&lt;li>&lt;strong>Clique removal / Merging&lt;/strong>: Multiply relations that share prime factors appearing two or more times, eliminating variables and reducing to a denser but smaller-dimensional system of equations.&lt;/li>
&lt;/ul>
&lt;p>As a result, a matrix with billions of rows is compressed into a huge sparse matrix $\mathbf{A}$ with tens of millions of rows (elements are 0 and 1 over the field $\mathbb{F}_2$).&lt;/p>
&lt;h3 id="34-phase-4-linear-algebra-phase">3.4 Phase 4: Linear Algebra Phase
&lt;/h3>&lt;p>Here, we find a non-trivial solution vector $\mathbf{x}$ for the equation $\mathbf{A} \mathbf{x} \equiv \mathbf{0} \pmod 2$. In other words, this is the problem of finding the left nullspace of a huge sparse matrix.&lt;/p>
&lt;p>Because the matrix size is extremely large, normal Gaussian elimination ($O(N^3)$) is completely impossible to compute. Therefore, an iterative method, a type of Krylov subspace method, is used. Historically, the &lt;strong>Block Lanczos method&lt;/strong> has been used, but in modern distributed computing environments, the &lt;strong>Block Wiedemann Algorithm&lt;/strong>, which can dramatically reduce communication overhead, is mainstream.&lt;/p>
&lt;p>The Block Wiedemann method calculates the minimal polynomial from the matrix $\mathbf{A}$ and a sequence of vectors, and constructs the basis of the nullspace using the Berlekamp-Massey algorithm. This step is extremely difficult to parallelize, and is one of the biggest bottlenecks of GNFS, requiring a tightly coupled communication network of supercomputers or large-scale clusters.&lt;/p>
&lt;h3 id="35-phase-5-square-root-phase">3.5 Phase 5: Square Root Phase
&lt;/h3>&lt;p>From the solution of linear algebra, a product that becomes a &amp;ldquo;perfect square&amp;rdquo; is constructed on each of the rational and algebraic sides.
On the rational side, $\prod (a-bm)$ becomes the square $X^2$ of some integer $X$, and on the algebraic side, the corresponding product of ideals becomes a perfect square $\gamma^2$ over the algebraic field.
By computing this $\gamma$ over the algebraic field and applying the homomorphism $\phi: \alpha \mapsto m \pmod n$ to the ring of rational integers, the congruence:
$X^2 \equiv \phi(\gamma)^2 \equiv Y^2 \pmod n$
is obtained.&lt;/p>
&lt;p>Computing the square root over the algebraic field requires deep knowledge of algebraic number theory, using complex algorithms such as &lt;strong>Montgomery&amp;rsquo;s Method&lt;/strong>. Finally, $\gcd(X-Y, n)$ is calculated, and if a non-trivial factor is obtained, the factorization is complete.&lt;/p>
&lt;hr>
&lt;h2 id="4-are-there-classical-algorithms-beyond-gnfs">4. Are There Classical Algorithms Beyond GNFS?
&lt;/h2>&lt;p>To date, no classical algorithm has been discovered whose asymptotic complexity falls below $L_n[1/3, c]$ for the factorization of general integers. However, there are some attempts and derivative algorithms to break through theoretical and practical limits.&lt;/p>
&lt;h3 id="41-multiple-number-field-sieve-mnfs">4.1 Multiple Number Field Sieve (MNFS)
&lt;/h3>&lt;p>As an approach extending GNFS, there is the &lt;strong>Multiple Number Field Sieve (MNFS)&lt;/strong> by D. Coppersmith. While GNFS uses two polynomials (rational side and algebraic side), MNFS uses multiple different algebraic side polynomials simultaneously for a single rational side polynomial.&lt;/p>
$$ f_1(x), f_{2,1}(x), f_{2,2}(x), \dots, f_{2,V}(x) $$
&lt;p>By utilizing multiple algebraic fields, the probability of &amp;ldquo;becoming smooth in any of the algebraic fields&amp;rdquo; can be dramatically increased in each sieving step. Coppersmith succeeded in slightly reducing the constant $c$ in the complexity $L_n[1/3, c]$ through this approach.
Specifically, while the constant of GNFS is $c = (64/9)^{1/3} \approx 1.923$, it has been theoretically shown that optimizing MNFS can reduce the complexity to about $c \approx 1.902$.
However, in practice, the overhead of managing multiple fields is large, and it has not yet led to a decisive breakthrough for RSA moduli on a practical scale.&lt;/p>
&lt;h3 id="42-is-an-l_n14-class-algorithm-possible">4.2 Is an $L_n[1/4]$ Class Algorithm Possible?
&lt;/h3>&lt;p>Regarding the limits of classical integer factorization algorithms, a theme that has been debated among mathematicians for many years is the question, &amp;ldquo;Does an algorithm with an exponent $\alpha = 1/4$ exist?&amp;rdquo;
Current GNFS and its derivatives are strongly bound to the framework of &amp;ldquo;searching for smoothness&amp;rdquo; by sieving, and within this paradigm, it is widely believed that $\alpha = 1/3$ is the limit. Even from the analysis of the distribution probability of smooth integers using the Dickman function, it is thought that with the current combination of algebraic field construction methods and sieves, the barrier of $O(L_n[1/3])$ cannot be crossed no matter how much it is optimized.&lt;/p>
&lt;p>If an $L_n[1/4]$ or even a classical polynomial-time algorithm were to exist, it would have to rely on entirely new mathematical structures that humanity currently cannot conceive of (for example, a more advanced algebraic geometry approach like Schoof&amp;rsquo;s algorithm for elliptic curve cryptography), completely different from the &amp;ldquo;smoothness-based&amp;rdquo; approach like GNFS. However, there are no signs of such at present.&lt;/p>
&lt;hr>
&lt;h2 id="5-breakthrough-by-quantum-computers-shors-algorithm">5. Breakthrough by Quantum Computers: Shor&amp;rsquo;s Algorithm
&lt;/h2>&lt;p>While classical computers face the barrier of $L_n[1/3]$, &lt;strong>Shor&amp;rsquo;s Algorithm&lt;/strong>, published by Peter Shor in 1994, smashed this barrier by fundamentally changing the computation model itself.&lt;/p>
&lt;h3 id="51-the-impact-of-quantum-polynomial-time">5.1 The Impact of Quantum Polynomial Time
&lt;/h3>&lt;p>Shor&amp;rsquo;s algorithm reduces the integer factorization problem to the &amp;ldquo;Order Finding Problem&amp;rdquo;. For a certain integer $a$, it is the problem of finding the period (order) $r$ of the function $f(x) = a^x \pmod n$.
While classical computers require exponential time to find this period, by using &lt;strong>Quantum Phase Estimation (QPE)&lt;/strong> and the &lt;strong>Quantum Fourier Transform (QFT)&lt;/strong> on a quantum computer, it is possible to evaluate all superpositions of states in parallel and extract the period $r$ with high probability.&lt;/p>
&lt;p>In terms of computational complexity, the execution time of Shor&amp;rsquo;s algorithm is &lt;strong>quantum polynomial time&lt;/strong>, specifically as follows:
&lt;/p>
$$ O((\log n)^3) $$
&lt;p>
Considering recent optimized circuit implementations, it is said that it can be reduced to $O((\log n)^2 \log \log n)$.&lt;/p>
&lt;div class="mermaid">graph LR
A["Classical Algorithm (GNFS)"] -->|Limit| B["Sub-exponential Time L_n[1/3]"]
C["Quantum Algorithm (Shor)"] -->|Breakthrough| D["Polynomial Time O((log n)^3)"]
B --> E["Continued use of RSA (Increase key length)"]
D --> F["Complete collapse of RSA cryptography"]&lt;/div>
&lt;h3 id="52-classical-sub-exponential-time-vs-quantum-polynomial-time">5.2 Classical Sub-exponential Time vs. Quantum Polynomial Time
&lt;/h3>&lt;p>The difference between these two complexity classes holds decisive meaning in real-world cryptographic security.&lt;/p>
&lt;p>For example, consider the case of factoring RSA-2048 (a 2048-bit composite number).&lt;/p>
&lt;ul>
&lt;li>&lt;strong>GNFS (Classical)&lt;/strong>: Substituting $n \approx 2^{2048}$ into $L_n[1/3, 1.923]$, about $2^{112}$ operations are required. This is an astronomical amount of computation that would take longer than the lifespan of the universe even if all the computing resources on Earth today were mobilized.&lt;/li>
&lt;li>&lt;strong>Shor&amp;rsquo;s Algorithm (Quantum)&lt;/strong>: With an $O((\log n)^3)$ algorithm, about $2048^3 \approx 8.5 \times 10^9$ logical gate operations are sufficient. This means that if appropriate hardware (a universal quantum computer with millions of physical qubits and error correction capabilities) exists, the calculation could be completed in just a few hours to a few days.&lt;/li>
&lt;/ul>
&lt;p>The paradigm shift from the sub-exponential function of &amp;ldquo;exponent $\alpha=1/3$&amp;rdquo; to &amp;ldquo;polynomial time&amp;rdquo; neutralizes the traditional cryptographic strategy of ensuring security by increasing the key length.&lt;/p>
&lt;hr>
&lt;h2 id="6-conclusion-outlook-for-the-next-generation">6. Conclusion: Outlook for the Next Generation
&lt;/h2>&lt;p>The current scientific consensus on the question &amp;ldquo;Are there classical algorithms beyond GNFS?&amp;rdquo; is as follows:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Practical improvements continue, but there are no asymptotic leaps&lt;/strong>: Attempts to improve the constant term $c$ of GNFS, such as MNFS, optimization of polynomial selection, and parallelization of the Block Wiedemann method, are ongoing. However, the possibility of discovering a classical algorithm with $\alpha$ falling below $1/3$ is considered extremely low.&lt;/li>
&lt;li>&lt;strong>The security of RSA on classical computers remains strong&lt;/strong>: The computational complexity of GNFS remains enormous, and RSA-2048 and RSA-4096 will continue to maintain their security against attacks by classical computers for decades to come.&lt;/li>
&lt;li>&lt;strong>The true threat is quantum algorithms&lt;/strong>: What crossed the barrier of computational complexity was Shor&amp;rsquo;s algorithm, based on the principles of quantum mechanics. As a result, the world is forced to transition to Post-Quantum Cryptography (PQC). The transition to new mathematical problems that are considered difficult to solve even for quantum computers (cannot be solved in polynomial time), such as lattice-based cryptography and hash-based cryptography, is currently at the forefront of cryptography.&lt;/li>
&lt;/ol>
&lt;p>The General Number Field Sieve (GNFS) is one of the &amp;ldquo;highest peaks&amp;rdquo; humanity has reached by challenging the limits of classical mathematics and algorithm design. Understanding the profound mathematical structure of GNFS is not merely learning the history of cryptanalysis, but also an intellectual journey of exploration that touches upon the beauty of computational complexity theory and algebraic number theory. Until the day quantum computers are put into practical use, GNFS will likely continue to defend its throne as the strongest integer factorization algorithm.&lt;/p></description></item><item><title>Simulating Shor's Algorithm in Python</title><link>http://kenji.blog/en/p/shors-algorithm-simulation-python/</link><pubDate>Fri, 11 Sep 2026 08:00:00 +0900</pubDate><guid>http://kenji.blog/en/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 Simulating Shor's Algorithm in Python" />&lt;h1 id="1-introduction-the-cryptographic-crisis-brought-by-quantum-computers">1. Introduction: The Cryptographic Crisis Brought by Quantum Computers
&lt;/h1>&lt;p>Much of the security in modern internet society relies on &lt;strong>public-key cryptography&lt;/strong> (especially RSA encryption). When we transmit credit card information for online shopping or exchange highly confidential data, the content of that communication is strongly protected by RSA encryption.&lt;/p>
&lt;p>The basis for the security of RSA encryption relies on the mathematical fact that &amp;ldquo;&lt;strong>factoring huge integers is extremely difficult for classical computers (the PCs and supercomputers we use every day).&lt;/strong>&amp;rdquo; However, &lt;strong>Shor&amp;rsquo;s Algorithm&lt;/strong>, published by Peter Shor in 1994, fundamentally overturned this premise. It was mathematically proven that if Shor&amp;rsquo;s algorithm were executed on a large-scale quantum computer, it could solve factorization problems—which would take classical computers longer than the age of the universe—in just minutes to hours.&lt;/p>
&lt;p>In this article, we will thoroughly explain how Shor&amp;rsquo;s algorithm performs integer factorization so quickly in detail, from its mathematical mechanics to a concrete simulation implementation using Python and the quantum computing framework &lt;strong>Qiskit&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h1 id="2-dramatic-shift-in-computational-complexity-from-exponential-to-polynomial-time">2. Dramatic Shift in Computational Complexity: From Exponential to Polynomial Time
&lt;/h1>&lt;p>Why is prime factorization so difficult? Even if we use the &amp;ldquo;General Number Field Sieve (GNFS),&amp;rdquo; known as the best factorization algorithm for classical computers, its computational complexity is sub-exponential.&lt;/p>
&lt;p>The time complexity to factorize a composite number of $N$ digits using classical methods is as follows:&lt;/p>
$$ O\left(\exp\left( c (\log N)^{1/3} (\log \log N)^{2/3} \right)\right) $$
&lt;p>Because of this, simply increasing the key length (e.g., to 2048 bits or 4096 bits) ensures that deciphering it on a classical computer would take thousands or tens of thousands of years—an unrealistic amount of time.&lt;/p>
&lt;p>However, using &lt;strong>Shor&amp;rsquo;s Algorithm&lt;/strong> on a quantum computer dramatically reduces the computational complexity to polynomial time relative to the number of input bits $\log N$:&lt;/p>
$$ O((\log N)^3) $$
&lt;p>This means that if we double the number of bits, the computation time on a classical computer increases astronomically, whereas on a quantum computer it only increases by at most about 8 times. This &lt;strong>reduction in complexity class from exponential time to polynomial time (inclusion in the BQP class)&lt;/strong> is the true marvel of Shor&amp;rsquo;s algorithm.&lt;/p>
&lt;div class="mermaid">graph TD
A["Increase in input size (bits) N"] --> B{"Algorithm selection"}
B -->|Classical: General Number Field Sieve| C["Sub-exponential increase O(exp(...))"]
B -->|Quantum: Shor's algorithm| D["Polynomial time O((log N)^3)"]
C --> E["Thousands to billions of years (Undecipherable)"]
D --> F["Minutes to hours (Decipherable in realistic time)"]&lt;/div>
&lt;hr>
&lt;h1 id="3-algorithm-overview-and-mathematical-background">3. Algorithm Overview and Mathematical Background
&lt;/h1>&lt;p>Shor&amp;rsquo;s algorithm does not actually perform everything on a quantum computer. It is composed of a collaboration between pre-processing and post-processing on a classical computer and the core part (the order-finding algorithm) on a quantum computer.&lt;/p>
&lt;p>The overall flow of the algorithm is as follows:&lt;/p>
&lt;div class="mermaid">graph TD
A["Input: Composite number N to be factored"] --> B["Choose a random number a such that a &lt; N"]
B --> C{"gcd(a, N) > 1 ?"}
C -- "Yes" --> D["Output trivial factor gcd(a, N) and terminate"]
C -- "No" --> E["Find the period r of f(x) = a^x mod N using quantum algorithm"]
E --> F{"Is r even AND a^(r/2) ≢ -1 mod N ?"}
F -- "No" --> B
F -- "Yes" --> G["Calculate factors p = gcd(a^(r/2) - 1, N), q = gcd(a^(r/2) + 1, N)"]
G --> H["Output: p, q"]&lt;/div>
&lt;h2 id="reduction-of-factorization-to-the-order-finding-problem">Reduction of Factorization to the Order Finding Problem
&lt;/h2>&lt;p>Shor&amp;rsquo;s stroke of genius lies in converting the &amp;ldquo;&lt;strong>factorization problem&lt;/strong>&amp;rdquo; into an &amp;ldquo;&lt;strong>Order Finding Problem&lt;/strong>&amp;rdquo;.&lt;/p>
&lt;p>Consider an integer $N$ (the number to be factored) and an integer $a$ coprime to $N$ ($1 &lt; a &lt; N$). We define the following modular exponentiation function:&lt;/p>
$$ f(x) = a^x \bmod N $$
&lt;p>This function has a certain period $r$. That is, $f(x+r) = f(x)$ holds true for any $x$. In particular, when $x=0$, the smallest positive integer $r$ such that:&lt;/p>
$$ a^r \equiv 1 \pmod N $$
&lt;p>is called the &amp;ldquo;order of $a$ modulo $N$&amp;rdquo;. If we can find this period $r$, we can derive the prime factors as follows.&lt;/p>
&lt;p>Rearranging the equation gives:
&lt;/p>
$$ a^r - 1 \equiv 0 \pmod N $$
&lt;p>
If $r$ is even, we can factor it using the difference of squares formula:
&lt;/p>
$$ (a^{r/2} - 1)(a^{r/2} + 1) \equiv 0 \pmod N $$
&lt;p>This means that $N$ shares a common divisor with either $(a^{r/2} - 1)$ or $(a^{r/2} + 1)$ (provided that the condition $a^{r/2} \not\equiv -1 \pmod N$ is met). Therefore, using the Euclidean algorithm to calculate:&lt;/p>
$$ p = \gcd(a^{r/2} - 1, N) $$
$$ q = \gcd(a^{r/2} + 1, N) $$
&lt;p>allows us to find the non-trivial prime factors $p, q$ of $N$. This computation (calculating the greatest common divisor and generating random numbers) can be done extremely fast on classical computers. The problem is thus narrowed down to &lt;strong>how to find the period $r$ quickly&lt;/strong>. On a classical computer, finding this period $r$ itself takes exponential time. This is where the quantum computer comes into play.&lt;/p>
&lt;hr>
&lt;h1 id="4-quantum-algorithm-part-mechanics-of-order-finding">4. Quantum Algorithm Part: Mechanics of Order Finding
&lt;/h1>&lt;p>The subroutine for finding the period $r$ using a quantum computer consists of the following 4 steps:&lt;/p>
&lt;div class="mermaid">graph LR
subgraph "Quantum State Transitions"
S1["|0⟩|0⟩ (Initialization)"] --> S2["H Gate: Superposition Σ|x⟩|0⟩"]
S2 --> S3["Oracle U: Σ|x⟩|a^x mod N⟩"]
S3 --> S4["QFT: Period extraction via interference"]
S4 --> S5["Measurement: Obtain approximated value y"]
end&lt;/div>
&lt;h2 id="step-1-initialization-of-quantum-registers-and-superposition">Step 1: Initialization of Quantum Registers and Superposition
&lt;/h2>&lt;p>First, we prepare two quantum registers. The first register is for inputting states, and the second register is for storing the result of the function&amp;rsquo;s calculation.
The initial state is all $|0\rangle$.&lt;/p>
$$ |\psi_0\rangle = |0\rangle_1 |0\rangle_2 $$
&lt;p>We apply Hadamard gates to all qubits in the first register, creating an equal-probability superposition of all possible inputs $x$ (from $0$ to $Q-1$, where $Q=2^n$).&lt;/p>
$$ |\psi_1\rangle = \frac{1}{\sqrt{Q}} \sum_{x=0}^{Q-1} |x\rangle_1 |0\rangle_2 $$
&lt;p>Through this, the quantum computer simultaneously holds the states for all $Q$ inputs in a single operation. This is the powerful source of &lt;strong>quantum parallelism&lt;/strong>.&lt;/p>
&lt;h2 id="step-2-application-of-the-oracle-function-modular-exponentiation">Step 2: Application of the Oracle Function (Modular Exponentiation)
&lt;/h2>&lt;p>Next, using a quantum arithmetic circuit $U_f$, we calculate the function $f(x) = a^x \bmod N$ and store the result in the second register.&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>At this point, the first and second registers are in a state of &lt;strong>quantum entanglement&lt;/strong>. If we were to (hypothetically) observe the second register and obtain a specific value $k = a^{x_0} \bmod N$, the state of the first register would collapse into a superposition of $x$ values that yield that $k$. Since the period of the function is $r$, the remaining states will be values separated by $r$: $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>However, we do not want to know $x_0$; we want to know the period $r$ itself. It is impossible to observe $r$ directly from this state. Therefore, we use the Quantum Fourier Transform.&lt;/p>
&lt;h2 id="step-3-phase-interference-via-quantum-fourier-transform-qft">Step 3: Phase Interference via Quantum Fourier Transform (QFT)
&lt;/h2>&lt;p>We apply the &lt;strong>Quantum Fourier Transform (QFT)&lt;/strong> to the first register. QFT is the quantum version of the classical discrete Fourier transform, and it transforms the amplitudes of the state vector. The action of QFT on the basis state $|x\rangle$ is defined as follows:&lt;/p>
$$ QFT |x\rangle = \frac{1}{\sqrt{Q}} \sum_{y=0}^{Q-1} \omega^{xy} |y\rangle $$
&lt;p>Here, $\omega = e^{2\pi i / Q}$.&lt;/p>
&lt;p>When QFT is applied, the state amplitudes interfere with each other. Skipping the mathematical details, when QFT is applied to a state with period $r$, the waves cause &lt;strong>Constructive Interference&lt;/strong> only when $y$ is extremely close to an integer multiple of $Q/r$. For all other states, the probability amplitudes cancel out due to &lt;strong>Destructive Interference&lt;/strong>, approaching zero.&lt;/p>
&lt;h2 id="step-4-measurement-and-continued-fraction-expansion">Step 4: Measurement and Continued Fraction Expansion
&lt;/h2>&lt;p>Finally, we measure the first register. The value $y$ obtained from the measurement will satisfy the following condition with high probability:&lt;/p>
$$ y \approx c \frac{Q}{r} \implies \frac{y}{Q} \approx \frac{c}{r} $$
&lt;p>(where $c$ is an unknown integer such that $0 \le c &lt; r$)&lt;/p>
&lt;p>By applying the classical algorithm of &lt;strong>Continued Fraction Expansion&lt;/strong> to the obtained rational number $y/Q$, we can calculate the approximated fraction $c/r$ and extract the period $r$ from its denominator.&lt;/p>
&lt;hr>
&lt;h1 id="5-simulation-implementation-using-python-and-qiskit">5. Simulation Implementation using Python and Qiskit
&lt;/h1>&lt;p>Since theory alone can be hard to grasp, let&amp;rsquo;s actually simulate Shor&amp;rsquo;s algorithm using Python and IBM&amp;rsquo;s quantum computing framework, &lt;strong>Qiskit&lt;/strong>.&lt;/p>
&lt;p>Here, we will implement the most classic and famous example scenario: &lt;strong>&amp;ldquo;Factoring $N=15$ using $a=7$.&amp;rdquo;&lt;/strong>&lt;/p>
&lt;h2 id="preparation-of-the-execution-environment">Preparation of the Execution Environment
&lt;/h2>&lt;p>Please install Qiskit beforehand.&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="overview-of-the-python-implementation-code">Overview of the Python Implementation Code
&lt;/h2>&lt;p>The code below is an example implementation of Shor&amp;rsquo;s algorithm specialized for $N=15, a=7$. Because building a general-purpose modular exponentiation circuit is currently too computationally expensive for simulators, we are hardcoding the gate operations for the specific case of $a=7$.&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. Function to build the inverse Quantum Fourier Transform (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;Generates an n-qubit inverse Quantum Fourier Transform circuit&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 gates to reverse the order&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"># Applying controlled-phase and H gates&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. Function to build the controlled modular exponentiation for 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;Generates a controlled U gate for specific a and power (N=15 only)&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"># Hardcoded logic for 7^x mod 15 when 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. Main quantum circuit configuration&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: Number of qubits in the control register&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># The target register is 4 bits to represent 0 to 15&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">QuantumCircuit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n_count&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n_count&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Initialization of the 1st register (control register) (Generating 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"># Initialization of the 2nd register (target register) to |1&amp;gt; (0001)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">n_count&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Application of the controlled modular exponentiation (oracle)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">q&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n_count&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Apply the operation for 2^q&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">c_amod15&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="n">q&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="n">q&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="n">n_count&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">)])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Apply inverse quantum Fourier transform to the 1st 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"># Measure the 1st 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">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"># --- Execution Section ---&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"># Use 8 qubits for the control register (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;Search settings: 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">, Control 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"># Generate the circuit&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">shor_circuit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n_count&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Execute on the 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"># transpilation is recommended in newer Qiskit versions&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">Measurement results (bitstring: observation count):&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"> times&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"># Classical post-processing: Identifying period r using continued fraction expansion&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">--- Period calculation and factorization ---&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"># Convert bitstring to decimal&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 = measurement value / 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"># Get approximated fraction using continued fraction expansion. Denominator limit is 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;Observation: &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"> | Continued fraction: &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"> | Estimated period 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"># Check if period r is even and yields valid results&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; Success! The prime factors of &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"> are &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"> and &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; Only trivial factors found. Try again.&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; Failed because the period is odd.&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-explanation-and-result-analysis">Code Explanation and Result Analysis
&lt;/h2>&lt;p>When executing the above code, specific peaks (observed values) are obtained with high probability as the measurement results of the control register. In the case of &lt;code>n_count=8&lt;/code> ($Q=256$), with an ideal quantum computer (or simulator), values like &lt;code>0&lt;/code>, &lt;code>64&lt;/code>, &lt;code>128&lt;/code>, and &lt;code>192&lt;/code> will appear as observed values with overwhelming probability.&lt;/p>
&lt;p>Dividing these by $Q=256$, the phase $y/Q$ becomes $0.0$, $0.25$, $0.5$, and $0.75$, respectively.
Applying continued fraction expansion to these phases yields:&lt;/p>
&lt;ul>
&lt;li>$0.25 \to 1/4$ (Estimated period $r=4$)&lt;/li>
&lt;li>$0.50 \to 1/2$ (Estimated period $r=2$)&lt;/li>
&lt;li>$0.75 \to 3/4$ (Estimated period $r=4$)&lt;/li>
&lt;/ul>
&lt;p>Using the period $r=4$ obtained here, we calculate the prime factors.
Since $a=7, r=4$:
$p = \gcd(7^2 - 1, 15) = \gcd(48, 15) = 3$
$q = \gcd(7^2 + 1, 15) = \gcd(50, 15) = 5$&lt;/p>
&lt;p>Brilliantly, we have successfully factorized $15 = 3 \times 5$.&lt;/p>
&lt;blockquote>
&lt;p>[!TIP]
If a measurement value of $y=128$ (phase $0.5$) is obtained, the denominator becomes $2$, yielding a divisor of the true period rather than the true period $r=4$. In such cases, the true period can be reached by either executing the algorithm multiple times or by investigating multiples of the obtained $r$.&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h1 id="6-challenges-toward-practical-application-and-the-limits-of-the-nisq-era">6. Challenges Toward Practical Application and the Limits of the NISQ Era
&lt;/h1>&lt;p>While it was easy to factorize $N=15$ on a simulator, factoring RSA-2048 (a 617-digit decimal number) used in real-world applications still faces numerous walls for actual quantum computers.&lt;/p>
&lt;p>The era we are currently living in is called the &lt;strong>NISQ (Noisy Intermediate-Scale Quantum) era&lt;/strong>. Qubits are extremely vulnerable to noise from the external environment, and their states break down midway through computations due to &amp;ldquo;decoherence.&amp;rdquo;&lt;/p>
&lt;p>In order to accurately execute deep circuits (with many gates) like Shor&amp;rsquo;s algorithm, &lt;strong>Quantum Error Correction&lt;/strong> to correct noise is essential. To create a single noise-free &amp;ldquo;logical qubit,&amp;rdquo; it is necessary to encode thousands of &amp;ldquo;physical qubits&amp;rdquo; using methods like the Surface Code.&lt;/p>
&lt;p>To break 2048-bit RSA encryption, it is estimated that thousands of perfect logical qubits are required, and realizing this would necessitate a fault-tolerant quantum computer equipped with &lt;strong>millions to tens of millions of physical qubits&lt;/strong>. Since even the most advanced current quantum processors only have around a few hundred to a few thousand physical qubits, the world&amp;rsquo;s cryptography will not be broken immediately.&lt;/p>
&lt;blockquote>
&lt;p>[!WARNING]
However, there exists a threat model known as &amp;ldquo;Store Now, Decrypt Later&amp;rdquo;. Attackers might store large amounts of currently encrypted confidential communication data, adopting a strategy to decrypt everything all at once 10 to 20 years later the moment a powerful quantum computer is completed.&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h1 id="7-transitioning-to-post-quantum-cryptography-pqc">7. Transitioning to Post-Quantum Cryptography (PQC)
&lt;/h1>&lt;p>In preparation for the arrival of &amp;ldquo;Q-Day&amp;rdquo; (the day quantum computers break cryptography), cryptographers around the world, spearheaded by the National Institute of Standards and Technology (NIST) in the US, are pushing forward with the standardization of &lt;strong>Post-Quantum Cryptography (PQC)&lt;/strong>.&lt;/p>
&lt;p>PQC is based on new mathematical problems (such as lattice problems, multivariate polynomial problems, and hash-based functions) that are mathematically considered inefficient to solve even using Shor&amp;rsquo;s algorithm (or Grover&amp;rsquo;s algorithm). Algorithms like &amp;ldquo;CRYSTALS-Kyber&amp;rdquo; and &amp;ldquo;CRYSTALS-Dilithium&amp;rdquo; have already been selected as standard specifications, and their integration into Apple&amp;rsquo;s iMessage and various web browser communication protocols is gradually beginning.&lt;/p>
&lt;p>For engineers managing IT infrastructure, building &amp;ldquo;crypto-agility&amp;rdquo; (the ability to quickly switch cryptographic methods) into systems to transition from existing RSA or elliptic curve cryptography to PQC will be a major mission going forward.&lt;/p>
&lt;hr>
&lt;h1 id="8-conclusion">8. Conclusion
&lt;/h1>&lt;p>In this article, we provided a thorough explanation on a scale of 10,000 characters, starting from the theoretical mathematical background of Shor&amp;rsquo;s algorithm, covering the mechanics of period extraction using the Quantum Fourier Transform, and ending with a concrete simulation code using Python and Qiskit.&lt;/p>
&lt;p>The fact that the laws of physics in the microscopic world of quantum mechanics can fundamentally overturn computational complexity theory and cryptography—which are the foundations of macroscopic information science—is one of the most exciting paradigm shifts in the history of science. We must keep a close eye on the ongoing offensive and defensive battle between the continuously evolving quantum computing technology and the new cryptographic techniques standing up against it.&lt;/p>
&lt;p>By all means, please try executing the Python code introduced this time in your own environment, and experience the &amp;ldquo;magic of computation&amp;rdquo; created by the superposition and interference of quantum states.&lt;/p>
&lt;hr>
&lt;p>&lt;strong>References&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>[Illustrated PQC] Comparison of Major Post-Quantum Cryptography Algorithms</title><link>http://kenji.blog/en/p/post-quantum-cryptography-algorithms-comparison/</link><pubDate>Fri, 11 Sep 2026 07:00:00 +0900</pubDate><guid>http://kenji.blog/en/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 [Illustrated PQC] Comparison of Major Post-Quantum Cryptography Algorithms" />&lt;h2 id="1-introduction-the-cryptography-crisis-brought-by-quantum-computers">1. Introduction: The &amp;ldquo;Cryptography Crisis&amp;rdquo; Brought by Quantum Computers
&lt;/h2>&lt;p>In modern internet society, public-key cryptography is indispensable infrastructure for protecting the confidentiality of communications and data integrity. The widely used RSA cryptography and Elliptic Curve Cryptography (ECC) rely on the mathematical barriers of &amp;ldquo;the difficulty of factoring large composite numbers&amp;rdquo; and &amp;ldquo;the difficulty of the discrete logarithm problem on elliptic curves,&amp;rdquo; respectively. It has been proven that classical computers (including the supercomputers we use today) would take longer than the age of the universe to solve these mathematical problems, which has been the basis of their security.&lt;/p>
&lt;p>However, this solid premise is about to be completely overturned by the theory and practical advancement of &lt;strong>quantum computers&lt;/strong>. The &amp;ldquo;&lt;strong>Shor&amp;rsquo;s Algorithm&lt;/strong>&amp;rdquo;, published by cryptographer Peter Shor in 1994, theoretically proved that the integer factorization problem and the discrete logarithm problem can be solved in &amp;ldquo;polynomial time&amp;rdquo; by running it on a sufficiently capable Cryptographically Relevant Quantum Computer (CRQC). This means that all public-key cryptography currently in use will be rendered powerless.&lt;/p>
&lt;div class="mermaid">graph TD
A["Large-scale Quantum Computer (CRQC)"] -->|Execution| B["Shor's Algorithm"]
B -->|Decryption in polynomial time| C["Integer Factorization Problem (RSA)"]
B -->|Decryption in polynomial time| D["Discrete Logarithm Problem (ECC / ECDSA)"]
C --> E["Eavesdropping, data tampering, and spoofing of encrypted communications"]
D --> E
F["Store Now, Decrypt Later (SNDL)"] --> E&lt;/div>
&lt;p>It is extremely dangerous to think that &amp;ldquo;there is no problem because the full-scale completion of quantum computers is still decades away.&amp;rdquo; This is because an attack method called &lt;strong>Store Now, Decrypt Later (SNDL)&lt;/strong> is already a real threat. This is an attack where malicious states or hacker organizations save a massive amount of currently encrypted communication data (such as TLS traffic) in storage and decrypt all of it the moment a powerful quantum computer becomes available in the future. State secrets, infrastructure information, and medical data that need long-term protection are already exposed to this threat.&lt;/p>
&lt;p>Furthermore, for symmetric-key cryptography (such as AES) and hash functions (such as SHA-256), there is &lt;strong>Grover&amp;rsquo;s Algorithm&lt;/strong>, discovered in 1996. This reduces the computational complexity of a brute-force attack to its square root. In other words, the security level of AES-128 is effectively halved to $2^{64}$, so it is recommended to use longer keys and hash lengths, such as AES-256 and SHA-384, in the quantum era.&lt;/p>
&lt;p>To counter this unprecedented cryptography crisis, &lt;strong>Post-Quantum Cryptography (PQC)&lt;/strong> was born, which is based on new mathematical problems that are difficult to decrypt even with a quantum computer. This article provides an extremely detailed explanation of the major PQC algorithms, from their mathematical background to their mechanisms and architectural comparisons, based on the results of the PQC standardization process led by the National Institute of Standards and Technology (NIST) in the United States.&lt;/p>
&lt;hr>
&lt;h2 id="2-overview-and-history-of-the-nist-pqc-standardization-project">2. Overview and History of the NIST PQC Standardization Project
&lt;/h2>&lt;p>Transitioning cryptographic technologies takes years to decades, including redesigning protocols, updating systems, and replacing hardware. Therefore, cryptographers around the world have been advancing PQC research since early on. The US NIST (National Institute of Standards and Technology) has played a central role in this. In 2016, NIST announced a public call for the PQC standardization process and accepted entirely new cryptographic algorithm proposals from the global cryptographic community.&lt;/p>
&lt;p>The targets for standardization were the following two main categories:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Public-Key Cryptography / Key Encapsulation Mechanism (KEM)&lt;/strong>: A mechanism for securely sharing (distributing) a shared key to encrypt the communication path, such as in TLS connections.&lt;/li>
&lt;li>&lt;strong>Digital Signatures&lt;/strong>: A mechanism to prove that data has not been tampered with and that there is no spoofing of the sender (authenticity) in software updates and electronic certificates.&lt;/li>
&lt;/ol>
&lt;p>After a fierce competition of evaluation, analysis, and cryptanalysis spanning about 6 years (Round 1 to Round 3), further evaluation for Round 4 was conducted for some algorithms. As a result, the following algorithms were officially published as Federal Information Processing Standards (FIPS) in 2024 and established as the future global standards:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>FIPS 203 (ML-KEM)&lt;/strong>: KEM based on CRYSTALS-Kyber&lt;/li>
&lt;li>&lt;strong>FIPS 204 (ML-DSA)&lt;/strong>: Digital signature based on CRYSTALS-Dilithium&lt;/li>
&lt;li>&lt;strong>FIPS 205 (SLH-DSA)&lt;/strong>: Stateless hash-based signature based on SPHINCS+&lt;/li>
&lt;li>&lt;strong>(Scheduled for future formulation) FN-DSA&lt;/strong>: Digital signature based on FALCON&lt;/li>
&lt;/ul>
&lt;p>These selected algorithms rely on different mathematical &amp;ldquo;hardness problems,&amp;rdquo; ensuring diversity (Crypto Agility) so that even if a fatal vulnerability is discovered in one algorithm in the future, the entire system will not collapse. In the standardization process, lattice-based cryptography became the main player mainly due to its performance, but hash-based cryptography and code-based cryptography were adopted as powerful backups.&lt;/p>
&lt;hr>
&lt;h2 id="3-classification-of-major-mathematical-approaches-in-pqc">3. Classification of Major Mathematical Approaches in PQC
&lt;/h2>&lt;p>PQC algorithms are broadly divided into the following five categories based on the mathematical problems that form the basis of their security. This article delves deeply into the top three in particular.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Lattice-based Cryptography&lt;/strong>:
Based on the Shortest Vector Problem (SVP) and Closest Vector Problem (CVP) in multidimensional lattice spaces, and the derived LWE problem. It is the center of NIST standardization, and Kyber, Dilithium, and FALCON fall into this category. It has the best balance of processing speed, public key size, and ciphertext size, making it suitable for general-purpose use.&lt;/li>
&lt;li>&lt;strong>Hash-based Cryptography&lt;/strong>:
Relies solely on the &amp;ldquo;collision resistance&amp;rdquo; and &amp;ldquo;one-wayness&amp;rdquo; of cryptographic hash functions (such as SHA-2 and SHAKE) for its security basis. It is only applicable to digital signatures (such as SPHINCS+), but its security proof is the strongest, and it features extremely high resistance to unknown mathematical attacks.&lt;/li>
&lt;li>&lt;strong>Code-based Cryptography&lt;/strong>:
Based on the theory of error-correcting codes, it relies on the difficulty of the Syndrome Decoding Problem. Classic McEliece, proposed in the 1970s, is a representative example, having a very long history and proven security, but on the other hand, the public key size is extremely large, in the megabyte range.&lt;/li>
&lt;li>&lt;strong>Multivariate Polynomial Cryptography&lt;/strong>:
Based on the difficulty of finding a solution to a system of multivariate quadratic equations over a finite field (MQ problem). It was mainly proposed as digital signatures (such as Rainbow), but during the final round of NIST, a powerful attack method that could crack it in a few days on a single PC was discovered, and many algorithms dropped out of the standardization.&lt;/li>
&lt;li>&lt;strong>Isogeny-based Cryptography&lt;/strong>:
Based on the path-finding problem on an isogeny graph of elliptic curves. The key size is very small, and it was expected to be a legitimate successor to ECC, but &amp;ldquo;SIKE,&amp;rdquo; the final candidate, was completely broken in just a few hours on a normal PC in 2022 using classical mathematics (such as the Castryck-Decru attack), marking a dramatic end that symbolized the difficulty and terror of PQC design.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="4-the-abyss-of-lattice-cryptography-mathematical-foundation-of-the-lwe-problem-and-module-lwe">4. The Abyss of Lattice Cryptography: Mathematical Foundation of the LWE Problem and Module-LWE
&lt;/h2>&lt;p>&lt;strong>Lattice-based cryptography&lt;/strong> is currently considered the most promising and has become the center of standardization. At the root of its security is the &lt;strong>LWE (Learning with Errors) problem&lt;/strong>. Proposed by Oded Regev in 2005, this groundbreaking achievement earned him the Gödel Prize. One cannot talk about modern PQC without understanding the LWE problem.&lt;/p>
&lt;h3 id="41-what-is-the-lwe-learning-with-errors-problem">4.1. What is the LWE (Learning with Errors) Problem?
&lt;/h3>&lt;p>First, consider a simple system of linear equations. Suppose there is a known random matrix $A$ and an unknown secret vector $\vec{s}$ under a certain modulus $q$ (modulo $q$), and their product $\vec{b}$ is given:&lt;/p>
$$ \vec{b} = A\vec{s} \pmod q $$
&lt;p>In this case, it is easy to find the unknown $\vec{s}$ from the public information $A$ and $\vec{b}$. Using the classical algorithm &amp;ldquo;Gaussian elimination,&amp;rdquo; $\vec{s}$ can be easily calculated in polynomial time.&lt;/p>
&lt;p>However, adding a &amp;ldquo;small intentional error (noise)&amp;rdquo; to this equation dramatically increases the difficulty of the problem. This is the &lt;strong>LWE problem&lt;/strong>.&lt;/p>
&lt;p>Prepare an unknown secret vector $\vec{s} \in \mathbb{Z}_q^n$ and a randomly chosen matrix $A \in \mathbb{Z}_q^{m \times n}$. Furthermore, prepare an error vector $\vec{e} \in \mathbb{Z}_q^m$ whose &amp;ldquo;elements have sufficiently small values,&amp;rdquo; chosen according to a normal or binomial distribution, and calculate $\vec{b}$ as follows:&lt;/p>
$$ \vec{b} = A\vec{s} + \vec{e} \pmod q $$
&lt;p>The &lt;strong>Search LWE problem&lt;/strong> is the problem of &amp;ldquo;finding the secret information $\vec{s}$ from the public information $(A, \vec{b})$.&amp;rdquo; Due to the existence of this error $\vec{e}$, if one attempts an algebraic solution such as Gaussian elimination, the error $\vec{e}$ amplifies like a snowball in the process of adding and subtracting equations, ultimately becoming indistinguishable from random values and breaking down.&lt;/p>
&lt;p>The greatness of the LWE problem lies in the fact that there is a powerful theoretical proof (reduction) that unless there is a quantum algorithm that can solve GapSVP (Decision Shortest Vector Problem) and SIVP (Shortest Independent Vector Problem), which are &amp;ldquo;worst-case hardness&amp;rdquo; problems on lattices, the LWE problem cannot be solved in the average-case either. In other words, even for a randomly generated cryptographic key, it is guaranteed to have robust security backed by a theoretical upper bound.&lt;/p>
&lt;h3 id="42-dramatic-efficiency-improvement-by-ring-lwe-and-module-lwe">4.2. Dramatic Efficiency Improvement by Ring-LWE and Module-LWE
&lt;/h3>&lt;p>The normal LWE problem (Standard LWE) has a very clear basis for security, but the size of the matrix $A$ becomes very large, and the key size reaches the megabyte class, making it impractical. Therefore, an approach was proposed to provide an algebraic structure by utilizing Polynomial Rings.&lt;/p>
&lt;p>In the &lt;strong>Ring-LWE problem&lt;/strong>, instead of simple vectors and matrices, elements (polynomials) of a certain polynomial ring $R_q$ are used. The following cyclotomic polynomial ring is generally used in the NIST standard:&lt;/p>
$$ R_q = \mathbb{Z}_q[X]/(X^n + 1) $$
&lt;p>Here, $n$ is a power of 2 (e.g., 256), and $q$ is an appropriate prime number. Over this ring, using elements $a, s, e \in R_q$, $b = a \cdot s + e \pmod q$ is calculated. Because a single polynomial $a$ has $n$ coefficients, data can be significantly compressed, and by using the finite field version of the Fast Fourier Transform (FFT) called &lt;strong>NTT (Number Theoretic Transform)&lt;/strong>, ultra-fast polynomial multiplication becomes possible with a computational complexity of $O(n \log n)$.&lt;/p>
&lt;p>However, Ring-LWE had concerns that &amp;ldquo;there might be an unknown vulnerability due to the special algebraic structure of the ring.&amp;rdquo; Furthermore, there was an engineering challenge that when changing the security level (such as AES-128, 192, 256 equivalent), the degree $n$ of the polynomial itself had to be changed, and the entire implementation, such as the NTT algorithm, had to be rewritten accordingly.&lt;/p>
&lt;p>Therefore, the &lt;strong>Module-LWE (M-LWE) problem&lt;/strong> was adopted by standardization algorithms such as Kyber and Dilithium. Module-LWE is a compromise situated exactly halfway between the structureless Standard LWE and the overly structured Ring-LWE, using a $k \times k$ matrix (module) whose components are elements of the polynomial ring $R_q$:&lt;/p>
$$ \vec{b} = A\vec{s} + \vec{e} \pmod{R_q} \quad (A \in R_q^{k \times k}, \vec{s}, \vec{e} \in R_q^k) $$
&lt;p>The greatest advantage of Module-LWE is that the security level can be easily scaled simply by changing the matrix dimension $k$ while keeping the polynomial degree $n$ (in the NIST standard, $n=256$) fixed.
For example, in Kyber, the dimension $k$ is adjusted as follows:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Kyber512 (Level 1)&lt;/strong>: $k = 2$ (equivalent to AES-128)&lt;/li>
&lt;li>&lt;strong>Kyber768 (Level 3)&lt;/strong>: $k = 3$ (equivalent to AES-192)&lt;/li>
&lt;li>&lt;strong>Kyber1024 (Level 5)&lt;/strong>: $k = 4$ (equivalent to AES-256)&lt;/li>
&lt;/ul>
&lt;p>This made it possible to reuse 100% of the underlying NTT code and polynomial operation hardware circuits across all security levels, dramatically improving implementation security and efficiency.&lt;/p>
&lt;hr>
&lt;h2 id="5-crystals-kyber-ml-kem-next-generation-key-encapsulation-mechanism">5. CRYSTALS-Kyber (ML-KEM): Next-Generation Key Encapsulation Mechanism
&lt;/h2>&lt;p>CRYSTALS-Kyber, officially standardized as &lt;strong>FIPS 203 (ML-KEM)&lt;/strong>, is a Key Encapsulation Mechanism (KEM) based on the aforementioned Module-LWE problem. It will become the de facto global standard for securely sharing session keys in TLS 1.3, SSH, and the like in the future.&lt;/p>
&lt;h3 id="51-architecture-of-kem-key-encapsulation-mechanism">5.1. Architecture of KEM (Key Encapsulation Mechanism)
&lt;/h3>&lt;p>In the PQC era, instead of a direct approach like RSA where &amp;ldquo;the client creates a common key, encrypts it with the server&amp;rsquo;s public key, and sends it,&amp;rdquo; a KEM encapsulation framework becomes the 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: "Generate secret key (sk) and public key (pk)"
Client->>Server: "Send public key (pk)"
Note over Server: "ML-KEM Encaps()"
Server->>Server: "Generate a random shared key (K)"
Server->>Server: "Encapsulate K with pk to create ciphertext (c)"
Server->>Client: "Send ciphertext (c)"
Note over Client: "ML-KEM Decaps()"
Client->>Client: "Decrypt ciphertext (c) using secret key (sk)"
Client->>Client: "Decapsulate and extract the shared key (K)"
Note over Client, Server: "Start encrypted communication (e.g. AES) using the shared key (K)"&lt;/div>
&lt;h3 id="52-kybers-internal-algorithm-mechanism-and-the-fujisaki-okamoto-transform">5.2. Kyber&amp;rsquo;s Internal Algorithm Mechanism and the Fujisaki-Okamoto Transform
&lt;/h3>&lt;p>Kyber&amp;rsquo;s design is highly sophisticated. First, it constructs a public-key encryption scheme (Kyber.CPAPKE) that is secure only against CPA (Chosen Plaintext Attack), and then adopts a design that upgrades it into a complete KEM that is secure against CCA (Adaptive Chosen Ciphertext Attack) by applying a cryptographically extremely powerful method called the &lt;strong>Fujisaki-Okamoto Transform&lt;/strong>.&lt;/p>
&lt;p>The core encryption and decryption mechanisms of CPAPKE are as follows:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Key Generation&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>From a random seed value, generate a matrix $A \in R_q^{k \times k}$ in the NTT domain. The modulus $q$ used is $3329$.&lt;/li>
&lt;li>Sample a secret vector $\vec{s}$ and an error vector $\vec{e}$ with small coefficients from a Centered Binomial Distribution (CBD).&lt;/li>
&lt;li>Calculate $\vec{t} = A\vec{s} + \vec{e}$. The public key is $(A, \vec{t})$, and the secret key is $\vec{s}$. (In reality, $A$ is published as a seed value to save bandwidth).&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Encryption&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>Encode the 32-byte message to be shared (shared key material) $m$ into a polynomial.&lt;/li>
&lt;li>Generate a new random vector $\vec{r}$ and small errors $\vec{e_1}, e_2$.&lt;/li>
&lt;li>$\vec{u} = A^T\vec{r} + \vec{e_1}$&lt;/li>
&lt;li>$v = \vec{t}^T\vec{r} + e_2 + \lfloor q/2 \rceil \cdot m$&lt;/li>
&lt;li>The ciphertext is $(\vec{u}, v)$.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Decryption&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>The receiver calculates $v - \vec{s}^T\vec{u}$.&lt;/li>
&lt;li>Expanding this formula mathematically yields the following:
$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>Substituting $\vec{t} = A\vec{s} + \vec{e}$ here cancels out the main term $\vec{s}^TA^T\vec{r}$.&lt;/li>
&lt;li>What remains is $\lfloor q/2 \rceil \cdot m + (\vec{e}^T\vec{r} + e_2 - \vec{s}^T\vec{e_1})$.&lt;/li>
&lt;li>Since the terms in parentheses are &amp;ldquo;products and sums of small errors,&amp;rdquo; they remain sufficiently small values (noise) as a whole. Therefore, by making a threshold judgment on whether each coefficient is close to $0$ or close to $q/2$, the bits (0 or 1) of the original message $m$ can be completely restored without error.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>Kyber&amp;rsquo;s greatest strengths are its overwhelming &lt;strong>processing speed&lt;/strong> and &lt;strong>moderate key size&lt;/strong>. For Kyber768, the public key size is 1,184 bytes and the ciphertext size is 1,088 bytes. While larger compared to RSA-3072 (key size around 384 bytes), it can fit within the MTU (Maximum Transmission Unit) of modern internet communications without packet fragmentation, having almost no adverse effect on network latency.&lt;/p>
&lt;hr>
&lt;h2 id="6-crystals-dilithium-ml-dsa-general-purpose-lattice-based-digital-signature">6. CRYSTALS-Dilithium (ML-DSA): General-Purpose Lattice-Based Digital Signature
&lt;/h2>&lt;p>In the standardization of digital signatures, algorithms with different design philosophies within the same lattice cryptography approach competed against each stands. Among them, &lt;strong>CRYSTALS-Dilithium&lt;/strong> was selected as &lt;strong>FIPS 204 (ML-DSA)&lt;/strong> for general-purpose digital signatures.&lt;/p>
&lt;h3 id="61-the-fiat-shamir-with-aborts-paradigm">6.1. The Fiat-Shamir with Aborts Paradigm
&lt;/h3>&lt;p>Like Kyber, Dilithium is a digital signature scheme based on the Module-LWE (and Module-SIS problem). The design base uses an extremely important paradigm called &amp;ldquo;&lt;strong>Fiat-Shamir with Aborts&lt;/strong>&amp;rdquo;.&lt;/p>
&lt;p>The Fiat-Shamir transform itself is a standard method for converting an interactive zero-knowledge proof protocol into a non-interactive digital signature. The prover (signer) generates a commitment $y$, calculates $w = Ay$, passes it through a hash function to obtain a random challenge $c$, and calculates the response $z = y + cs$.&lt;/p>
&lt;p>However, simply applying this to lattice cryptography caused a fatal problem (side-channel-like mathematical leakage) where the distribution of the response $z$ was distorted depending on the value of the secret key $s$, gradually leaking information about the secret key $s$ to an attacker observing many signatures.&lt;/p>
&lt;p>The Dilithium design team (Lyubashevsky et al.) introduced a method called &amp;ldquo;&lt;strong>Rejection Sampling&lt;/strong>&amp;rdquo;, where if the coefficients of the calculated signature $z$ do not fall within a pre-set safe threshold, the entire signature process is aborted and recalculated from the beginning using a new random number $y$.&lt;/p>
&lt;p>As a result, the finally output signature $z$ has a completely uniform distribution independent of the secret key, succeeding in completely preventing mathematical information leakage.&lt;/p>
&lt;h3 id="62-dilithiums-advantages-and-ease-of-implementation">6.2. Dilithium&amp;rsquo;s Advantages and Ease of Implementation
&lt;/h3>&lt;p>A major design advantage of Dilithium is that it &lt;strong>does not use&lt;/strong> complex &amp;ldquo;sampling from a Gaussian distribution&amp;rdquo; or &amp;ldquo;floating-point arithmetic&amp;rdquo; at all in the signature generation process. Because it can be implemented using only sampling from a uniform distribution, simple integer modulo arithmetic, NTT, and a hash function (SHAKE), it is easy to implement securely and in constant-time in a wide range of environments, from embedded microcontrollers to cloud servers. This gives it robust resistance against physical side-channel attacks such as timing attacks.&lt;/p>
&lt;hr>
&lt;h2 id="7-falcon-fn-dsa-ultimately-compact-lattice-signature">7. FALCON (FN-DSA): Ultimately Compact Lattice Signature
&lt;/h2>&lt;p>NIST selected &lt;strong>FALCON (Fast-Fourier Lattice-based Compact Signatures over NTRU)&lt;/strong>, another lattice-based signature with different characteristics from Dilithium, as a standardization candidate (currently drafting as FN-DSA).&lt;/p>
&lt;h3 id="71-ntru-lattices-and-gaussian-sampling">7.1. NTRU Lattices and Gaussian Sampling
&lt;/h3>&lt;p>FALCON&amp;rsquo;s greatest feature is that it uses not the LWE problem but the historical &lt;strong>NTRU (N-th degree Truncated polynomial Ring Units) lattices&lt;/strong> that have existed since 1996. Furthermore, it adopts the &amp;ldquo;&lt;strong>Hash-and-Sign&lt;/strong>&amp;rdquo; paradigm based on the GPV (Gentry-Peikert-Vaikuntanathan) framework.&lt;/p>
&lt;p>In Hash-and-Sign, the hash value of a message is set as a target point in space, and finding the point on the lattice closest to that point (an approximate solution to the closest vector problem) serves as the signature. To do this, it is necessary to sample points according to a discrete Gaussian distribution using a &amp;ldquo;high-quality short basis&amp;rdquo; as the secret key.&lt;/p>
&lt;p>FALCON dramatically accelerated this heavy computation using a method called &amp;ldquo;&lt;strong>Fast Fourier Orthogonalization (FFO)&lt;/strong>&amp;rdquo;.&lt;/p>
&lt;h3 id="72-pros-and-cons-of-falcon">7.2. Pros and Cons of FALCON
&lt;/h3>&lt;p>The overwhelming advantage of FALCON is that its &lt;strong>signature size and public key size are extremely small (compact)&lt;/strong>. While the signature size of Dilithium3 is about 3,309 bytes, the signature size of FALCON-512 is only about 666 bytes. The public key is also very small at 897 bytes, making it a lifesaver in environments with extremely limited communication bandwidth, IoT devices, or specific network protocols.&lt;/p>
&lt;p>However, there is a significant drawback. Because discrete Gaussian sampling, which involves complex &lt;strong>floating-point arithmetic (64-bit IEEE 754)&lt;/strong>, is essential during signature generation, constant-time implementation to prevent timing leakage is extremely difficult, and the code becomes huge. For this reason, FALCON is positioned as a powerful specialized algorithm for specific uses, in contrast to the general-purpose Dilithium.&lt;/p>
&lt;div class="mermaid">graph LR
A["Requirements for Digital Signatures"] --> B{"What is the top priority constraint?"}
B -->|"Simplicity of implementation, versatility, ease of constant-time implementation"| C["Dilithium (ML-DSA)"]
B -->|"Minimization of communication bandwidth, compactness of data size"| D["FALCON (FN-DSA)"]
C --> E["General-purpose TLS certificates, digital signatures for software"]
D --> F["Protocols with strict packet size limits, special environments"]&lt;/div>
&lt;hr>
&lt;h2 id="8-sphincs-slh-dsa-hash-based-signature-boasting-the-strongest-security">8. SPHINCS+ (SLH-DSA): Hash-Based Signature Boasting the Strongest Security
&lt;/h2>&lt;p>To prepare for the worst-case scenario (a rare event) where the security of lattice cryptography is broken by a brilliant mathematician&amp;rsquo;s breakthrough in the future, NIST formulated &lt;strong>FIPS 205 (SLH-DSA)&lt;/strong>, namely &lt;strong>SPHINCS+&lt;/strong>, as a standard with a completely different approach from lattice cryptography.&lt;/p>
&lt;p>SPHINCS+ is classified as a &lt;strong>hash-based signature&lt;/strong>. The basis of its security relies solely on &amp;ldquo;the cryptographic hash functions used (such as SHA-2 and SHAKE256) having collision resistance and one-wayness.&amp;rdquo; Because it does not depend on mathematical problems with specific algebraic structures like LWE or integer factorization, it boasts extremely robust security (the most conservative security) where even if any powerful quantum algorithm appears in the future, one can simply counter it by increasing the output length of the hash function.&lt;/p>
&lt;h3 id="81-stateless-architecture-with-wots-and-fors">8.1. Stateless Architecture with WOTS+ and FORS
&lt;/h3>&lt;p>The history of hash-based signatures is old, dating back to Lamport signatures and Winternitz One-Time Signatures (WOTS) in the 1970s. These were disposable keys that could &amp;ldquo;securely sign only once.&amp;rdquo; To make them usable multiple times, algorithms like XMSS (eXtended Merkle Signature Scheme) and LMS were developed, combining a Merkle Tree to manage countless one-time keys with a single root hash.&lt;/p>
&lt;p>However, XMSS and LMS had a fatal flaw of being &amp;ldquo;&lt;strong>stateful&lt;/strong>&amp;rdquo;. It was necessary to strictly record the index state of &amp;ldquo;which one-time key was used&amp;rdquo; in non-volatile memory every time a signature was made, and if the state rolled back due to something like restoring a virtual machine snapshot and the same one-time key was used twice, the secret key would leak immediately, and the system would collapse.&lt;/p>
&lt;p>SPHINCS+ is a &amp;ldquo;&lt;strong>stateless&lt;/strong>&amp;rdquo; hash-based signature that solves this state management hassle.
Its core technology is the following combination:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>WOTS+ (Winternitz One-Time Signature Plus)&lt;/strong>: A basic one-time signature.&lt;/li>
&lt;li>&lt;strong>FORS (Forest of Random Subsets)&lt;/strong>: A Few-Time Signature technology. It remains secure even if the same key is reused a few times.&lt;/li>
&lt;li>&lt;strong>Hyper-Tree&lt;/strong>: A massive structure of multi-layered Merkle Trees.&lt;/li>
&lt;/ol>
&lt;p>When signing with SPHINCS+, instead of managing state, it uses a pseudorandom number to randomly select one of a vast number of FORS keys at the bottom of the Hyper-Tree to sign. Because the number of leaves in the tree is astronomically large, the probability of accidentally picking the same key twice (collision) is negligibly small, resulting in a stateless realization.&lt;/p>
&lt;p>The sole and greatest weakness of SPHINCS+ is that its &lt;strong>signature size is extremely large&lt;/strong>. Depending on the parameters, the signature size can reach 17 to 49 kilobytes, and the signature generation speed is also overwhelmingly slower than lattice cryptography. Therefore, rather than for daily web browsing, it is intended for uses where signatures are not made frequently and long-term absolute security is strongly required, such as software update signatures and root Certificate Authority (CA) certificates.&lt;/p>
&lt;hr>
&lt;h2 id="9-code-based-cryptography-the-good-old-giant-classic-mceliece">9. Code-Based Cryptography: The Good Old Giant, Classic McEliece
&lt;/h2>&lt;p>In the NIST standardization process, an important approach still being evaluated as a final candidate for Round 4 is &lt;strong>Classic McEliece&lt;/strong> of &lt;strong>code-based cryptography&lt;/strong>.&lt;/p>
&lt;p>Proposed by Robert McEliece in 1978, this algorithm is one of the oldest in the history of public-key cryptography, alongside RSA. It utilizes algebraic geometry codes called &amp;ldquo;Goppa codes,&amp;rdquo; where a message is intentionally encrypted with an error (noise vector) added, and only the person holding the parity check matrix of the Goppa code as a secret key can remove the error using powerful error-correcting capabilities to decrypt the original message. This is based on the &amp;ldquo;&lt;strong>Syndrome Decoding Problem&lt;/strong>&amp;rdquo;.&lt;/p>
$$ \vec{c} = \vec{m} G + \vec{e} $$
&lt;p>
(where $G$ is the scrambled generator matrix which is the public key, and $\vec{e}$ is the error vector of weight $t$)&lt;/p>
&lt;p>The amazing thing about Classic McEliece is its overwhelming track record: &lt;strong>despite more than 40 years passing since its proposal and being exposed to intense cryptanalysis research by cryptographers worldwide, no fundamental vulnerability has ever been discovered&lt;/strong>. It possesses the most &amp;ldquo;time-proven robust security&amp;rdquo; among PQC.&lt;/p>
&lt;p>Furthermore, it has the advantage of a very small ciphertext size (only about 100 to 200 bytes). However, it has a fatal flaw in that &lt;strong>the public key size is in the megabyte (MB) range&lt;/strong>. Even at the lowest security level (AES-128 equivalent), the public key is about 250KB, and it exceeds 1MB at higher levels.&lt;/p>
&lt;p>For this reason, it cannot be applied at all to uses where the public key is transmitted over a network during every communication, such as in TLS handshakes. However, in special use cases where public keys can be pre-deployed in systems, such as sharing pre-shared keys for VPNs, hardcoding public keys in firmware, or satellite communications, it continues to be considered a highly promising option due to its robust security.&lt;/p>
&lt;hr>
&lt;h2 id="10-performance-comparison-and-trade-offs-of-each-pqc-algorithm">10. Performance Comparison and Trade-offs of Each PQC Algorithm
&lt;/h2>&lt;p>The performance characteristics of the major algorithms explained so far at typical security levels (equivalent to NIST Level 2-3, AES-128-192 levels) are summarized in the table below.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Algorithm (Standard Name)&lt;/th>
&lt;th style="text-align:left">Category&lt;/th>
&lt;th style="text-align:left">Mathematical Basis&lt;/th>
&lt;th style="text-align:left">Public Key Size&lt;/th>
&lt;th style="text-align:left">Secret Key Size&lt;/th>
&lt;th style="text-align:left">Ciphertext/Signature Size&lt;/th>
&lt;th style="text-align:left">Processing Speed Trend&lt;/th>
&lt;th style="text-align:left">Main Features and Uses&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">Very fast&lt;/td>
&lt;td style="text-align:left">Best balance of key size and speed. General-purpose KEM standard such as TLS 1.3.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Dilithium3&lt;/strong>&lt;br>(ML-DSA)&lt;/td>
&lt;td style="text-align:left">Signature&lt;/td>
&lt;td style="text-align:left">Module-LWE&lt;/td>
&lt;td style="text-align:left">1,952 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">Fast for both generation and verification&lt;/td>
&lt;td style="text-align:left">Simple implementation. General-purpose digital signature standard.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>FALCON-512&lt;/strong>&lt;br>(FN-DSA)&lt;/td>
&lt;td style="text-align:left">Signature&lt;/td>
&lt;td style="text-align:left">NTRU Lattice&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">Signature generation is slower, verification is ultra-fast&lt;/td>
&lt;td style="text-align:left">Minimal signature size. However, requires floating-point operations. For embedded/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">Signature&lt;/td>
&lt;td style="text-align:left">Hash Function&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">Approx. 17,000 Bytes&lt;/td>
&lt;td style="text-align:left">Generation is very slow&lt;/td>
&lt;td style="text-align:left">Mathematical failure risk is almost zero. High security uses like root certificates.&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>Approx. 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">Encapsulation is fast&lt;/td>
&lt;td style="text-align:left">40 years of security track record. Giant public key. For hardcodable environments.&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="understanding-the-trade-offs">Understanding the Trade-offs
&lt;/h3>&lt;p>In the world of PQC, there is no single magical algorithm that has &amp;ldquo;small size, fast speed, and perfect mathematical guarantees.&amp;rdquo;&lt;/p>
&lt;ul>
&lt;li>&lt;strong>The Internet Standard (Kyber / Dilithium)&lt;/strong>: The best balance of performance, making it the most suitable for a drop-in replacement of current RSA/ECC.&lt;/li>
&lt;li>&lt;strong>Ultimate Conservatism (SPHINCS+)&lt;/strong>: Chosen when one wants absolute insurance against future mathematical breakthroughs, even at the expense of data size or processing speed.&lt;/li>
&lt;li>&lt;strong>For Special Environments (FALCON / Classic McEliece)&lt;/strong>: Specialized weapons chosen according to environmental constraints, such as when communication bandwidth is extremely narrow or when pre-distribution is possible.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="11-challenges-toward-practical-application-and-the-practical-solution-of-hybrid-cryptography">11. Challenges Toward Practical Application and the Practical Solution of &amp;ldquo;Hybrid Cryptography&amp;rdquo;
&lt;/h2>&lt;p>With the completion of standardization by NIST and the official issuance of FIPS standards, the PQC migration of IT infrastructure worldwide has begun in earnest. Google&amp;rsquo;s Chrome browser, Apple&amp;rsquo;s iMessage (PQ3 protocol), and network providers like Cloudflare have already implemented PQC support in their protocols and started actual operations.&lt;/p>
&lt;p>However, completely switching to new cryptographic algorithms all at once comes with a very high risk. If a brilliant mathematician were to discover a fatal attack method (a mathematical flaw solvable even by classical computers) against lattice cryptography like Kyber a few years from now, entire systems relying on it would instantly become completely defenseless.&lt;/p>
&lt;p>A practical and recommended approach to mitigate this uncertainty risk is &amp;ldquo;&lt;strong>Hybrid Cryptography&lt;/strong>&amp;rdquo;.&lt;/p>
&lt;p>In hybrid cryptography, key exchange is performed using both a classical cryptographic algorithm with a long track record (e.g., Elliptic Curve Cryptography like X25519) and a new PQC algorithm (e.g., Kyber768) simultaneously. Shared key components are generated individually with each algorithm, and finally, a secure Key Derivation Function (KDF) is used to mix the two components to generate the final master secret.&lt;/p>
&lt;div class="mermaid">graph TD
A["Client"] -->|1. Send X25519 Public Key + Kyber Public Key| B["Server"]
B -->|2. Return X25519 Shared Key + Kyber Encapsulated Ciphertext| A
A --> C{"Derive Master Secret (KDF)"}
B --> C
C -->|Input: (X25519 Shared Key) || (Kyber Shared Key)| D["Secure Communication Key (AES-256 / ChaCha20)"]
D -->|"Resistant to both quantum threats &amp; classical vulnerabilities"| E["Secure Hybrid Encrypted Communication (TLS 1.3)"]&lt;/div>
&lt;p>This achieves a robust two-tiered security: &amp;ldquo;even if a quantum computer becomes a reality and ECC is broken, Kyber protects the communication,&amp;rdquo; and conversely, &amp;ldquo;even if an unknown mathematical flaw is found in Kyber, ECC protects the communication.&amp;rdquo; A representative example is the &lt;strong>X25519MLKEM768 (formerly X25519Kyber768)&lt;/strong> draft being standardized by the IETF, and communications between current web browsers and cutting-edge servers are already being carried out precisely using this hybrid method.&lt;/p>
&lt;p>Furthermore, the concept of &lt;strong>Crypto Agility&lt;/strong>, building a system architecture that &amp;ldquo;does not overly rely on a specific cryptographic algorithm and can quickly switch to another algorithm (e.g., from Kyber to McEliece, or Dilithium to SPHINCS+) in the event an algorithm fails,&amp;rdquo; will be an essential requirement in future system development.&lt;/p>
&lt;hr>
&lt;h2 id="12-conclusion-a-new-horizon-for-cryptographic-technology">12. Conclusion: A New Horizon for Cryptographic Technology
&lt;/h2>&lt;p>Ironically, quantum computers, the dream technology of humanity, have become the greatest threat to breaking the mathematical defenses of &amp;ldquo;integer factorization&amp;rdquo; and &amp;ldquo;discrete logarithm problems&amp;rdquo; that we have trusted for many years. However, cryptographers around the world did not succumb to this; they pioneered more complex and profound multi-dimensional mathematical fields such as lattice theory, hash function trees, and error-correcting codes, and built a new defense called Post-Quantum Cryptography (PQC).&lt;/p>
&lt;p>The completion of standardizations by NIST for FIPS 203 (ML-KEM), FIPS 204 (ML-DSA), and FIPS 205 (SLH-DSA) is not the goal. It is just the first step in the grand journey of PQC migration that will continue for decades to come. For software engineers and system architects, how to optimally adapt the &amp;ldquo;increased key sizes&amp;rdquo; and &amp;ldquo;changed computational costs&amp;rdquo; brought by these new algorithms into network protocols and systems will be a major technical challenge moving forward.&lt;/p>
&lt;p>The battle between quantum computers and cryptography is an exciting area where humanity&amp;rsquo;s mathematical exploration and the evolution of technology intersect most fiercely. Through this article, we hope you have deeply understood the beautiful mathematical theories behind PQC and the amazing mechanisms of each algorithm that will shape the future of cybersecurity.&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>The Day Quantum Computers Become Practical: The Current State in 2026</title><link>http://kenji.blog/en/p/quantum-computing-2026-current-status/</link><pubDate>Fri, 11 Sep 2026 06:00:00 +0900</pubDate><guid>http://kenji.blog/en/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 The Day Quantum Computers Become Practical: The Current State in 2026" />&lt;h2 id="1-introduction-where-quantum-computing-stands-in-2026">1. Introduction: Where Quantum Computing Stands in 2026
&lt;/h2>&lt;p>As of 2026, quantum computing has made a decisive shift from a &amp;ldquo;theoretical dream&amp;rdquo; to an &amp;ldquo;engineering reality.&amp;rdquo; As the limitations of &lt;strong>NISQ (Noisy Intermediate-Scale Quantum)&lt;/strong> devices—which were mainstream until a few years ago—became clear, research institutions and tech giants around the world shifted their focus toward realizing &amp;ldquo;FTQC (Fault-Tolerant Quantum Computing).&amp;rdquo;&lt;/p>
&lt;p>In this article, we will delve deep into the current state of quantum computers, incorporating the latest breakthroughs of 2026. In particular, we will detail quantum error correction (surface codes), the difference between physical and logical qubits, advancements in topological quantum computing, and the frontlines of superconducting and ion-trap architectures.&lt;/p>
&lt;hr>
&lt;h2 id="2-fundamentals-of-quantum-states-and-fidelity">2. Fundamentals of Quantum States and Fidelity
&lt;/h2>&lt;p>The qubit, the fundamental unit of a quantum computer, differs from a classical bit (0 or 1) in that it can exist in a superposition of 0 and 1. The state of a single qubit is represented as a vector on a Hilbert space as follows:&lt;/p>
$$
|\psi\rangle = \alpha|0\rangle + \beta|1\rangle
$$
&lt;p>Here, $\alpha$ and $\beta$ are complex probability amplitudes that satisfy the following normalization condition:&lt;/p>
$$
|\alpha|^2 + |\beta|^2 = 1
$$
&lt;p>An extremely important metric for measuring the performance of quantum computation is &lt;strong>Fidelity&lt;/strong>. The fidelity $F$ between an ideal quantum state $|\psi\rangle$ and an actual density matrix $\rho$ that has degraded into a mixed state due to noise is defined as follows:&lt;/p>
$$
F(\rho, |\psi\rangle) = \langle \psi | \rho | \psi \rangle
$$
&lt;p>As of 2026, the fidelity of 2-qubit gates (e.g., CNOT and CZ gates) has stably surpassed the &lt;strong>99.99%&lt;/strong> barrier (the so-called &amp;ldquo;four nines&amp;rdquo;) in superconducting architectures. This significantly exceeds the threshold for error correction using surface codes (about 99%), making it one of the biggest breakthroughs toward practical application.&lt;/p>
&lt;hr>
&lt;h2 id="3-the-limits-of-the-nisq-era-and-the-paradigm-shift-to-ftqc">3. The Limits of the NISQ Era and the Paradigm Shift to FTQC
&lt;/h2>&lt;p>The late 2010s to the early 2020s was the era of NISQ (Noisy Intermediate-Scale Quantum)—devices with tens to hundreds of qubits without error correction. However, NISQ had clear limitations.&lt;/p>
&lt;p>As the circuit depth increases, errors accumulate exponentially, making it impossible to obtain meaningful computation results. The overall success probability $P_{success}$ at a circuit depth $D$ decays with respect to the single-gate fidelity $f$ and the number of gates $N$ as follows:&lt;/p>
$$
P_{success} \approx f^N
$$
&lt;p>If $f = 0.99$ and 1000 gates are applied, $0.99^{1000} \approx 4.3 \times 10^{-5}$, and the result is almost entirely buried in random noise. For this reason, in 2026, resources are heavily concentrated on generating &lt;strong>Logical Qubits&lt;/strong> rather than directly scaling up NISQ algorithms (like VQE and QAOA).&lt;/p>
&lt;hr>
&lt;h2 id="4-quantum-error-correction-and-logical-qubits-the-forefront-of-surface-codes">4. Quantum Error Correction and Logical Qubits: The Forefront of Surface Codes
&lt;/h2>&lt;p>Quantum Error Correction (QEC) is a technology that encodes multiple &amp;ldquo;physical qubits&amp;rdquo; to create a single &amp;ldquo;logical qubit,&amp;rdquo; detecting and correcting errors. The most promising approach currently is the &lt;strong>Surface Code&lt;/strong>.&lt;/p>
&lt;h3 id="41-structure-of-the-surface-code">4.1 Structure of the Surface Code
&lt;/h3>&lt;p>In a surface code, qubits are arranged in a 2-dimensional grid. Data qubits (which hold the actual information) and measurement qubits (for syndrome measurement) are arranged in a checkerboard pattern.&lt;/p>
&lt;div class="mermaid">graph TD
A["Data Qubit (D1)"] --- B["Measure Qubit (M1)"]
B --- C["Data Qubit (D2)"]
C --- D["Measure Qubit (M2)"]
D --- E["Data Qubit (D3)"]
B --- F["Data Qubit (D4)"]
D --- G["Data 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>Bit-flip (X errors) and phase-flip (Z errors) are constantly monitored using the stabilizer operators $S_x$ and $S_z$.&lt;/p>
$$
S_x = \prod_{i \in \text{star}} X_i, \quad S_z = \prod_{j \in \text{plaquette}} Z_j
$$
&lt;p>A significant advancement in 2026 is that the &amp;ldquo;Break-even point&amp;rdquo; has been completely surpassed. In other words, the noise removed by error correction has become greater than the noise introduced by the extra circuitry required for it, allowing the lifespan of a logical qubit to exceed that of a physical qubit by orders of magnitude.&lt;/p>
&lt;h3 id="42-the-quantum-error-correction-cycle">4.2 The Quantum Error Correction Cycle
&lt;/h3>&lt;p>Error correction functions as a continuous feedback loop.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant D as "Data Qubits"
participant M as "Ancilla/Measure Qubits"
participant C as "Classical Controller"
loop "Syndrome Extraction Cycle (approx 1 microsec)"
D->>M: "Entangle (CNOT/CZ)"
M->>C: "Measure State (Syndrome)"
C->>C: "Decode Syndrome (e.g. Minimum Weight Perfect Matching)"
C-->>D: "Apply Pauli Correction (if necessary)"
end&lt;/div>
&lt;p>Currently, the technology to execute this classical decoding process (syndrome analysis) in nanoseconds using FPGAs or dedicated ASICs has been established, and real-time error correction has entered the practical stage.&lt;/p>
&lt;hr>
&lt;h2 id="5-evolution-of-hardware-architectures-2026-edition">5. Evolution of Hardware Architectures (2026 Edition)
&lt;/h2>&lt;p>Quantum hardware in 2026 is evolving primarily along three axes: &amp;ldquo;Superconducting,&amp;rdquo; &amp;ldquo;Ion-Trap,&amp;rdquo; and &amp;ldquo;Topological.&amp;rdquo;&lt;/p>
&lt;h3 id="51-integration-of-superconducting-qubits">5.1 Integration of Superconducting Qubits
&lt;/h3>&lt;p>The superconducting approach is a field led by companies like IBM and Google, with Transmon qubits using Josephson junctions being the mainstream. In 2026, megachips integrating thousands to ten thousand physical qubits on a single chip became a reality.&lt;/p>
&lt;p>Notably, &lt;strong>Quantum Interconnects (module-to-module quantum communication)&lt;/strong> have been established. Quantum teleportation between chips using microwave photons has been implemented at a commercial level, making it possible to bypass the size limitations of a single dilution refrigerator.&lt;/p>
&lt;h3 id="52-2d-scaling-and-optical-interconnects-for-ion-traps">5.2 2D Scaling and Optical Interconnects for Ion Traps
&lt;/h3>&lt;p>The ion-trap architecture (led by Quantinuum, IonQ, etc.) uses the internal energy states of ions suspended in a vacuum as qubits. Compared to superconducting methods, they boast extremely long T1/T2 coherence times and have the advantage of all-to-all connectivity.&lt;/p>
&lt;p>The 2026 breakthrough involved expanding the QCCD (Quantum Charge Coupled Device) architecture into two dimensions and generating high-speed entanglement between multiple traps using photonic interconnects. This drastically improved the slow gate speeds and scalability issues that were weaknesses of the ion-trap method.&lt;/p>
&lt;h3 id="53-topological-quantum-computing-controlling-anyons">5.3 Topological Quantum Computing: Controlling Anyons
&lt;/h3>&lt;p>&lt;strong>Topological quantum computing&lt;/strong>, long considered theoretical, has finally entered the phase of experimental demonstration in 2026. This approach, promoted by Microsoft and others, uses non-Abelian anyons called &amp;ldquo;Majorana Zero Modes.&amp;rdquo;&lt;/p>
&lt;p>Quantum gates are executed through an operation called &amp;ldquo;Braiding,&amp;rdquo; which involves swapping the positions of anyon particles.&lt;/p>
$$
|\psi_{final}\rangle = B_{ij} |\psi_{initial}\rangle
$$
&lt;p>Here, $B_{ij}$ is the braiding operator. Because the topological approach relies on the global topology of the &amp;ldquo;knots&amp;rdquo; rather than the local state of particles to store information, it is inherently robust against environmental noise (hardware-level fault tolerance). In 2026, the world&amp;rsquo;s first generation of high-fidelity topological logical qubits was confirmed, drawing attention as a powerful shortcut to FTQC.&lt;/p>
&lt;hr>
&lt;h2 id="6-roadmap-to-practical-application-and-future-outlook">6. Roadmap to Practical Application and Future Outlook
&lt;/h2>&lt;p>To truly demonstrate &lt;strong>Quantum Advantage&lt;/strong>, where quantum computers overwhelm classical computers (supercomputers) in fields like &amp;ldquo;chemical computation,&amp;rdquo; &amp;ldquo;materials science,&amp;rdquo; and &amp;ldquo;financial modeling,&amp;rdquo; thousands of logical qubits are required.&lt;/p>
&lt;div class="mermaid">gantt
title "Quantum Computing Roadmap (Revised 2026)"
dateFormat YYYY
axisFormat %Y
section "NISQ Era"
"Noisy Qubits (&lt;1000)" :done, 2018, 2024
section "Early FTQC"
"Break-even Point Demonstration" :done, 2024, 2026
"Hundreds of Logical Qubits" :active, 2026, 2028
section "Full-Scale FTQC"
"1000+ Logical Qubits (Commercial App)" : 2028, 2030
"Universal Fault-Tolerant Quantum Computer" : 2030, 2035&lt;/div>
&lt;h3 id="61-current-challenges-and-the-future">6.1 Current Challenges and the Future
&lt;/h3>&lt;p>The biggest challenges as of 2026 are the cooling capacity of the massive cryostats (dilution refrigerators) needed to maintain ultra-low temperatures, and the wiring (I/O bottleneck) connecting room-temperature control equipment to the cryogenic quantum chips. In response, the development of Cryo-CMOS controller chips that operate in cryogenic environments is advancing rapidly.&lt;/p>
&lt;h3 id="conclusion">Conclusion
&lt;/h3>&lt;p>2026 will likely be recorded in the history of quantum computing as &amp;ldquo;the first year of logical qubit scaling.&amp;rdquo; With the demonstration of error correction algorithms, the modularization of hardware, and rapid progress in the topological approach, &amp;ldquo;the day they become practical&amp;rdquo; is no longer a tale of the distant future but a concrete milestone to look forward to within the next few years. For developers and companies in the quantum algorithm space, now is the time to seriously invest in quantum-native problem solving.&lt;/p>
&lt;hr>
&lt;p>&lt;em>This article was written based on the latest quantum computing research papers and industry trends as of 2026.&lt;/em>&lt;/p></description></item><item><title>How to Solve the Traveling Salesperson Problem (TSP) in Mathematica</title><link>http://kenji.blog/en/p/mathematica%E3%81%A7%E5%B7%A1%E5%9B%9E%E3%82%BB%E3%83%BC%E3%83%AB%E3%82%B9%E3%83%9E%E3%83%B3%E5%95%8F%E9%A1%8C%E3%82%92%E8%A7%A3%E3%81%8F/</link><pubDate>Wed, 12 Oct 2022 19:05:58 +0900</pubDate><guid>http://kenji.blog/en/p/mathematica%E3%81%A7%E5%B7%A1%E5%9B%9E%E3%82%BB%E3%83%BC%E3%83%AB%E3%82%B9%E3%83%9E%E3%83%B3%E5%95%8F%E9%A1%8C%E3%82%92%E8%A7%A3%E3%81%8F/</guid><description>&lt;img src="http://kenji.blog/p/mathematica%E3%81%A7%E5%B7%A1%E5%9B%9E%E3%82%BB%E3%83%BC%E3%83%AB%E3%82%B9%E3%83%9E%E3%83%B3%E5%95%8F%E9%A1%8C%E3%82%92%E8%A7%A3%E3%81%8F/img.webp" alt="Featured image of post How to Solve the Traveling Salesperson Problem (TSP) in Mathematica" />&lt;h1 id="solving-the-traveling-salesperson-problem-with-mathematica">Solving the Traveling Salesperson Problem with Mathematica
&lt;/h1>&lt;h2 id="problem">Problem
&lt;/h2>&lt;blockquote class="twitter-tweet">&lt;p lang="ja" dir="ltr">電車でこんな広告を見かけました😁📸 &lt;a href="https://t.co/iXEgvtXrpL">pic.twitter.com/iXEgvtXrpL&lt;/a>&lt;/p>&amp;mdash; 早稲田大学 早水桃子研究室 (@hayamizu_lab) &lt;a href="https://x.com/hayamizu_lab/status/1579806418982825984?ref_src=twsrc%5Etfw">October 11, 2022&lt;/a>&lt;/blockquote>
&lt;script async src="https://platform.x.com/widgets.js" charset="utf-8">&lt;/script>
&lt;h2 id="solution">Solution
&lt;/h2>&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-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">d=SparseArray[{{1,2}-&amp;gt;10,{2,1}-&amp;gt;10,{1,5}-&amp;gt;15,{5,1}-&amp;gt;15,{1,4}-&amp;gt;12,{4,1}-&amp;gt;12,{1,3}-&amp;gt;20,{3,1}-&amp;gt;20,{2,5}-&amp;gt;10,{5,2}-&amp;gt;10,{3,4}-&amp;gt;10,{4,3}-&amp;gt;10,{3,8}-&amp;gt;30,{8,3}-&amp;gt;30,{3,7}-&amp;gt;20,{7,3}-&amp;gt;20,{3,6}-&amp;gt;25,{6,3}-&amp;gt;25,{4,5}-&amp;gt;15,{5,4}-&amp;gt;15,{4,8}-&amp;gt;20,{8,4}-&amp;gt;20,{5,9}-&amp;gt;18,{9,5}-&amp;gt;18,{5,8}-&amp;gt;15,{8,5}-&amp;gt;15,{6,7}-&amp;gt;5,{7,6}-&amp;gt;5,{7,8}-&amp;gt;35,{8,7}-&amp;gt;35,{8,9}-&amp;gt;12,{9,8}-&amp;gt;12},{9,9},Infinity];
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>We create a matrix using the SparseArray function. Each element represents the distance between cities at the row and column of that element. For example, the first element &lt;code>{1,2}-&amp;gt;10&lt;/code> means the distance between 1 and 2 is 10. The second to last element &lt;code>{9,9}&lt;/code> indicates the size of the matrix, and the final element &lt;code>Infinity&lt;/code> means the length of paths between unspecified cities is infinite, meaning there is no path.&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-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">{len,tour}=FindShortestTour[{1,2,3,4,5,6,7,8,9},DistanceFunction-&amp;gt;(d[[#1,#2]]&amp;amp;)]
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>You can easily solve the traveling salesperson problem with the FindShortestTour function. &lt;code>{1,2,3,4,5,6,7,8,9}&lt;/code> represents the city numbers. &lt;code>DistanceFunction-&amp;gt;(d[[#1,#2]]&amp;amp;)&lt;/code> passes the matrix d which represents the distance between cities.&lt;/p>
&lt;h2 id="output">Output
&lt;/h2>&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-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">{137, {1, 2, 5, 9, 8, 7, 6, 3, 4}}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The output gives the shortest distance and the tour route for it. The shortest distance is &lt;code>137&lt;/code>, and the route is &lt;code>1→2→5→9→8→7→6→3→4→1&lt;/code>. Converting this to ABC order gives &lt;code>A, B, E, I, H, G, F, C, D&lt;/code>.&lt;/p></description></item></channel></rss>