<?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/zh-tw/categories/mathematics/</link><description>Recent content in Mathematics on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>zh-tw</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 22:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/zh-tw/categories/mathematics/index.xml" rel="self" type="application/rss+xml"/><item><title>利用費馬小定理的加密基礎與實作</title><link>http://kenji.blog/zh-tw/p/fermats-little-theorem-cryptography-implementation/</link><pubDate>Fri, 11 Sep 2026 22:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/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 利用費馬小定理的加密基礎與實作" />&lt;h2 id="1-簡介支撐現代密碼學的數學奧秘">1. 簡介：支撐現代密碼學的數學奧秘
&lt;/h2>&lt;p>在現代數位社會，特別是透過網際網路進行通訊時，「加密」已成為不可或缺的基礎技術。我們能透過網頁瀏覽器經由 HTTPS 安全地瀏覽網站、在網路銀行進行金融交易，以及在通訊應用程式中進行私密對話，全是因為有高度數學理論支持的加密協定在背後運作。其中扮演特別重要角色的就是「公開金鑰加密」，而其代表正是 &lt;strong>RSA 加密&lt;/strong>。&lt;/p>
&lt;p>包含 RSA 加密在內的許多加密演算法，其安全性與正確性在很大程度上依賴於 17 世紀法國數學家皮耶·德·費馬（Pierre de Fermat）所發現的一個非常優美且強大的定理。這就是&lt;strong>費馬小定理（Fermat&amp;rsquo;s Little Theorem）&lt;/strong>。此外，將其一般化的李昂哈德·歐拉（Leonhard Euler）定理，在密碼學理論中也發揮了決定性的作用。&lt;/p>
&lt;p>本篇文章將從基礎開始，徹底解說費馬小定理這個純數學的發現，是如何應用於現代實用的加密技術，特別是「質數判定」與「RSA 加密」。這是一份非常詳細的技術指南，內容涵蓋數學證明、加密與解密機制，以及使用 C++ 與 Python 進行具體演算法實作。&lt;/p>
&lt;hr>
&lt;h2 id="2-同餘與模算數基礎">2. 同餘與模算數基礎
&lt;/h2>&lt;p>為了理解費馬小定理，首先必須熟悉「模算數（同餘式）」這個數學概念。模算數是一種著眼於除以某個固定數字（稱為模數）後的「餘數」之計算系統。因為它像時鐘的表面（每 12 小時繞一圈）一樣運算，所以也被稱為「時鐘數學」。&lt;/p>
&lt;p>當整數 $a$ 和 $b$ 除以正整數 $n$ 的餘數相等時，數學上會以下列方式表示：&lt;/p>
$$
a \equiv b \pmod n
$$
&lt;p>這讀作「在模 $n$ 之下，$a$ 與 $b$ 同餘」。例如，17 除以 5 的餘數是 2，而 12 除以 5 的餘數也是 2。因此，可以寫成如下形式：&lt;/p>
$$
17 \equiv 12 \pmod 5 \equiv 2 \pmod 5
$$
&lt;p>在模算數中，一般的四則運算（加法、減法、乘法）可以直接成立：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>加法&lt;/strong>: 若 $a \equiv b \pmod n$ 且 $c \equiv d \pmod n$，則 $a + c \equiv b + d \pmod n$&lt;/li>
&lt;li>&lt;strong>減法&lt;/strong>: 若 $a \equiv b \pmod n$ 且 $c \equiv d \pmod n$，則 $a - c \equiv b - d \pmod n$&lt;/li>
&lt;li>&lt;strong>乘法&lt;/strong>: 若 $a \equiv b \pmod n$ 且 $c \equiv d \pmod n$，則 $a \times c \equiv b \times d \pmod n$&lt;/li>
&lt;li>&lt;strong>指數&lt;/strong>: 若 $a \equiv b \pmod n$，則對於任意自然數 $k$，$a^k \equiv b^k \pmod n$ 成立&lt;/li>
&lt;/ol>
&lt;p>不過，關於&lt;strong>除法&lt;/strong>必須特別注意。一般來說，即使 $a \times c \equiv b \times c \pmod n$，也不能直接將兩邊除以 $c$ 得出 $a \equiv b \pmod n$。這只有在 $c$ 和 $n$ 互質（最大公因數為 1）的情況下才成立。這個「模反元素（模逆元）」的概念，在後文將提到的 RSA 加密金鑰生成中非常重要。&lt;/p>
&lt;hr>
&lt;h2 id="3-費馬小定理的數學背景與證明">3. 費馬小定理的數學背景與證明
&lt;/h2>&lt;p>掌握了模算數的基礎後，讓我們來看看本篇的主題——費馬小定理。&lt;/p>
&lt;h3 id="31-定理的定義">3.1 定理的定義
&lt;/h3>&lt;p>費馬小定理可以表述如下：&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>費馬小定理 (Fermat&amp;rsquo;s Little Theorem)&lt;/strong>
設 $p$ 為質數，$a$ 為不是 $p$ 的倍數（即 $a$ 與 $p$ 互質）的任意整數。此時，以下同餘式成立：
&lt;/p>
$$ a^{p-1} \equiv 1 \pmod p $$
&lt;/blockquote>
&lt;p>此外，拿掉「$a$ 不是 $p$ 的倍數」的條件，將其表示為對所有整數 $a$ 都成立的形式也很常見。在這種情況下，兩邊同乘 $a$ 可得：&lt;/p>
$$
a^p \equiv a \pmod p
$$
&lt;h3 id="32-透過具體例子確認">3.2 透過具體例子確認
&lt;/h3>&lt;p>為了確認定理是否真的成立，我們用具體的數字來驗證看看。
設質數 $p = 5$。則 $p-1 = 4$。我們選擇不是 $p$ 的倍數的整數作為 $a$。&lt;/p>
&lt;ul>
&lt;li>當 $a = 2$ 時：$2^{5-1} = 2^4 = 16$。$16 \div 5 = 3$ 餘 $1$。因此 $16 \equiv 1 \pmod 5$。（成立）&lt;/li>
&lt;li>當 $a = 3$ 時：$3^{5-1} = 3^4 = 81$。$81 \div 5 = 16$ 餘 $1$。因此 $81 \equiv 1 \pmod 5$。（成立）&lt;/li>
&lt;li>當 $a = 4$ 時：$4^{5-1} = 4^4 = 256$。$256 \div 5 = 51$ 餘 $1$。因此 $256 \equiv 1 \pmod 5$。（成立）&lt;/li>
&lt;/ul>
&lt;p>就這樣，無論選擇什麼樣的 $a$（只要不是 5 的倍數），其 4 次方除以 5 的餘數必然為 1。看起來像魔法一樣，但這源自於質數所具備的優美性質。&lt;/p>
&lt;h3 id="33-定理的數學證明">3.3 定理的數學證明
&lt;/h3>&lt;p>為什麼會成立這樣的事實呢？這裡我們介紹一個使用剩餘系集合的優雅證明。&lt;/p>
&lt;p>考慮集合 $S = \{1, 2, 3, \dots, p-1\}$。這些是除以 $p$ 後餘數為 $1$ 到 $p-1$ 的整數代表元素。
現在，我們將各個元素乘上與 $p$ 互質的整數 $a$，得到一個新集合 $T$：
&lt;/p>
$$ T = \{1a, 2a, 3a, \dots, (p-1)a\} $$
&lt;p>我們考慮這個集合 $T$ 中的各個元素除以 $p$ 的餘數。令人驚訝的是，這些餘數雖然順序可能改變，但與原來集合 $S$ 的元素集合完全一致。
因為：&lt;/p>
&lt;ol>
&lt;li>$T$ 的元素不會是 $p$ 的倍數（因為 $a$ 和原本的元素都不是 $p$ 的倍數）。&lt;/li>
&lt;li>在 $T$ 之中，不存在兩個在模 $p$ 下同餘的不同元素。如果 $ia \equiv ja \pmod p$ （其中 $i \neq j$），因為 $a$ 和 $p$ 互質，我們可以除以 $a$，得到 $i \equiv j \pmod p$，這就產生了矛盾。&lt;/li>
&lt;/ol>
&lt;p>因此，將 $S$ 的所有元素相乘的結果，與將 $T$ 的所有元素相乘的結果，在模 $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>將左邊整理，因為有 $p-1$ 個 $a$，所以：&lt;/p>
$$
a^{p-1} \cdot (p-1)! \equiv (p-1)! \pmod p
$$
&lt;p>因為 $(p-1)!$ 與 $p$ 互質，所以兩邊可以除以 $(p-1)!$，最終導出以下定理：&lt;/p>
$$
a^{p-1} \equiv 1 \pmod p
$$
&lt;p>這就是費馬小定理的證明。&lt;/p>
&lt;hr>
&lt;h2 id="4-歐拉函數與歐拉定理">4. 歐拉函數與歐拉定理
&lt;/h2>&lt;p>費馬小定理是關於「質數 $p$」的定理，而將其推廣至「任意正整數 $n$」的人，就是李昂哈德·歐拉。為了理解 RSA 加密，這個推廣是不可或缺的。&lt;/p>
&lt;h3 id="41-歐拉函數-phin">4.1 歐拉函數 $\phi(n)$
&lt;/h3>&lt;p>歐拉函數（或稱歐拉 $\phi$ 函數） $\phi(n)$ 是一個表示「在 $1$ 到 $n$ 的整數中，與 $n$ 互質的數字個數」的函數。&lt;/p>
&lt;ul>
&lt;li>當為質數 $p$ 時，由於 $1$ 到 $p-1$ 的所有整數都與 $p$ 互質，因此 $\phi(p) = p - 1$。&lt;/li>
&lt;li>對於兩個相異質數 $p, q$，其乘積 $n = p \times q$ 的情況，$\phi(n)$ 可以用非常簡單的算式求出：
$$ \phi(p \times q) = \phi(p) \times \phi(q) = (p - 1)(q - 1) $$&lt;/li>
&lt;/ul>
&lt;p>這個性質，正是 RSA 加密金鑰生成的根本邏輯。&lt;/p>
&lt;h3 id="42-歐拉定理">4.2 歐拉定理
&lt;/h3>&lt;p>歐拉將費馬小定理推廣如下：&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>歐拉定理 (Euler&amp;rsquo;s Theorem)&lt;/strong>
對於正整數 $n$ 以及與其互質的整數 $a$，以下關係成立：
&lt;/p>
$$ a^{\phi(n)} \equiv 1 \pmod n $$
&lt;/blockquote>
&lt;p>如果 $n$ 是質數 $p$，則 $\phi(p) = p - 1$，這就變成了費馬小定理本身（$a^{p-1} \equiv 1 \pmod p$）。也就是說，費馬小定理只不過是歐拉定理的一個特例。&lt;/p>
&lt;hr>
&lt;h2 id="5-尋找巨大的質數費馬質數判定法">5. 尋找巨大的質數：費馬質數判定法
&lt;/h2>&lt;p>在加密技術（如 RSA 加密與 Diffie-Hellman 金鑰交換等）中，必須能高速找出長達數百位數的「巨大質數」。然而，如果要判定一個巨大數字 $N$ 是否為質數，若使用測試除以從 $2$ 到 $\sqrt{N}$ 的所有數字是否能整除的「試除法」，將會花費等同於宇宙壽命般漫長的時間。&lt;/p>
&lt;p>因此，反過來利用費馬小定理的「機率性質數判定法」，即 &lt;strong>費馬質數判定法（Fermat Primality Test）&lt;/strong> 便應運而生。&lt;/p>
&lt;h3 id="51-什麼是機率性質數判定法">5.1 什麼是機率性質數判定法
&lt;/h3>&lt;p>根據費馬小定理，若 $p$ 為質數，則對於任意的 $a$ ($1 &lt; a &lt; p$)，$a^{p-1} \equiv 1 \pmod p$ 必然成立。
取其逆否命題，可以說「如果對於某個 $a$，得出 $a^{p-1} \not\equiv 1 \pmod p$，那麼 $p$ &lt;strong>絕對不是質數（是合數）&lt;/strong>」。&lt;/p>
&lt;p>因此，如果想判定 $N$ 是否為質數，隨機選擇幾個 $a$，計算 $a^{N-1} \pmod N$ 並確認結果是否為 $1$。如果只要有一次得出 $1$ 以外的答案，就可以確定 $N$ 是合數。如果試了多次結果都是 $1$，則可以高度機率地判斷 $N$ 「大概是質數」。&lt;/p>
&lt;h3 id="52-演算法解說與流程圖">5.2 演算法解說與流程圖
&lt;/h3>&lt;p>費馬質數判定法的演算法如下。&lt;/p>
&lt;div class="mermaid">flowchart TD
Start["開始"] --> Input["輸入判定目標數 p 與測試次數 k"]
Input --> LoopStart["迴圈從 i = 0 到 k-1"]
LoopStart --> Condition{"i &lt; k ?"}
Condition -- "是" --> RandomA["在 1 &lt; a &lt; p-1 範圍內隨機選擇整數 a"]
RandomA --> Calc["計算模冪 a^(p-1) mod p"]
Calc --> CheckPrime{"結果為 1 嗎？"}
CheckPrime -- "否" --> ReturnComposite["p 是合數（確定）"]
CheckPrime -- "是" --> Increment["將 i 加 1"]
Increment --> Condition
Condition -- "否" --> ReturnPrime["p 大概是質數（機率性）"]
ReturnComposite --> End["結束"]
ReturnPrime --> End&lt;/div>
&lt;h3 id="53-卡邁克爾數偽質數的陷阱">5.3 卡邁克爾數（偽質數）的陷阱
&lt;/h3>&lt;p>費馬質數判定法雖然非常快速，但有一個重大的缺點。那就是存在著像惡魔一般的數字，明明是合數，卻對所有的 $a$ 都滿足 $a^{N-1} \equiv 1 \pmod N$。這被稱為 &lt;strong>卡邁克爾數 (Carmichael numbers)&lt;/strong>。最小的卡邁克爾數是 $561$ ($3 \times 11 \times 17$)。&lt;/p>
&lt;p>由於卡邁克爾數的存在，單純的費馬測試無法進行絕對的質數判定。因此，在實際的加密系統（如 OpenSSL 等）中，標準使用的是改良自費馬測試的 &lt;strong>米勒-拉賓（Miller-Rabin）質數判定法&lt;/strong>。因為米勒-拉賓判定法能看穿卡邁克爾數，可將誤判的機率實質上降至零。&lt;/p>
&lt;h3 id="54-高速的模冪運算反覆平方法">5.4 高速的模冪運算（反覆平方法）
&lt;/h3>&lt;p>在質數判定演算法中，需要計算 $a^{N-1} \pmod N$，但當 $N$ 巨大時，$a^{N-1}$ 將成為天文數字級別的位數，無法裝入電腦的記憶體中。
解決這個問題的是 &lt;strong>反覆平方法（Exponentiation by Squaring）&lt;/strong> 或模冪運算。透過在計算的每一個步驟都取餘數（mod N），可以讓數值始終保持小於 $N$，從而能非常高速（計算複雜度為 $O(\log N)$）地進行計算。&lt;/p>
&lt;hr>
&lt;h2 id="6-質數判定與模冪運算的實作">6. 質數判定與模冪運算的實作
&lt;/h2>&lt;p>那麼，我們就來使用 C++ 和 Python 實作費馬質數判定法和反覆平方法吧。&lt;/p>
&lt;h3 id="61-使用-c-實作">6.1 使用 C++ 實作
&lt;/h3>&lt;p>在 C++ 中，標準整數型別容易發生溢位，處理巨大數字時需要多精度整數函式庫（如 GMP 等）。不過，為了理解演算法，這裡展示在 64 位元整數（&lt;code>unsigned long long&lt;/code>）範圍內的實作。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;random&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="k">namespace&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 高速的模冪運算 (a^b 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="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">// 若 b 的最低位元為 1，則將 result 乘上 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">// 為防止溢位擴展為 128bit
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 將 a 平方
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">__int128&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="n">a&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 將 b 右移（減半）
&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">// 費馬質數判定法
&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">// 若 a^(p-1) mod p 不為 1，則是合數
&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">// 大概是質數
&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">// 已知的質數
&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-使用-python-實作">6.2 使用 Python 實作
&lt;/h3>&lt;p>Python 的標準整數型別支援多精度整數，因此不需擔心位數溢位。此外，Python 的內建函數 &lt;code>pow(a, b, m)&lt;/code> 內部就使用了反覆平方法，因此非常快速。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;/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"> 使用費馬質數判定法的機率性質數判定
&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"># 在 2 到 p-2 之間隨機選擇一個數字 a&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"># 計算 a^(p-1) mod p。內建的 pow 很快速。&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"># 確定是合數&lt;/span>
&lt;/span>&lt;/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"># 大概是質數&lt;/span>
&lt;/span>&lt;/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"># 測試&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"> 大概是質數。&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"> 是合數。&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-在-rsa-加密中的應用費馬與歐拉結果的地方">7. 在 RSA 加密中的應用：費馬與歐拉結果的地方
&lt;/h2>&lt;p>費馬小定理（以及歐拉定理）最偉大的應用領域，就是 1977 年由 Rivest、Shamir 與 Adleman 三人所開發的 &lt;strong>RSA 加密&lt;/strong>。
RSA 加密是一個名為「公開金鑰加密」的劃時代系統，它實現了一種機制：用來加密的金鑰（公開金鑰）對全世界公開，但用來解密的金鑰（私鑰）只有接收者本人知道。&lt;/p>
&lt;p>這種不對稱性，是基於「將巨大的合數進行質因數分解是極度困難的」這一計算複雜度上的安全性。&lt;/p>
&lt;h3 id="71-rsa-加密的機制金鑰生成加密解密">7.1 RSA 加密的機制（金鑰生成、加密、解密）
&lt;/h3>&lt;p>讓我們透過 Mermaid 的循序圖來確認 RSA 加密的整體通訊流程。&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant Alice["愛麗絲 (接收者)"]
participant Bob["鮑伯 (發送者)"]
Alice->>Alice: "生成巨大的質數 p, q"
Alice->>Alice: "計算 N = p * q, φ(N) = (p-1)(q-1)"
Alice->>Alice: "計算公開金鑰 e 與私鑰 d (e*d ≡ 1 mod φ(N))"
Alice->>Bob: "傳送公開金鑰 (N, e)"
Note over Bob: "準備明文 M (M &lt; N)"
Bob->>Bob: "計算密文 C = M^e mod N"
Bob->>Alice: "傳送密文 C"
Alice->>Alice: "計算明文 M = C^d mod N 並解密"&lt;/div>
&lt;p>以下解說數學上的詳細步驟。&lt;/p>
&lt;h4 id="步驟-1金鑰的生成接收者愛麗絲的作業">步驟 1：金鑰的生成（接收者愛麗絲的作業）
&lt;/h4>&lt;ol>
&lt;li>隨機生成兩個巨大的質數 $p$ 與 $q$（這裡會用到前述的質數判定法）。&lt;/li>
&lt;li>計算其乘積 $N = p \times q$。這個 $N$ 會被公開。&lt;/li>
&lt;li>使用歐拉函數，計算 $\phi(N) = (p-1)(q-1)$。&lt;/li>
&lt;li>選擇與 $\phi(N)$ 互質的整數 $e$（公開指數）（常使用 $e = 65537$）。&lt;/li>
&lt;li>計算 $e$ 的模反元素 $d$（私密指數）。亦即，找出滿足下式的 $d$：
$$ e \cdot d \equiv 1 \pmod{\phi(N)} $$
這個計算使用了&lt;strong>擴展歐幾里得演算法&lt;/strong>。&lt;/li>
&lt;/ol>
&lt;p>至此，&lt;strong>公開金鑰為 $(N, e)$&lt;/strong>，&lt;strong>私鑰為 $(N, d)$&lt;/strong>。（$p, q, \phi(N)$ 會立即銷毀或嚴格保密）。&lt;/p>
&lt;h4 id="步驟-2加密發送者鮑伯的作業">步驟 2：加密（發送者鮑伯的作業）
&lt;/h4>&lt;p>假設鮑伯想發送訊息 $M$ 給愛麗絲（$M$ 是將文字轉換為數值後的結果，且 $0 \le M &lt; N$）。
鮑伯使用愛麗絲的公開金鑰 $(N, e)$，進行以下計算製作密文 $C$：&lt;/p>
$$
C \equiv M^e \pmod N
$$
&lt;p>透過網路將這個 $C$ 發送給愛麗絲。&lt;/p>
&lt;h4 id="步驟-3解密接收者愛麗絲的作業">步驟 3：解密（接收者愛麗絲的作業）
&lt;/h4>&lt;p>收到密文 $C$ 的愛麗絲，使用只有自己知道的私鑰 $d$ 進行以下計算：&lt;/p>
$$
M' \equiv C^d \pmod N
$$
&lt;p>令人驚奇的是，這個計算結果 $M'$ 會與原始訊息 $M$ 完全一致。&lt;/p>
&lt;h3 id="72-為什麼能解密數學證明">7.2 為什麼能解密？（數學證明）
&lt;/h3>&lt;p>在這裡，費馬小定理（歐拉定理）發揮了它的真正價值。為什麼 $C^d \pmod N$ 能變回 $M$ 呢？&lt;/p>
&lt;p>我們將解密的式子展開。
因為 $C \equiv M^e \pmod N$，所以：
&lt;/p>
$$ C^d \equiv (M^e)^d \equiv M^{ed} \pmod N $$
&lt;p>在金鑰生成的步驟中，我們選擇了 $d$ 使得 $e \cdot d \equiv 1 \pmod{\phi(N)}$。這意味著存在某個整數 $k$，可以寫成如下形式：
&lt;/p>
$$ e \cdot d = 1 + k \cdot \phi(N) $$
&lt;p>將其代入上面的式子：
&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>在這裡&lt;strong>歐拉定理&lt;/strong> ($M^{\phi(N)} \equiv 1 \pmod N$) 登場了。（※嚴格來說，$M$ 和 $N$ 必須互質，但在 RSA 中 $M$ 和 $N$ 不互質的機率是天文數字級別地低，且透過中國剩餘定理可以證明即使不互質也成立）。&lt;/p>
&lt;p>應用歐拉定理，$M^{\phi(N)} \equiv 1$，因此：
&lt;/p>
$$ M \cdot (1)^k \equiv M \pmod N $$
&lt;p>完美地還原了 $M$！費馬與歐拉在幾百年前發現的數之性質，完美地保證了現代數位通訊的機密性。&lt;/p>
&lt;hr>
&lt;h2 id="8-rsa-加密的簡易實作-python">8. RSA 加密的簡易實作 (Python)
&lt;/h2>&lt;p>因為只有理論較難體會，所以我們用 Python 來實際實作 RSA 加密的金鑰生成、加密、解密的過程吧。這是一個供教育用途的「簡易（玩具）實作」，但所使用的數學與真實情況完全相同。&lt;/p>
&lt;p>用來求得模反元素 $d$ 的「擴展歐幾里得演算法」也包含在實作中。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;span class="lnt">74
&lt;/span>&lt;span class="lnt">75
&lt;/span>&lt;span class="lnt">76
&lt;/span>&lt;span class="lnt">77
&lt;/span>&lt;span class="lnt">78
&lt;/span>&lt;span class="lnt">79
&lt;/span>&lt;span class="lnt">80
&lt;/span>&lt;span class="lnt">81
&lt;/span>&lt;span class="lnt">82
&lt;/span>&lt;span class="lnt">83
&lt;/span>&lt;span class="lnt">84
&lt;/span>&lt;span class="lnt">85
&lt;/span>&lt;span class="lnt">86
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">random&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 求最大公因數&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"># 擴展歐幾里得演算法 (求得 ax + by = gcd(a,b) 的 x, y)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 用於尋找 e*d ≡ 1 (mod φ(N)) 中的 d&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;不存在反元素&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"># 質數生成函數（簡易版：生成小質數）&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"># 用簡單判定來代替前述的費馬測試&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 金鑰生成&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"># 避免 p 和 q 變成一樣&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 常使用 65537 等質數，但這裡隨機選擇&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"># 私鑰 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"># 公開金鑰 (e, n), 私鑰 (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"># 計算 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"># 計算 cipher^d mod n，並轉回字元&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"># 執行範例&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加密 簡易實作 ---&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"># 使用 12bit 的質數&lt;/span>
&lt;/span>&lt;/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;公開金鑰 (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;私鑰 (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">原始訊息: &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"># 加密&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;密文: &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"># 解密&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;解密後的訊息: &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>執行這段程式碼後，就可以確認字元陣列如何被轉換成不眼熟的數字陣列（密文），然後再透過私鑰完美還原為原始字串的過程。&lt;/p>
&lt;hr>
&lt;h2 id="9-結語數學之美與實用性的交會點">9. 結語：數學之美與實用性的交會點
&lt;/h2>&lt;p>在 17 世紀，當皮耶·德·費馬發現這個「小定理」時，沒有人認為這會有什麼實際用途。費馬本人也是出於純粹的數學探求心在進行數論的研究。&lt;/p>
&lt;p>然而，大約 300 年後的 1970 年代，在電腦網路的黎明期，作為確立安全通訊協定不可或缺的加密技術，費馬定理實現了戲劇性的復活。基於費馬小定理的質數判定技術，以及基於歐拉定理的 RSA 加密，字面上支撐著現代的網際網路基礎設施。&lt;/p>
&lt;p>我們每天不經意發送的 LINE 訊息、在 Amazon 上的購物，全都是在這個 $a^{p-1} \equiv 1 \pmod p$ 簡單而優美的數學公式之上舞動著的。費馬小定理告訴我們，無論數學多麼抽象，總有一天必定會派上用場。&lt;/p>
&lt;p>在學習程式設計或密碼學理論時，理解其基礎的數學結構，將會成為深入理解那些被當作黑盒子般提供的函式庫運作方式，並設計出更安全系統的一大武器。&lt;/p></description></item><item><title>格子密碼學（Lattice-based cryptography）的數學直觀</title><link>http://kenji.blog/zh-tw/p/lattice-based-cryptography-math-intuition/</link><pubDate>Fri, 11 Sep 2026 21:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/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 格子密碼學（Lattice-based cryptography）的數學直觀" />&lt;h1 id="1-導入後量子密碼學pqc的黎明與格子密碼學的崛起">1. 導入：後量子密碼學（PQC）的黎明與格子密碼學的崛起
&lt;/h1>&lt;p>支撐現代社會數位基礎設施的是以 RSA 密碼和橢圓曲線密碼（ECC）為首的公鑰密碼技術。這些密碼系統是將安全性的基礎建立在「質因數分解問題」與「離散對數問題」等數學難題上，人們相信傳統古典電腦無法有效率地解決這些問題（需要指數級時間）。&lt;/p>
&lt;p>然而，彼得·秀爾（Peter Shor）於1994年發表的「秀爾演算法（Shor&amp;rsquo;s algorithm）」在密碼學界引發了震撼。該演算法在數學上證明了，一旦大規模的量子電腦問世，就能在多項式時間內解決質因數分解問題與離散對數問題。這意味著目前被廣泛使用的公鑰密碼學，在未來將完全可能被破解。&lt;/p>
&lt;p>為了對抗這種「量子威脅（Quantum Threat）」，迫切需要研究即使使用量子電腦也難以破解的新型密碼系統。這就是被稱為「後量子密碼學（Post-Quantum Cryptography: PQC）」或「抗量子計算密碼學」的領域。&lt;/p>
&lt;p>PQC 有幾個有力的候選方案。包括基於雜湊的密碼學、基於編碼的密碼學、多變數多項式密碼學以及同源密碼學等，但其中目前最受矚目，且處於 NIST（美國國家標準暨技術研究院）PQC 標準化流程核心的，就是「格子密碼學（Lattice-based cryptography）」。與其他方法相比，格子密碼學具有極快的加密和解密處理速度，並具備一個在密碼理論中極為強大的安全性證明：將「最壞情況複雜度（Worst-case complexity）」歸約至「平均情況複雜度（Average-case complexity）」。&lt;/p>
&lt;p>本文將從作為格子密碼學基礎的「格子（Lattice）」的數學定義出發，深入淺出地解說格子上的困難問題，如 SVP（最短向量問題）和 CVP（最近點向量問題），以及可說是現代格子密碼學心臟的「LWE 問題（Learning With Errors，容錯學習問題）」。文中將結合數學公式、幾何直觀，以及具體的數值範例來進行徹底且深入的解說。&lt;/p>
&lt;h1 id="2-格子lattice的數學定義與幾何直觀">2. 格子（Lattice）的數學定義與幾何直觀
&lt;/h1>&lt;h2 id="21-向量空間與格子">2.1 向量空間與格子
&lt;/h2>&lt;p>在數學中，「格子（Lattice）」是指在 $n$ 維實數向量空間 $\mathbb{R}^n$ 內，有規則地排列的離散點的集合。雖然它與線性代數中學到的向量空間（Vector Space）相似，但有著決定性的差異。向量空間是由基底向量以「實數係數」的線性組合所表示的連續空間，而格子則是由基底向量以「整數係數」的線性組合所表示的離散空間。&lt;/p>
&lt;p>讓我們給出數學上嚴格的定義。考慮在 $m$ 維實數向量空間 $\mathbb{R}^m$ 中的 $n$ 個（$n \le m$）線性獨立的向量 $\mathbf{b}_1, \mathbf{b}_2, \dots, \mathbf{b}_n$。將這些向量作為行向量構成的矩陣設為 $B = [\mathbf{b}_1, \mathbf{b}_2, \dots, \mathbf{b}_n] \in \mathbb{R}^{m \times n}$。我們將這個 $B$ 稱為格子的「基底（Basis）」。&lt;/p>
&lt;p>由這個基底 $B$ 所生成的格子 $\mathcal{L}(B)$ 定義如下：&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>這裡的重點在於，係數 $x_i$ 僅限於整數 $\mathbb{Z}$，而非實數 $\mathbb{R}$。這使得空間內形成的不是無數連續的點，而是像等間距排列的十字路口般的「離散點的集合」。&lt;/p>
&lt;h2 id="22-幾何直觀">2.2 幾何直觀
&lt;/h2>&lt;p>讓我們以二維平面 $\mathbb{R}^2$ 為例來思考。如果選擇基底向量為 $\mathbf{b}_1 = \begin{pmatrix} 1 \\ 0 \end{pmatrix}$ 與 $\mathbf{b}_2 = \begin{pmatrix} 0 \\ 1 \end{pmatrix}$，由它們生成的格子，將會是座標平面上所有整數座標 $(x, y) \in \mathbb{Z}^2$ 的集合。這是最簡單的「正方格子」。&lt;/p>
&lt;p>然而，格子並不總是正交的。例如，如果我們考慮基底 $\mathbf{b}_1 = \begin{pmatrix} 2 \\ 1 \end{pmatrix}$ 與 $\mathbf{b}_2 = \begin{pmatrix} 1 \\ 3 \end{pmatrix}$，所生成的點將會像傾斜扭曲的網格交點。&lt;/p>
&lt;h2 id="23-基底的非唯一性與么模變換">2.3 基底的非唯一性與么模變換
&lt;/h2>&lt;p>這裡有一個攸關格子密碼學安全性根本的重要性質。那就是「能生成相同格子的基底有無數個」。&lt;/p>
&lt;p>例如，前面提到的由基底 $\mathbf{b}_1 = (1, 0)^T, \mathbf{b}_2 = (0, 1)^T$ 生成的 $\mathbb{Z}^2$ 格子，如果使用 $\mathbf{b}'_1 = (1, 1)^T, \mathbf{b}'_2 = (2, 3)^T$ 這個基底，也會生成完全相同的格子 $\mathbb{Z}^2$。&lt;/p>
&lt;p>某個基底 $B$ 和另一個基底 $B'$ 能生成相同格子的充分必要條件是：存在一個元素均為整數的矩陣 $U \in \mathbb{Z}^{n \times n}$，其行列式為 $\det(U) = \pm 1$，並且可以表示為：
&lt;/p>
$$ B' = B U $$
&lt;p>
這樣的矩陣 $U$ 被稱為「么模矩陣（Unimodular matrix）」。&lt;/p>
&lt;p>在密碼學應用上的基本概念是：將「好的基底（接近正交、由較短向量組成的基底）」作為私鑰，並將「壞的基底（互相極度斜交、由非常長的向量組成的基底）」作為公鑰。隨著維度的增加，要透過計算從壞的基底求出好的基底將會變得非常困難。這就是格子密碼學的基本直觀。&lt;/p>
&lt;h1 id="3-格子中的計算困難問題">3. 格子中的計算困難問題
&lt;/h1>&lt;p>格子密碼學的安全性仰賴於解決格子上特定數學問題的困難度。在這裡，我們介紹最基本且最著名的兩個問題。&lt;/p>
&lt;h2 id="31-最短向量問題shortest-vector-problem-svp">3.1 最短向量問題（Shortest Vector Problem: SVP）
&lt;/h2>&lt;p>SVP 是格子理論中最經典且著名的問題。&lt;/p>
&lt;p>&lt;strong>定義（SVP）：&lt;/strong>
給定任意格子基底 $B$，在該格子 $\mathcal{L}(B)$ 所屬的非零向量中，找出歐幾里得範數（長度）最小的向量 $\mathbf{v}$。&lt;/p>
&lt;p>用數學公式表示，就是求出使得 $\min_{\mathbf{v} \in \mathcal{L}(B) \setminus \{\mathbf{0}\}} \| \mathbf{v} \|$ 成立的 $\mathbf{v}$ 的問題。這個最小的長度記為 $\lambda_1(\mathcal{L})$，被稱為「格子的第一連續最小值（First successive minimum）」。&lt;/p>
&lt;p>如果是在二維或三維的低維度空間，只要畫個圖就能用肉眼找到最短的向量。或者，也可以使用高斯（Gauss）的格子基底歸約演算法等來有效率地解決。然而，當維度 $n$ 達到數百至數千這類高維度時，已知嚴格解出 SVP 是 NP 困難的。&lt;/p>
&lt;p>在現實的密碼學中，使用的是尋找「近似較短向量」的近似 SVP（$\gamma$-SVP），而不是嚴格的最短向量。當近似係數 $\gamma$ 為多項式大小時，該問題仍然被認為是非常困難的。&lt;/p>
&lt;h2 id="32-最近點向量問題closest-vector-problem-cvp">3.2 最近點向量問題（Closest Vector Problem: CVP）
&lt;/h2>&lt;p>CVP 也是格子密碼學中極為重要的問題。&lt;/p>
&lt;p>&lt;strong>定義（CVP）：&lt;/strong>
給定任意格子基底 $B$ 以及空間內任意的目標向量 $\mathbf{t} \in \mathbb{R}^m$（不一定是格子點），找出所有格子點中距離 $\mathbf{t}$ 最近的格子點 $\mathbf{v} \in \mathcal{L}(B)$。&lt;/p>
&lt;p>用數學公式表示，就是尋找使得 $\min_{\mathbf{v} \in \mathcal{L}(B)} \| \mathbf{v} - \mathbf{t} \|$ 成立的格子點 $\mathbf{v}$ 的問題。&lt;/p>
&lt;p>與 SVP 一樣，CVP 在高維度中也是 NP 困難的。從密碼學應用的角度來看，稍後將提到的 LWE 問題，與這個 CVP 的特殊變體（Bounded Distance Decoding: BDD，有界距離解碼）有著密切的關係。&lt;/p>
&lt;h2 id="33-為什麼高維度時會解不出來lll-與-bkz-的極限">3.3 為什麼高維度時會解不出來？（LLL 與 BKZ 的極限）
&lt;/h2>&lt;p>作為解決高維度格子問題的著名演算法，有 LLL 演算法（Lenstra-Lenstra-Lovász algorithm）。LLL 演算法可以在多項式時間內運作，並將格子基底在某種程度上歸約（Reduction）為「好的基底」。然而，LLL 演算法所能找到的最短向量，其長度相對於真正的最短向量有一個呈指數級（$2^{\mathcal{O}(n)}$）增長的近似係數，因此並不足以破解密碼的安全性。&lt;/p>
&lt;p>如果使用對 LLL 進行改良的 BKZ（Block Korkine-Zolotarev）演算法等更強大的基底歸約演算法，就能找到更短的向量，但其計算量會相對於區塊大小（Block size）呈指數級增長。在格子密碼學中，正是透過估算這個 BKZ 演算法的執行時間來決定安全的參數（例如維度 $n$ 的大小等）。在目前 PQC 的標準參數中，維度 $n$ 被設定為 500 到 1000 以上的值，據說即使使用超級電腦或未來的量子電腦，破解所需的時間也會超過宇宙的年齡。&lt;/p>
&lt;h1 id="4-lwe-問題learning-with-errors的數學形式化">4. LWE 問題（Learning With Errors）的數學形式化
&lt;/h1>&lt;p>現代大部分的格子密碼學都基於 2005 年由 Oded Regev 所提出的「LWE 問題（Learning With Errors，容錯學習問題）」。LWE 問題的絕妙之處在於其形式化的簡單性，以及擁有「將最壞情況複雜度歸約為平均情況複雜度」這項強大的數學證明。&lt;/p>
&lt;h2 id="41-無雜訊的線性方程組">4.1 無雜訊的線性方程組
&lt;/h2>&lt;p>為了理解 LWE 問題，首先讓我們先考慮一個沒有雜訊的簡單線性方程組。
假設有一個未知的秘密向量 $\mathbf{s} \in \mathbb{Z}_q^n$（各個分量為 $0$ 到 $q-1$ 的整數）。這裡我們假設 $q$ 是質數。&lt;/p>
&lt;p>隨機選取係數向量 $\mathbf{a}_1, \mathbf{a}_2, \dots \in \mathbb{Z}_q^n$，並計算與秘密向量 $\mathbf{s}$ 的內積（對 $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>只要給定足夠數量（$n$ 個以上）的 $(\mathbf{a}_i, b_i)$ 數對，我們就可以利用線性代數中的「高斯消去法（Gaussian elimination）」，輕鬆地還原出秘密向量 $\mathbf{s}$。這是一個在多項式時間內可以輕易解出的問題。&lt;/p>
&lt;h2 id="42-lwe-問題的定義加入雜訊">4.2 LWE 問題的定義：加入雜訊
&lt;/h2>&lt;p>那麼，如果在這個問題中加入微小的「雜訊（誤差）」，會發生什麼事呢？
這就是 LWE 問題的本質。&lt;/p>
&lt;p>對未知的秘密向量 $\mathbf{s} \in \mathbb{Z}_q^n$，在各個方程式的結果中加入微小的誤差 $e_i \in \mathbb{Z}_q$：
$b_i = \langle \mathbf{a}_i, \mathbf{s} \rangle + e_i \pmod q$&lt;/p>
&lt;p>這裡的 $e_i$ 是一個平均值為 0、標準差相對較小（例如從常態分佈那樣的離散高斯分佈中選取）的微小整數值。
給定的資訊是隨機向量 $\mathbf{a}_i$ 與加上誤差後計算出的 $b_i$ 所構成的數對列表：
$( \mathbf{a}_1, b_1 ), ( \mathbf{a}_2, b_2 ), \dots, ( \mathbf{a}_m, b_m )$&lt;/p>
&lt;p>用矩陣來表示會非常簡潔：
使用隨機矩陣 $A \in \mathbb{Z}_q^{m \times n}$、秘密向量 $\mathbf{s} \in \mathbb{Z}_q^n$、誤差向量 $\mathbf{e} \in \mathbb{Z}_q^m$，可以寫成：
&lt;/p>
$$ \mathbf{b} = A \mathbf{s} + \mathbf{e} \pmod q $$
&lt;p>
我們只會被給予 $A$ 和 $\mathbf{b}$。從中求出 $\mathbf{s}$ 的問題就是「搜尋 LWE 問題（Search LWE problem）」。&lt;/p>
&lt;p>因為加入了誤差 $e_i$，如果試圖使用高斯消去法，在方程式加減的過程中誤差會呈指數級放大，最終將無法推導出正確的答案。乍看之下這只是一個簡單的線性方程組，但僅僅因為加入了這個微小的雜訊，問題的難度就躍升至 NP 困難的層級。&lt;/p>
&lt;h2 id="43-判定-lwe-問題decision-lwe">4.3 判定 LWE 問題（Decision LWE）
&lt;/h2>&lt;p>在密碼理論的證明中頻繁使用的，是搜尋 LWE 問題的變體——「判定 LWE 問題（Decision LWE problem）」。&lt;/p>
&lt;p>判定 LWE 問題是指，給定一個從以下兩種分佈中取得樣本的列表時，判定它來自哪一種分佈的問題：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>LWE 分佈&lt;/strong>：刻意計算出的 $(A, \mathbf{b} = A\mathbf{s} + \mathbf{e} \pmod q)$&lt;/li>
&lt;li>&lt;strong>均勻隨機分佈&lt;/strong>：由完全隨機選取的矩陣 $A$ 與向量 $\mathbf{u}$ 所構成的 $(A, \mathbf{u})$&lt;/li>
&lt;/ol>
&lt;p>令人驚訝的是，只要適當地選擇 LWE 問題的參數，從 LWE 分佈取得的數對，將與完全隨機資料的數對「在計算上不可區分（Computationally Indistinguishable）」。這個性質正是基於 LWE 的密碼能夠生成「與隨機數無法區分的密文」的根據。&lt;/p>
&lt;h2 id="44-從最壞情況複雜度到平均情況複雜度的歸約regev-定理">4.4 從最壞情況複雜度到平均情況複雜度的歸約（Regev 定理）
&lt;/h2>&lt;p>Oded Regev 最大的貢獻，就是將這個 LWE 問題的困難度，在數學上與前述的格子問題（SVP 與 CVP）的困難度連結了起來。&lt;/p>
&lt;p>他運用了量子歸約（Quantum reduction），證明了「如果存在能在平均情況下（對於隨機選取的 $A$ 和 $\mathbf{e}$）在多項式時間內解決 LWE 問題的演算法，那麼就存在能在多項式時間內解決任何格子在最壞情況下（最難的情況）的 Gap-SVP 的量子演算法」。（後來，Peikert 等人也提出了古典歸約的證明）。&lt;/p>
&lt;p>這在密碼理論中是一個夢寐以求的性質。因為它消除了「密碼被破解，可能只是因為我們碰巧選到了弱的密鑰（平均情況中的一小部分）」這種疑慮，並提供了「如果能解決平均情況的 LWE，就能解決格子中所有最難的問題（因此 LWE 絕對是困難的）」這樣強大的保證。&lt;/p>
&lt;div class="mermaid">graph TD
A["最壞情況的格子問題 (Gap-SVP, SIVP)"] -->|量子/古典歸約| B["平均情況的 LWE 問題"]
B -->|密碼學構造| C["基於 LWE 的密碼系統 (PKE, KEM, FHE)"]
style A fill:#ffcccc,stroke:#ff0000,stroke-width:2px,color:#000
style B fill:#ccffcc,stroke:#00aa00,stroke-width:2px,color:#000
style C fill:#ccccff,stroke:#0000ff,stroke-width:2px,color:#000&lt;/div>
&lt;h1 id="5-基於-lwe-的公鑰密碼系統regev-密碼的建構">5. 基於 LWE 的公鑰密碼系統（Regev 密碼）的建構
&lt;/h1>&lt;p>了解了 LWE 問題的困難度之後，我們來看看如何使用它進行加密和解密，也就是 Oded Regev 所提出的基本公鑰密碼系統。這裡將解說對 1 位元訊息 $M \in \{0, 1\}$ 進行加密的最基本機制。&lt;/p>
&lt;h2 id="51-金鑰生成key-generation">5.1 金鑰生成（Key Generation）
&lt;/h2>&lt;ol>
&lt;li>作為系統參數，決定模數質數 $q$、維度 $n$、方程式數量 $m$（$m > n \log q$）。&lt;/li>
&lt;li>隨機選取向量 $\mathbf{s} \in \mathbb{Z}_q^n$ 作為私鑰。&lt;/li>
&lt;li>生成隨機矩陣 $A \in \mathbb{Z}_q^{m \times n}$。&lt;/li>
&lt;li>從離散高斯分佈等誤差分佈中選取微小的誤差向量 $\mathbf{e} \in \mathbb{Z}_q^m$。&lt;/li>
&lt;li>計算向量 $\mathbf{b} = A \mathbf{s} + \mathbf{e} \pmod q$。&lt;/li>
&lt;li>公鑰（Public Key）為 $(A, \mathbf{b})$。&lt;/li>
&lt;li>私鑰（Secret Key）為 $\mathbf{s}$。&lt;/li>
&lt;/ol>
&lt;p>公鑰本身簡直就是「LWE 問題的實例」。由於從公鑰 $(A, \mathbf{b})$ 求出私鑰 $\mathbf{s}$ 等同於解決搜尋 LWE 問題，因此保證了其安全性。&lt;/p>
&lt;h2 id="52-加密encryption">5.2 加密（Encryption）
&lt;/h2>&lt;p>愛麗絲使用鮑伯的公鑰 $(A, \mathbf{b})$，對 1 位元訊息 $M \in \{0, 1\}$ 進行加密。&lt;/p>
&lt;ol>
&lt;li>隨機選取一個二進位向量（各分量為 0 或 1）$\mathbf{r} \in \{0, 1\}^m$。&lt;/li>
&lt;li>計算向量 $\mathbf{u} = A^T \mathbf{r} \pmod q$，作為密文的前半部。（$A^T$ 是 $A$ 的轉置矩陣。也就是說，這是在將 $A$ 的列中與 $\mathbf{r}$ 分量為 1 對應的那些列加總起來）。&lt;/li>
&lt;li>計算純量 $v = \mathbf{b}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor \pmod q$，作為密文的後半部。
（如果訊息 $M$ 為 0，則不加任何東西；如果為 1，則加上正好是 $q$ 一半的值 $\lfloor \frac{q}{2} \rfloor$）。&lt;/li>
&lt;li>密文（Ciphertext）為 $(\mathbf{u}, v)$。&lt;/li>
&lt;/ol>
&lt;p>加密直觀上的意義，是針對公鑰的矩陣 $A$ 和向量 $\mathbf{b}$ 取「隨機子集的和」。由於判定 LWE 問題的困難度，這個密文 $(\mathbf{u}, v)$ 看起來將與完全隨機的向量和均勻隨機數無法區分（語意安全性：Semantic Security）。&lt;/p>
&lt;div class="mermaid">flowchart LR
M["訊息 M 屬於 {0,1}"] --> Enc
PK["公鑰 (A, b)"] --> Enc
r["隨機二進位向量 r"] --> Enc
subgraph Enc ["加密過程"]
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["密文 (u, v)"]&lt;/div>
&lt;h2 id="53-解密decryption">5.3 解密（Decryption）
&lt;/h2>&lt;p>鮑伯使用私鑰 $\mathbf{s}$ 來解密密文 $(\mathbf{u}, v)$。&lt;/p>
&lt;ol>
&lt;li>計算以下的值： $D = v - \mathbf{s}^T \mathbf{u} \pmod q$&lt;/li>
&lt;li>如果計算結果接近 $0$，則輸出 $M=0$；如果接近 $\lfloor \frac{q}{2} \rfloor$，則輸出 $M=1$。&lt;/li>
&lt;/ol>
&lt;p>為什麼這樣就能解密呢？讓我們在數學上展開來看看。
請回憶一下 $\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>在這裡，公式中的 $\mathbf{s}^T A^T \mathbf{r}$ 被完美地抵消掉了！
剩下的部分是 $\mathbf{e}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor$。&lt;/p>
&lt;p>$\mathbf{e}$ 是分量非常小的雜訊向量，而 $\mathbf{r}$ 是分量為 0 或 1 的二進位向量。因此，它們的內積 $\mathbf{e}^T \mathbf{r}$ 也會（只要參數設定得當）保持在一個相對較小的值。&lt;/p>
&lt;ul>
&lt;li>如果 $M=0$，結果會是 $\mathbf{e}^T \mathbf{r}$，這是一個接近 $0$ 的小數值。&lt;/li>
&lt;li>如果 $M=1$，結果會是 $\mathbf{e}^T \mathbf{r} + \lfloor \frac{q}{2} \rfloor$，這會位於 $q$ 的一半即 $\lfloor \frac{q}{2} \rfloor$ 附近。&lt;/li>
&lt;/ul>
&lt;p>只要參數的設計能讓誤差 $\mathbf{e}^T \mathbf{r}$ 的絕對值收斂在 $\frac{q}{4}$ 以內，鮑伯只需要看計算結果是比較接近 $0$ 還是 $\lfloor \frac{q}{2} \rfloor$，就能正確地判定（解密）訊息 $M$。這就是基於 LWE 的密碼能夠運作的美妙機制。&lt;/p>
&lt;div class="mermaid">flowchart LR
CT["密文 (u, v)"] --> Dec
SK["私鑰 s"] --> Dec
subgraph Dec ["解密過程"]
direction TB
calc["計算 D = v - s^T * u mod q"]
check["檢查 D 是接近 0 還是 q/2"]
end
calc --> check
Dec --> M_out["還原出的訊息 M"]&lt;/div>
&lt;h1 id="6-使用具體數值的-lwe-密碼玩具範例">6. 使用具體數值的 LWE 密碼玩具範例
&lt;/h1>&lt;p>只看一堆數學公式可能很難有真實感，所以我們實際設定極小的數值參數，來追蹤一次從加密到解密的計算過程。
（※在現實的密碼系統中，為了確保安全性，$n$ 會設定在 500 以上，$q$ 則是使用數千以上的值）&lt;/p>
&lt;p>&lt;strong>【參數設定】&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>模數 $q = 17$ （質數。因此值會落在 $0$ 到 $16$ 的範圍內）&lt;/li>
&lt;li>維度 $n = 2$&lt;/li>
&lt;li>方程式數量 $m = 4$&lt;/li>
&lt;li>假設要加密的訊息為 $M = 1$。&lt;/li>
&lt;li>訊息的位移量：$\lfloor \frac{q}{2} \rfloor = \lfloor \frac{17}{2} \rfloor = 8$&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>【1. 金鑰生成階段】&lt;/strong>
鮑伯隨機選取私鑰 $\mathbf{s}$、矩陣 $A$ 以及誤差向量 $\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>接著計算公鑰 $\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>
將其對 17 取模。($66 = 17 \times 3 + 15$ 等)
&lt;/p>
$$ A \mathbf{s} \pmod{17} = \begin{pmatrix} 15 \\ 1 \\ 11 \\ 16 \end{pmatrix} $$
&lt;p>
加上誤差向量 $\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>公鑰為 $A$ 與 $\mathbf{b} = (16, 0, 11, 1)^T$。&lt;/p>
&lt;p>&lt;strong>【2. 加密階段】&lt;/strong>
愛麗絲加密訊息 $M = 1$。
選取一個隨機向量 $\mathbf{r}$。這裡假設 $\mathbf{r} = (1, 0, 1, 0)^T$。&lt;/p>
&lt;p>計算 $\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>計算 $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>
加上對應於訊息 $M=1$ 的值 $\lfloor 17/2 \rfloor = 8$。
&lt;/p>
$$ v = \mathbf{b}^T \mathbf{r} + M \cdot 8 = 10 + 1 \times 8 = 18 \equiv 1 \pmod{17} $$
&lt;p>愛麗絲將密文 $(\mathbf{u}, v) = \left( \begin{pmatrix} 16 \\ 3 \end{pmatrix}, 1 \right)$ 傳送給鮑伯。&lt;/p>
&lt;p>&lt;strong>【3. 解密階段】&lt;/strong>
收到密文的鮑伯，使用私鑰 $\mathbf{s} = (3, 4)^T$ 進行解密。
計算解密處理公式： $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>在這裡，在模 17 的世界中，$-8$ 等於 $9$（$-8 + 17 = 9$）。
判斷得到的值 $D = 9$ 是比較接近 $0$ 還是 $8$（$\lfloor 17/2 \rfloor$）。
因為 $9$ 明顯比接近 $0$ 更接近 $8$，所以鮑伯正確地還原出了 $M = 1$！&lt;/p>
&lt;p>為什麼會變成 $9$ 呢？讓我們回想一下先前的證明。
誤差部分為 $\mathbf{e}^T \mathbf{r} = (1, -1, 0, 2) (1, 0, 1, 0)^T = 1 \times 1 + 0 \times 1 = 1$。
因此，計算結果會是 $\mathbf{e}^T \mathbf{r} + M \cdot 8 = 1 + 8 = 9$，證實了算出來的值符合理論預期。&lt;/p>
&lt;h1 id="7-邁向實用化的演進ring-lwe-與-module-lwe">7. 邁向實用化的演進：Ring-LWE 與 Module-LWE
&lt;/h1>&lt;p>我們到目前為止所說明的標準 LWE 問題（Standard LWE），雖然擁有非常強大的安全性證明，但在實際應用上卻有一個致命的弱點。那就是「金鑰的容量會變得十分巨大」以及「計算成本過高」。&lt;/p>
&lt;p>在 Standard LWE 中，公鑰包含了一個巨大的矩陣 $A \in \mathbb{Z}_q^{m \times n}$。當參數 $n$ 達到數百至數千時，這個矩陣的容量會達到數百萬位元組（MB）之多，要在網際網路通訊協定（如 TLS）中每次傳送和接收的話，負擔會太重。此外，矩陣與向量的乘法運算會花費 $\mathcal{O}(n^2)$ 的計算量。&lt;/p>
&lt;p>為了解決這個問題而導入的，是將名為多項式環（Polynomial rings）的代數結構結合到格子上的「Ring-LWE（RLWE）」以及「Module-LWE（MLWE）」。&lt;/p>
&lt;h2 id="71-ring-lwe-的直觀">7.1 Ring-LWE 的直觀
&lt;/h2>&lt;p>在 Ring-LWE 中，我們將向量與矩陣替換成多項式環 $\mathcal{R}_q = \mathbb{Z}_q[X]/(X^n + 1)$ 上的元素（多項式）。（這裡的 $n$ 會選擇 2 的次方數）。&lt;/p>
&lt;p>相對於 Standard LWE 的公鑰是矩陣 $A$，Ring-LWE 則是使用單一的多項式 $a(x)$。私鑰 $s(x)$ 與誤差 $e(x)$ 也都會變成多項式。
方程式會變成如下所示：
&lt;/p>
$$ b(x) = a(x) \cdot s(x) + e(x) \pmod q $$
&lt;p>因為這是多項式的乘法，所以可以透過使用類似於快速傅立葉變換（FFT）的「數論轉換（Number Theoretic Transform: NTT）」，將計算量大幅縮減至 $\mathcal{O}(n \log n)$。此外，因為公鑰的容量也從矩陣縮減成了單一多項式，所以資料大小減少到了 $\mathcal{O}(n)$。這在通訊頻寬上帶來了壓倒性的優勢。&lt;/p>
&lt;p>從數學角度來看，Ring-LWE 解決的不再是一般的格子，而是歸約到具有特殊對稱性，被稱為「理想格子（Ideal Lattice）」上的問題。&lt;/p>
&lt;h2 id="72-module-lwe-與-nist-的標準化kyber--ml-kem">7.2 Module-LWE 與 NIST 的標準化（Kyber / ML-KEM）
&lt;/h2>&lt;p>Ring-LWE 雖然效率很高，但卻也令人擔心理想格子特殊的代數結構會不會成為未來攻擊的突破口。因此，擷取 Standard LWE 的保守安全性以及 Ring-LWE 效率的「兩全其美」方案，就是「Module-LWE（MLWE）」。&lt;/p>
&lt;p>在 Module-LWE 中，我們考慮的是以多項式為元素所構成的小型矩陣和向量。也就是說，處理的是環上的模組（Module，加群）。
目前，被 NIST 選定作為 PQC 金鑰交換演算法（KEM）標準的「CRYSTALS-Kyber」（標準化名稱：ML-KEM），正是建構在這個 Module-LWE 問題的困難度之上。&lt;/p>
&lt;h1 id="8-為什麼對量子電腦是安全的">8. 為什麼對量子電腦是安全的？
&lt;/h1>&lt;p>最後，我們來探討一個核心問題：「為什麼格子密碼學被認為即使使用量子電腦也無法破解？」&lt;/p>
&lt;p>量子電腦用來破解 RSA 密碼與橢圓曲線密碼的秀爾演算法，本質上是一個用於解決「隱含子群問題（Hidden Subgroup Problem: HSP）」的演算法。RSA 或 ECC 背後的數學結構（有限阿貝爾群）具有週期性，透過使用名為量子傅立葉變換（QFT）的量子演算法特有操作，可以一次萃取出這個週期（隱含的子群）。&lt;/p>
&lt;p>然而，格子問題卻截然不同。格子雖然也有週期性，但在 SVP 或 CVP 中要求出的是「最短距離」或「消除雜訊」這種幾何學上的非線性性質。即使直接套用像秀爾演算法這種「阿貝爾群上的量子傅立葉變換」，也無法有效率地萃取出對解答格子問題有用的資訊。截至目前為止，尚未發現能在多項式時間內解決 SVP 或 LWE 的量子演算法，學界普遍相信，即使擁有量子電腦的平行計算能力，也只有類似於暴力破解的搜尋方式（透過葛羅夫演算法（Grover&amp;rsquo;s algorithm）達成的平方根加速程度）才是有效的手段。&lt;/p>
&lt;h1 id="9-總結">9. 總結
&lt;/h1>&lt;p>本文中，我們從格子的幾何定義開始，詳細地解說了格子密碼學的數學直觀，包括 LWE 問題的形式化，一直到公鑰密碼系統的建構。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>格子（Lattice）&lt;/strong> 是一個由基底向量以整數係數進行線性組合所表示的離散空間，在高維度下，要找到接近正交的「好基底」（SVP）將會變得困難。&lt;/li>
&lt;li>&lt;strong>LWE 問題（Learning With Errors）&lt;/strong> 是一個求解帶有雜訊的線性方程組的問題，因為這與格子在最壞情況下問題的困難度息息相關，所以能提供強大的安全性基礎。&lt;/li>
&lt;li>透過利用 LWE 問題，藉由刻意加入或消除雜訊的精妙機制，實現了加密與解密（&lt;strong>Regev 密碼&lt;/strong>）。&lt;/li>
&lt;li>在現實的協定中，為了提升通訊效率和計算速度，採用了使用多項式環的 &lt;strong>Ring-LWE&lt;/strong> 與 &lt;strong>Module-LWE&lt;/strong>，並成為了 NIST 標準 &lt;strong>ML-KEM&lt;/strong> 的基礎。&lt;/li>
&lt;/ol>
&lt;p>在量子電腦帶來前所未有的計算典範轉移之際，誕生於古典線性代數與數論深淵之中的「格子密碼學」，將肩負起未來網際網路安全基礎的重任，這是一件非常浪漫的事情。格子密碼學基礎的數學絕非過於艱澀難懂，只要具備線性代數與機率的基礎知識，就能充分理解其優美的結構。希望本文能幫助您理解作為 PQC 核心的格子密碼學。&lt;/p></description></item><item><title>黎曼猜想與質數分佈：與現代密碼學的深層關聯</title><link>http://kenji.blog/zh-tw/p/riemann-hypothesis-prime-distribution-cryptography/</link><pubDate>Fri, 11 Sep 2026 16:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/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 黎曼猜想與質數分佈：與現代密碼學的深層關聯" />&lt;h1 id="1-前言質數這宇宙之謎與黎曼猜想">1. 前言：質數這宇宙之謎與黎曼猜想
&lt;/h1>&lt;p>「質數（Prime Numbers）」是只能被1和自己整除的自然數，在數學世界中也被稱為「原子」。2, 3, 5, 7, 11, 13&amp;hellip; 這般延續的數列，乍看之下似乎毫無秩序、隨機出現。自從古希臘數學家歐幾里得證明了「質數有無窮多個」以來，無數的數學家們便不斷挑戰，試圖解開隱藏在這個質數排列中的規律。&lt;/p>
&lt;p>最逼近這個質數之謎的，是1859年由德國數學家波恩哈德·黎曼（Bernhard Riemann）所提出的**「黎曼猜想（Riemann Hypothesis）」**。黎曼猜想是現代數學中最重要且未解決的難題之一，被克雷數學研究所列為千禧年大獎難題之一，並懸賞了100萬美元的獎金。&lt;/p>
&lt;p>乍看之下，關於質數分佈的純數學難題，似乎與我們的日常生活毫無關聯。然而，支撐現代社會基礎設施的網際網路安全，特別是&lt;strong>RSA加密和橢圓曲線密碼學（ECC）等現代密碼技術&lt;/strong>，都深深依賴於巨大質數的性質。&lt;/p>
&lt;p>本篇文章將帶領讀者踏上一段數學之旅，從質數分佈、質數定理、黎曼ζ函數，一路探討到黎曼猜想的核心，並極為詳細且深入地解說它如何與現代密碼技術相結合，以及如果黎曼猜想被證明，世界將會發生什麼樣的變化。&lt;/p>
&lt;hr>
&lt;h1 id="2-質數定理與質數分佈高斯的發現">2. 質數定理與質數分佈：高斯的發現
&lt;/h1>&lt;p>為了解質數是如何分佈的，數學家們構想出了&lt;strong>質數計數函數（Prime-counting function）&lt;/strong> $\pi(x)$，用來表示「小於等於某個數 $x$ 的質數有多少個」。&lt;/p>
&lt;p>例如：&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>15歲的天才數學家卡爾·弗里德里希·高斯（Carl Friedrich Gauss）在計算了龐大的質數表後，發現質數的出現頻率與自然對數 $\ln x$ 成反比地遞減。也就是說，他猜想在某個數 $x$ 附近找到質數的機率大約是 $\frac{1}{\ln x}$。&lt;/p>
&lt;p>將這個猜想用積分來表現，就是&lt;strong>對數積分（Logarithmic integral）&lt;/strong> $\text{Li}(x)$：&lt;/p>
$$ \text{Li}(x) = \int_{2}^{x} \frac{dt}{\ln t} $$
&lt;p>高斯的猜想後來在1896年由雅克·阿達馬和夏爾-讓·德拉瓦萊·普桑各自獨立證明，並確立為&lt;strong>質數定理（Prime Number Theorem, PNT）&lt;/strong>。&lt;/p>
$$ \lim_{x \to \infty} \frac{\pi(x)}{\text{Li}(x)} = 1 $$
&lt;p>或者近似地表示如下：&lt;/p>
$$ \pi(x) \sim \frac{x}{\ln x} $$
&lt;p>透過這個定理，我們了解到從巨觀來看，質數具有非常平滑且可預測的分佈。然而，從微觀來看，$\pi(x)$ 和 $\text{Li}(x)$ 之間總是存在著「誤差」，也就是「波動」。這個波動的真面目，正是黎曼猜想所試圖解開的最大謎團。&lt;/p>
&lt;hr>
&lt;h1 id="3-黎曼ζ函數與歐拉乘積">3. 黎曼ζ函數與歐拉乘積
&lt;/h1>&lt;p>在解析質數分佈時，最強大的武器就是&lt;strong>黎曼ζ函數（Riemann Zeta Function）&lt;/strong>。這原本是由萊昂哈德·歐拉（Leonhard Euler）針對實數 $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>歐拉最大的貢獻之一，就是證明了這個無窮級數可以表示為所有質數 $p$ 的無窮乘積。這就是&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>這個證明的直觀理解是，將等式右邊的每一項展開為等比級數並將它們相乘，根據算術基本定理（每個自然數都可以唯一地表示為質數的乘積），等式左邊的自然數倒數和將會被完美地重構出來。&lt;/p>
&lt;p>&lt;strong>就這麼一個數學公式，成為了連結分析學（無窮級數・連續函數）與數論（質數・離散數）的橋樑。&lt;/strong> 研究ζ函數，就等同於研究質數的分佈。&lt;/p>
&lt;hr>
&lt;h1 id="4-解析延拓與複數平面的擴展">4. 解析延拓與複數平面的擴展
&lt;/h1>&lt;p>黎曼的天才之處在於，他將歐拉原本只在實數範圍內考慮的 $\zeta(s)$ 的變數 $s$，擴展到了&lt;strong>複數 $s = \sigma + it$（$\sigma$ 為實部，$t$ 為虛部）&lt;/strong>。&lt;/p>
&lt;p>原本的無窮級數只在 $\sigma > 1$ 時收斂，但黎曼使用了「解析延拓（Analytic Continuation）」的手法，將 $\zeta(s)$ 的定義擴展到除了極點 $s = 1$ 之外的整個複數平面上，使其具有意義。&lt;/p>
&lt;p>他更進一步導出了ζ函數所滿足的優美函數方程式（Functional equation）：&lt;/p>
$$ \zeta(s) = 2^s \pi^{s-1} \sin\left(\frac{\pi s}{2}\right) \Gamma(1-s) \zeta(1-s) $$
&lt;p>這裡的 $\Gamma(x)$ 是伽瑪函數。透過這個方程式，我們可以從右半平面的性質得知左半平面的性質。&lt;/p>
&lt;h3 id="零點zeros-of-the-zeta-function">零點（Zeros of the Zeta Function）
&lt;/h3>&lt;p>使ζ函數的值為 0 的複數 $s$ 被稱為「零點」。
由函數方程式可知，當 $s$ 為負偶數（$-2, -4, -6, \dots$）時，$\sin(\pi s / 2)$ 會變成 0，因此 $\zeta(s) = 0$。這些被稱為&lt;strong>平凡零點（Trivial zeros）&lt;/strong>。&lt;/p>
&lt;p>然而，在質數分佈中真正重要的，是除此之外的零點，也就是存在於 $0 \le \sigma \le 1$ 的「臨界帶（Critical strip）」內的&lt;strong>非平凡零點（Non-trivial zeros）&lt;/strong>。&lt;/p>
&lt;hr>
&lt;h1 id="5-黎曼猜想的核心與顯式公式">5. 黎曼猜想的核心與顯式公式
&lt;/h1>&lt;p>黎曼計算了少數幾個零點，並提出了一個令人驚嘆的猜想。這就是&lt;strong>黎曼猜想&lt;/strong>。&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>黎曼猜想 (Riemann Hypothesis)&lt;/strong>
黎曼ζ函數 $\zeta(s)$ 的所有非平凡零點，其實部都位於 $1/2$ 的直線上（$\text{Re}(s) = 1/2$）。&lt;/p>
&lt;/blockquote>
&lt;p>這條實部為1/2的直線被稱為「臨界線（Critical line）」。&lt;/p>
&lt;div class="mermaid">graph TD
A["黎曼ζ函數 ζ(s)"] --> B["透過解析延拓擴展至複數平面"]
B --> C["平凡零點 (s = -2, -4, -6 ...)"]
B --> D["非平凡零點 (0 &lt;= Re(s) &lt;= 1)"]
D --> E["黎曼猜想"]
E --> F["所有非平凡零點皆位於 Re(s) = 1/2 上"]
F --> G["通往質數分佈誤差項極限的證明"]&lt;/div>
&lt;p>為什麼黎曼猜想會如此重要呢？那是因為，ζ函數的零點&lt;strong>完全&lt;/strong>決定了質數的分佈。&lt;/p>
&lt;p>黎曼與後來的數學家馮·曼戈爾特，導出了一個能精確描述質數分佈的「顯式公式（Explicit formula）」。使用切比雪夫函數 $\psi(x)$，可以表示如下：&lt;/p>
$$ \psi(x) = x - \sum_{\rho} \frac{x^\rho}{\rho} - \ln(2\pi) - \frac{1}{2}\ln(1 - x^{-2}) $$
&lt;p>這裡的 $\rho$ 遍歷ζ函數的所有非平凡零點。
主項是 $x$（這對應於質數定理），從中加上或減去依賴於零點 $\rho$ 的波狀項，就能精確還原質數階梯狀的分佈。可以說，非平凡零點代表了質數分佈的「頻率（波）」。&lt;/p>
&lt;p>如果黎曼猜想是正確的，也就是所有非平凡零點 $\rho$ 的實部恰好都是 $1/2$，那麼質數定理的誤差項將會在理論上可預期的最小範圍內。&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>也就是說，&lt;strong>如果黎曼猜想為真，這將證明質數是以我們所能想像最「規律、優美」的方式分佈著。&lt;/strong>&lt;/p>
&lt;hr>
&lt;h1 id="6-現代密碼技術與質數不可分割的關係">6. 現代密碼技術與質數不可分割的關係
&lt;/h1>&lt;p>到目前為止，我們探討的是深奧的純數學世界，但這些質數的性質，卻從根本上支撐著現代數位社會。其代表性例子，便是以&lt;strong>RSA加密&lt;/strong>為首的公開金鑰密碼系統。&lt;/p>
&lt;p>網際網路上的信用卡支付、密碼傳輸、區塊鏈的數位簽章等，所有通訊的安全性都依賴於「質數」。&lt;/p>
&lt;h3 id="rsa加密的運作原理">RSA加密的運作原理
&lt;/h3>&lt;p>RSA加密的安全性，建立在「將位數極大的合成數進行質因數分解是非常困難的」這個數學事實（質因數分解問題）之上。&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>金鑰生成&lt;/strong>:
隨機選擇兩個巨大的質數 $p$ 和 $q$（例如各2048位元）。
將它們相乘計算出 $N = p \times q$。這個 $N$ 將成為公開金鑰的一部分。
利用歐拉函數 $\phi(N) = (p-1)(q-1)$，生成私鑰 $d$。&lt;/p>
$$ e \times d \equiv 1 \pmod{\phi(N)} $$
&lt;/li>
&lt;li>
&lt;p>&lt;strong>加密與解密&lt;/strong>:
明文 $M$ 使用公開金鑰 $e, N$ 轉換為密文 $C$。
&lt;/p>
$$ C \equiv M^e \pmod{N} $$
&lt;p>
只有擁有私鑰 $d$ 的人才能解密。
&lt;/p>
$$ M \equiv C^d \pmod{N} $$
&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph LR
A["明文 (Plaintext)"] --> B["使用公開金鑰(e, N)進行加密"]
B --> C["密文 (Ciphertext)"]
C --> D["使用私鑰(d)進行解密"]
D --> E["原始明文"]
F["攻擊者 (Attacker)"] -- "嘗試對N進行質因數分解" --> C
F -.-> G["若不知道p與q，則無法計算出d"]&lt;/div>
&lt;p>要破解RSA加密，就必須從巨大的 $N$ 中找出原本的質數 $p$ 和 $q$（進行質因數分解）。即使使用目前主流的演算法（如普通數域篩法：GNFS），要將數百位數的數字進行質因數分解，即使動用超級電腦，所花費的時間也被認為會遠遠超過宇宙的年齡。&lt;/p>
&lt;hr>
&lt;h1 id="7-黎曼猜想對密碼技術的影響">7. 黎曼猜想對密碼技術的影響
&lt;/h1>&lt;p>那麼，位居純數學頂點的「黎曼猜想」與「密碼技術」是如何產生交集的呢？&lt;/p>
&lt;h3 id="71-質數生成演算法質數判定與廣義黎曼猜想grh">7.1. 質數生成演算法（質數判定）與廣義黎曼猜想（GRH）
&lt;/h3>&lt;p>為了運用RSA加密，首先必須生成巨大的質數 $p$ 和 $q$。然而，要確切且高速地判定「某個數是否為質數」並不容易。&lt;/p>
&lt;p>目前實用上被廣泛使用的是&lt;strong>米勒-拉賓質數判定法（Miller-Rabin primality test）&lt;/strong>，這是一種機率性演算法。這個演算法速度很快，但有極低的機率會將合成數誤判為質數（稱為「偽質數」）。&lt;/p>
&lt;p>但是，如果假設將黎曼猜想擴展到狄利克雷L函數上的**「廣義黎曼猜想（Generalized Riemann Hypothesis, GRH）」&lt;strong>為真，情況就會發生戲劇性的變化。
若GRH為真，米勒-拉賓判定法的測試次數上限就能獲得數學上的保證，從機率性演算法&lt;/strong>昇華為「確定性多項式時間演算法」**（這是在AKS質數測試演算法被發現前就已知的重要事實）。&lt;/p>
&lt;p>也就是說，黎曼猜想（及其推廣）扮演著直接為「能否以絕對的自信且高速地生成巨大質數」這個密碼學基礎生成過程背書的角色。&lt;/p>
&lt;h3 id="72-與質因數分解演算法的關係">7.2. 與質因數分解演算法的關係
&lt;/h3>&lt;p>在評估破解密碼一方的演算法（如普通數域篩法等）的計算複雜度時，關於質數分佈的知識也是不可或缺的。許多質因數分解演算法依賴於「平滑數（Smooth numbers：只包含較小質因數的數字）」的分佈。&lt;/p>
&lt;p>為了嚴密評估平滑數出現的頻率，需要對質數分佈有深刻的理解，這裡也充分運用了直接關聯到ζ函數與黎曼猜想的解析數論技巧。如果黎曼猜想被證明，質數分佈的誤差被完全確定，我們就能更精確地看清質因數分解演算法的效能極限。&lt;/p>
&lt;hr>
&lt;h1 id="8-如果黎曼猜想被證明密碼會被破解嗎">8. 如果黎曼猜想被證明，密碼會被破解嗎？
&lt;/h1>&lt;p>雖然有如都市傳說般流傳著「如果黎曼猜想被解開，RSA加密就會在一瞬間瓦解」，但&lt;strong>這在數學上是不正確的&lt;/strong>。&lt;/p>
&lt;p>黎曼猜想的證明本身，並不會立刻孕育出能讓質因數分解戲劇性加速的魔法演算法。因為黎曼猜想終究是關於質數「巨觀分佈規律性」的定理，並不能直接告訴我們個別數字 $N$ 能被哪個質數整除（局部性質）。&lt;/p>
&lt;p>然而，這並不代表影響為零。
因為在證明黎曼猜想的過程中，&lt;strong>極有可能性會發現「新的數學工具」或「未知的解析手法」&lt;/strong>。回顧歷史，當費馬最後定理或龐加萊猜想被證明時，在此過程中發展出的新理論，都讓整個數學領域有了大幅度的飛躍。&lt;/p>
&lt;p>如果確立了能夠完全操作黎曼ζ函數零點性質的未知代數幾何手法，或是非交換幾何的手法，我們不能否認，這最終可能導致劃時代的質因數分解演算法（例如將計算複雜度降至多項式時間的古典演算法）被發現。就這個意義而言，密碼學家絕不能對黎曼猜想的動向掉以輕心。&lt;/p>
&lt;h3 id="量子電腦與秀爾演算法">量子電腦與秀爾演算法
&lt;/h3>&lt;p>對密碼技術而言，更直接、更具現實威脅的不是黎曼猜想的證明，而是&lt;strong>量子電腦&lt;/strong>。1994年彼得·秀爾（Peter Shor）發表的「秀爾演算法」證明了，只要擁有足夠效能的量子電腦，就能在多項式時間內解決質因數分解問題。這將導致RSA加密和橢圓曲線密碼學從根本上被破解。&lt;/p>
&lt;p>目前，世界各地正積極推進轉移至即使是量子電腦也無法解讀的「後量子密碼學（Post-Quantum Cryptography, PQC）」（如晶格密碼等）。依賴於質數的密碼技術，或許在某種意義上即將結束其黃金時代，但質數本身的數學價值，永遠不會消失。&lt;/p>
&lt;hr>
&lt;h1 id="9-結語數學的抽象性與現實社會的交會點">9. 結語：數學的抽象性與現實社會的交會點
&lt;/h1>&lt;div class="mermaid">graph TD
A["純數學的探索"] --> B["解明黎曼猜想"]
B --> C["完全理解質數分佈"]
C --> D["數論與代數幾何學的飛躍性發展"]
D -.-> E["全新質因數分解演算法的可能性"]
E -.-> F["密碼技術安全性評估的更新"]
A --> G["應用數學與電腦科學"]
G --> H["質數判定與密碼生成的效率化"]
H --> F&lt;/div>
&lt;p>從古希臘延續至今對質數無止盡的探索，被天才黎曼昇華為複數平面上一首優美的交響曲（ζ函數的零點）。而令人驚嘆的是，這純粹無瑕的數學結晶，在經過數個世紀後，竟被應用為確保網際網路社會安全的最強盾牌。&lt;/p>
&lt;p>黎曼猜想同時象徵了數學所具備的「抽象之美」與「對物理世界・現實社會驚人的適用力」。&lt;/p>
&lt;p>當這座至今無人登頂的巨大數學山峰有朝一日被征服時，我們不僅能完全理解質數這宇宙真理，更將對資訊化社會的基礎產生全新的觀點。學習密碼技術，就如同踏上一段追溯人類智慧歷史的旅程。&lt;/p></description></item><item><title>【數學解說】讓高中生也能看懂的RSA加密原理</title><link>http://kenji.blog/zh-tw/p/rsa-encryption-math-explained-for-beginners/</link><pubDate>Fri, 11 Sep 2026 13:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/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 【數學解說】讓高中生也能看懂的RSA加密原理" />&lt;p>互聯網社會安全的底層支柱技術之一就是「RSA加密」。線上購物的信用卡支付、與朋友在社群網路上的交流、公司機密資訊的收發等，我們每天不經意間使用的通訊，很多都是由RSA加密或其後續技術保護的。&lt;/p>
&lt;p>然而，一聽到「加密」，可能會聯想到間諜電影裡那種複雜的密碼機，或是只有少數天才才能理解的超高深數學。雖然現代密碼學確實建立在高等數學的基礎上，但&lt;strong>RSA加密的根本原理，只要具備高中數學（整數性質、質數、同餘等）的知識就足以理解&lt;/strong>。&lt;/p>
&lt;p>這篇文章將以高中數學知識為起點，逐步深入且徹底地解說RSA加密是基於什麼樣的數學原理運作的，以及為什麼它很難被破解。即使是不太擅長數學的人，我也會透過具體例子來淺顯易懂地解釋。&lt;/p>
&lt;hr>
&lt;h2 id="1-對稱密鑰加密與公鑰加密">1. 對稱密鑰加密與公鑰加密
&lt;/h2>&lt;p>在進入RSA加密的數學機制之前，我們先整理一下密碼學的基本概念。加密方式大致可分為「對稱密鑰加密」與「公鑰加密」兩種。&lt;/p>
&lt;h3 id="11-對稱密鑰加密方式的極限">1.1 對稱密鑰加密方式的極限
&lt;/h3>&lt;p>自古以來使用的加密方式，大多稱為「對稱密鑰加密方式」。這是一種&lt;strong>在「加密（將訊息轉換成秘密的密文）」與「解密（將密文還原成原本的訊息）」時使用相同密鑰&lt;/strong>的方式。&lt;/p>
&lt;p>例如，愛麗絲要寄一封秘密信件給鮑勃。愛麗絲用掛鎖（對稱密鑰）將信件鎖在箱子裡。鮑勃要打開那個箱子，就必須擁有與愛麗絲使用的同一把鑰匙。&lt;/p>
&lt;p>這種方式有一個很大的問題，就是「密鑰配送問題」。相隔兩地的愛麗絲與鮑勃在首次通訊時，該如何共享鑰匙而不被竊聽呢？如果在郵寄鑰匙的途中被第三者偷走，之後的加密通訊就會全部洩漏。&lt;/p>
&lt;h3 id="12-劃時代的發明公鑰加密方式">1.2 劃時代的發明「公鑰加密方式」
&lt;/h3>&lt;p>為了解決這個密鑰配送問題而發明出來的，就是「公鑰加密方式」。RSA加密也是其中一種。&lt;/p>
&lt;p>在公鑰加密方式中，會使用**「用來加密的密鑰（公鑰）」與「用來解密的密鑰（私鑰）」這兩把不同的鑰匙**。&lt;/p>
&lt;ol>
&lt;li>接收者鮑勃會建立一對「公鑰」與「私鑰」。&lt;/li>
&lt;li>鮑勃將「公鑰」公開給全世界（任何人都可以取得）。&lt;/li>
&lt;li>發送者愛麗絲使用鮑勃的「公鑰」來加密訊息並發送。&lt;/li>
&lt;li>加密後的訊息，只能用鮑勃獨有的「私鑰」來解密。&lt;/li>
&lt;/ol>
&lt;p>如果用掛鎖來比喻，鮑勃製作了許多「打開狀態的掛鎖（公鑰）」並散佈到全世界。愛麗絲將給鮑勃的訊息放入箱子，撿起鮑勃的掛鎖並將它鎖上。掛鎖一旦鎖上，就只有擁有「萬能鑰匙（私鑰）」的鮑勃才能打開。即使途中有人偷走了箱子，因為沒有萬能鑰匙，所以也打不開。&lt;/p>
&lt;div class="mermaid">graph TD
A["愛麗絲 (發送者)"] --> B["明文 (訊息)"]
B --> C["加密處理"]
D["鮑勃的公鑰 (任何人皆可取得)"] --> C
C --> E["透過網際網路發送: 密文"]
E --> F["解密處理"]
G["鮑勃的私鑰 (僅鮑勃擁有)"] --> F
F --> H["還原後的明文 (訊息)"]
H --> I["鮑勃 (接收者)"]&lt;/div>
&lt;p>要實現這種劃時代的系統，就需要一種**「單向函數（單向的數學謎題）」**，也就是「用公鑰很容易加密，但沒有私鑰就絕對無法解密」。而成為這個謎題零件的，正是我們熟知的「質數」。&lt;/p>
&lt;hr>
&lt;h2 id="2-支撐rsa加密的數學基礎1質數與質因數分解">2. 支撐RSA加密的數學基礎1：質數與質因數分解
&lt;/h2>&lt;p>RSA加密的安全性，建立在**「巨大數字的質因數分解非常困難」**這個數學事實上。&lt;/p>
&lt;h3 id="21-什麼是質數">2.1 什麼是質數
&lt;/h3>&lt;p>質數是指「除了1和自己本身之外，無法被其他數整除，且大於1的自然數」。
例如：$2, 3, 5, 7, 11, 13, 17, 19, 23...$&lt;/p>
&lt;p>質數就像是所有整數的「原子」。任何自然數都可以分解成質數相乘的形式。這稱為&lt;strong>質因數分解&lt;/strong>。例如 $60 = 2^2 \times 3 \times 5$，如果不考慮順序，就只有一種質因數分解的方法，這被稱為「算術基本定理」。&lt;/p>
&lt;h3 id="22-質因數分解的困難度單向函數">2.2 質因數分解的困難度（單向函數）
&lt;/h3>&lt;p>這裡的重點在於**「乘法很簡單，但質因數分解很困難」**這種不對稱性。&lt;/p>
&lt;p>例如，請試著心算以下兩個質數的乘法：
$11 \times 13 = ?$
這很簡單，答案是 $143$。&lt;/p>
&lt;p>那麼，這個數字呢？
請將 $323$ 進行質因數分解。
覺得如何？應該需要花一點時間。（答案是 $17 \times 19$）。&lt;/p>
&lt;p>如果數字很小，人類還能勉強算出來；但當數字變大時，即使使用電腦，計算難度也會呈現爆炸性成長。目前主流的RSA加密，會使用將兩個高達2048位元（十進位約600位數）、極其巨大的質數 $p$ 與 $q$ 相乘後的數字 $N = p \times q$。&lt;/p>
&lt;p>給定兩個巨大的質數 $p$ 和 $q$ 時，電腦瞬間（毫秒以下）就能計算出 $N$。但反過來，如果只給 $N$，要找出原本的 $p$ 和 $q$，即使讓現在最快的超級電腦運算幾兆年也解不出來。&lt;/p>
&lt;p>這種**「計算的不對稱性（去程簡單，回程困難）」**，就是創造出公鑰與私鑰關係的基礎。&lt;/p>
&lt;hr>
&lt;h2 id="3-支撐rsa加密的數學基礎2同餘模運算">3. 支撐RSA加密的數學基礎2：同餘（模運算）
&lt;/h2>&lt;p>RSA加密的計算，並不是我們平常用來讓數字無限變大的加法或乘法，而是在除以某個數的「餘數」世界中進行的。這稱為&lt;strong>同餘（模運算）&lt;/strong>。&lt;/p>
&lt;h3 id="31-時鐘的數學">3.1 時鐘的數學
&lt;/h3>&lt;p>模運算常被比喻為「時鐘的數學」。假設現在是10點，5小時後是幾點？ $10 + 5 = 15$ 點，但在一般的12小時制時鐘裡，我們會回答「3點」。這是因為15除以12的餘數是3。&lt;/p>
&lt;p>在數學的世界裡，我們會這樣表示：
&lt;/p>
$$ 15 \equiv 3 \pmod{12} $$
&lt;p>
讀作「15與3，在模12之下同餘（除以12的餘數相等）」。&lt;/p>
&lt;h3 id="32-同餘的基本性質">3.2 同餘的基本性質
&lt;/h3>&lt;p>同餘擁有與等式（$=$）非常相似且非常方便的性質。假設模（除數）為 $N$。
當 $a \equiv b \pmod N$ 且 $c \equiv d \pmod N$ 時，以下敘述成立：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>加法:&lt;/strong> $a + c \equiv b + d \pmod N$&lt;/li>
&lt;li>&lt;strong>減法:&lt;/strong> $a - c \equiv b - d \pmod N$&lt;/li>
&lt;li>&lt;strong>乘法:&lt;/strong> $a \times c \equiv b \times d \pmod N$&lt;/li>
&lt;li>&lt;strong>冪次方:&lt;/strong> $a^k \equiv b^k \pmod N$ （$k$ 為自然數）&lt;/li>
&lt;/ol>
&lt;p>其中特別重要的是「冪次方」的性質。這意味著**「餘數的次方，等於次方的餘數」**。
例如，我們想求 $7^{100}$ 除以 $5$ 的餘數。如果真的把 $7$ 乘100次再除以 $5$ 會非常辛苦；但如果使用同餘的性質，因為 $7 \equiv 2 \pmod 5$，所以 $7^{100} \equiv 2^{100} \pmod 5$，這能讓計算變得非常簡單。在密碼學的世界中，由於處理的是非常大數字的次方運算，這個性質是不可或缺的。&lt;/p>
&lt;hr>
&lt;h2 id="4-支撐rsa加密的數學基礎3歐拉函數與歐拉定理">4. 支撐RSA加密的數學基礎3：歐拉函數與歐拉定理
&lt;/h2>&lt;p>接下來就是RSA加密核心的數學魔法了。作為「費馬小定理」推廣的「歐拉定理」即將登場。&lt;/p>
&lt;h3 id="41-歐拉的總計函數-phin">4.1 歐拉的總計函數 $\phi(N)$
&lt;/h3>&lt;p>歐拉總計函數（$\phi$ 函數）是針對某個自然數 $N$，回傳**「從1到 $N$ 的自然數中，與 $N$ 互質（最大公因數為1）的數字個數」**的函數。&lt;/p>
&lt;p>我們來看幾個例子：&lt;/p>
&lt;ul>
&lt;li>$\phi(5)$：在1, 2, 3, 4, 5中，與5互質的有1, 2, 3, 4，共4個。因此 $\phi(5) = 4$。&lt;/li>
&lt;li>$\phi(6)$：在1, 2, 3, 4, 5, 6中，與6互質的有1, 5，共2個。因此 $\phi(6) = 2$。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>【質數時的特殊性質】&lt;/strong>
如果 $p$ 是質數，從 1 到 $p-1$ 的所有數字都會與 $p$ 互質。因此：
&lt;/p>
$$ \phi(p) = p - 1 $$
&lt;p>&lt;strong>【質數相乘時的特殊性質】&lt;/strong>
對於兩個不同的質數 $p$ 和 $q$，當 $N = p \times q$ 時，$\phi(N)$ 可以很容易地用以下公式計算：
&lt;/p>
$$ \phi(N) = \phi(p) \times \phi(q) = (p - 1)(q - 1) $$
&lt;p>
這個性質就是RSA加密中的「秘密後門（陷門函數）」。知道 $p$ 和 $q$ 的人（密鑰建立者）可以瞬間計算出 $\phi(N)$，但只知道 $N$ 的第三者，除非對 $N$ 進行質因數分解，否則無法求得 $\phi(N)$。&lt;/p>
&lt;h3 id="42-歐拉定理">4.2 歐拉定理
&lt;/h3>&lt;p>萊昂哈德·歐拉（Leonhard Euler）利用這個 $\phi(N)$，證明了以下優美的定理：&lt;/p>
&lt;p>&lt;strong>歐拉定理：&lt;/strong>
當整數 $a$ 與 $N$ 互質時，以下的同餘式成立：
&lt;/p>
$$ a^{\phi(N)} \equiv 1 \pmod N $$
&lt;p>這是一個驚人的性質：「將某個數字 $a$ 自乘 $\phi(N)$ 次後除以 $N$，餘數必定會是 $1$」。（當 $N$ 是質數 $p$ 時，公式為 $a^{p-1} \equiv 1 \pmod p$，這被稱為費馬小定理）。&lt;/p>
&lt;p>讓我們變形一下這個歐拉定理。兩邊再乘以 $a$：
&lt;/p>
$$ a^{\phi(N) + 1} \equiv a \pmod N $$
&lt;p>此外，對於任意整數 $k$，$a^{k \cdot \phi(N)}$ 也會是 $1^k = 1$，因此以下公式成立：
&lt;/p>
$$ a^{k \cdot \phi(N) + 1} \equiv a \pmod N $$
&lt;p>這個公式正是讓RSA加密中**「加密後再解密就能還原」**這種魔法得以成立的根本原理。&lt;/p>
&lt;hr>
&lt;h2 id="5-rsa加密的演算法密鑰生成加密解密的步驟">5. RSA加密的演算法：密鑰生成、加密、解密的步驟
&lt;/h2>&lt;p>基礎知識準備好後，我們終於要來看看RSA加密的具體步驟了。RSA加密主要分為「1. 密鑰生成」、「2. 加密」、「3. 解密」三個階段。&lt;/p>
&lt;div class="mermaid">flowchart TD
A1["1. 選擇質數 p, q"] --> A2["計算 N = p × q"]
A1 --> A3["計算 φ(N) = (p-1)(q-1)"]
A3 --> A4["選擇與 φ(N) 互質的 e"]
A3 --> A5["計算 d 使得 e × d ≡ 1 (mod φ(N))"]
A2 --> A6["公鑰 (N, e)"]
A4 --> A6
A5 --> A7["私鑰 d"]
B1["2. 明文訊息 M"] --> B2["計算 C ≡ M^e (mod N)"]
A6 -.-> B2
B2 --> B3["發送密文 C"]
B3 --> C1["3. 接收到的密文 C"]
C1 --> C2["計算 M ≡ C^d (mod N)"]
A7 -.-> C2
C2 --> C3["取得原本的明文訊息 M"]&lt;/div>
&lt;h3 id="51-密鑰生成key-generation">5.1 密鑰生成（Key Generation）
&lt;/h3>&lt;p>作為接收者的鮑勃，要為自己生成「公鑰」與「私鑰」。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>選擇質數:&lt;/strong> 隨機選擇兩個大質數 $p$ 和 $q$。&lt;/li>
&lt;li>&lt;strong>計算模 $N$:&lt;/strong> 計算 $N = p \times q$。這個 $N$ 會被公開。&lt;/li>
&lt;li>&lt;strong>計算 $\phi(N)$:&lt;/strong> 計算歐拉函數 $\phi(N) = (p - 1)(q - 1)$。這是只有鮑勃知道的秘密數字。&lt;/li>
&lt;li>&lt;strong>選擇公鑰 $e$:&lt;/strong> 選擇一個整數 $e$，滿足 $1 &lt; e &lt; \phi(N)$，且與 $\phi(N)$ 互質。&lt;/li>
&lt;li>&lt;strong>計算私鑰 $d$:&lt;/strong> 找出滿足以下條件的整數 $d$：
$$ e \times d \equiv 1 \pmod{\phi(N)} $$
也就是說，「找一個數字 $d$，使得 $e \times d$ 除以 $\phi(N)$ 的餘數為 $1$」。&lt;/li>
&lt;/ol>
&lt;p>這樣密鑰就準備完成了。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>公鑰:&lt;/strong> $(N, e)$ 的組合。公開給全世界。&lt;/li>
&lt;li>&lt;strong>私鑰:&lt;/strong> $d$。絕對不能告訴任何人。&lt;/li>
&lt;/ul>
&lt;h3 id="52-加密encryption">5.2 加密（Encryption）
&lt;/h3>&lt;p>假設愛麗絲想發送秘密訊息 $M$ 給鮑勃。（將 $M$ 視為文字數值化後的結果，且 $0 \le M &lt; N$）。愛麗絲會使用鮑勃的公鑰 $(N, e)$ 進行以下計算：&lt;/p>
$$ C \equiv M^e \pmod N $$
&lt;p>計算「將訊息 $M$ 的 $e$ 次方，除以 $N$ 的餘數 $C$」。這個 $C$ 就是密文。&lt;/p>
&lt;h3 id="53-解密decryption">5.3 解密（Decryption）
&lt;/h3>&lt;p>鮑勃接收到密文 $C$。鮑勃使用私鑰 $d$ 進行以下計算：&lt;/p>
$$ M \equiv C^d \pmod N $$
&lt;p>「將密文 $C$ 的 $d$ 次方，除以 $N$ 的餘數」，計算後竟然就能還原出原本的訊息 $M$！&lt;/p>
&lt;hr>
&lt;h2 id="6-為什麼解密後能還原數學證明">6. 為什麼解密後能還原？（數學證明）
&lt;/h2>&lt;p>你可能會覺得疑問：「只是把 $C$ 做了 $d$ 次方，為什麼就能還原成原本的 $M$ 呢？」這時，先前的「歐拉定理」就發揮威力了。&lt;/p>
&lt;p>我們把解密的計算式 $C^d \pmod N$ 中，代入加密的式子 $C = M^e$：
&lt;/p>
$$ C^d \equiv (M^e)^d \equiv M^{ed} \pmod N $$
&lt;p>回想一下密鑰生成的步驟5。鮑勃在製作 $d$ 時，選擇了讓 $e \times d \equiv 1 \pmod{\phi(N)}$ 的數字。這意味著「$ed$ 是 $\phi(N)$ 的倍數加 $1$」。我們可以用整數 $k$ 這樣寫：
&lt;/p>
$$ ed = k \cdot \phi(N) + 1 $$
&lt;p>將它代入指數部分，並利用指數律來分解：
&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>這裡假設訊息 $M$ 與 $N$ 互質，根據&lt;strong>歐拉定理&lt;/strong>，會有 $M^{\phi(N)} \equiv 1 \pmod N$。
&lt;/p>
$$ (M^{\phi(N)})^k \times M \equiv 1^k \times M \equiv M \pmod N $$
&lt;p>因此，完美地成立了以下公式：
&lt;/p>
$$ C^d \equiv M \pmod N $$
&lt;p>愛麗絲不知道 $d$，竊聽者也不知道 $d$，所以能從 $C$ 取出 $M$ 的，只有擁有 $d$ 的鮑勃。&lt;/p>
&lt;hr>
&lt;h2 id="7-具體例子用小質數手動計算體驗rsa">7. 具體例子：用小質數手動計算體驗RSA
&lt;/h2>&lt;p>讓我們實際用小數字（質數）來試試看愛麗絲給鮑勃的加密通訊。&lt;/p>
&lt;p>&lt;strong>【鮑勃的密鑰生成階段】&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>選擇兩個質數 $p=11$, $q=13$。&lt;/li>
&lt;li>計算 $N = 11 \times 13 = 143$。&lt;/li>
&lt;li>計算 $\phi(N) = (11 - 1) \times (13 - 1) = 10 \times 12 = 120$。&lt;/li>
&lt;li>選擇與 $\phi(N)=120$ 互質的公鑰 $e$。這裡我們選擇 $e=7$。&lt;/li>
&lt;li>求私鑰 $d$。尋找能讓 $7 \times d \equiv 1 \pmod{120}$ 的 $d$。
在方程式 $7d = 120k + 1$ 中，當 $k=6$ 時為 $721$，而 $721 \div 7 = 103$。
因此，$d = 103$。&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>公鑰：$(N=143, e=7)$&lt;/li>
&lt;li>私鑰：$d=103$&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>【愛麗絲的加密階段】&lt;/strong>
假設想發送的訊息 $M = 9$。
公式：$C \equiv 9^7 \pmod{143}$
$9^7 = 4,782,969$。把它除以 143，商為 $33447$ 餘數 $48$。
密文 $C = 48$。&lt;/p>
&lt;p>&lt;strong>【鮑勃的解密階段】&lt;/strong>
鮑勃收到密文 $C = 48$，使用私鑰 $d = 103$ 來解密。
公式：$M \equiv 48^{103} \pmod{143}$
在計算機中執行 &lt;code>(48 ** 103) % 143&lt;/code>，結果完美地出現「&lt;strong>9&lt;/strong>」！順利收到了原本的訊息。&lt;/p>
&lt;hr>
&lt;h2 id="8-私鑰-d-的求法擴展歐幾里得演算法">8. 私鑰 $d$ 的求法：擴展歐幾里得演算法
&lt;/h2>&lt;p>在手動計算的例子中，我們是靠直覺找 $k$ 才找出 $d=103$，但當數字高達幾百位數時，這種方法就行不通了。在實際的程式中，會使用**「擴展歐幾里得演算法」**。&lt;/p>
&lt;p>解開 $7d \equiv 1 \pmod{120}$，就等同於尋找滿足 $7d + 120y = 1$ 的整數 $d, y$。透過逆推歐幾里得演算法，就可以機械化地求出這個值。&lt;/p>
&lt;ol>
&lt;li>$120 \div 7 = 17$ 餘 $1$&lt;/li>
&lt;li>將其變形後為 $1 = 120 - 17 \times 7$&lt;/li>
&lt;li>也就是 $-17 \times 7 \equiv 1 \pmod{120}$&lt;/li>
&lt;/ol>
&lt;p>$-17$ 在模 $120$ 的世界裡，與 $120 - 17 = 103$ 意義相同。因此，瞬間就能求得 $d = 103$。無論多麼巨大的數字，用這個方法都能非常快速地計算出來。&lt;/p>
&lt;hr>
&lt;h2 id="9-rsa加密的另一面數位簽章">9. RSA加密的另一面：數位簽章
&lt;/h2>&lt;p>RSA加密最棒的一點在於，如果將公鑰和私鑰的角色反過來，還能當作**「數位簽章」**使用。&lt;/p>
&lt;p>加密時是「用公鑰加密 $\Rightarrow$ 用私鑰解密」，
但在數位簽章中，則會採取「用私鑰加密 $\Rightarrow$ 用公鑰解密」的步驟。&lt;/p>
&lt;div class="mermaid">flowchart TD
A1["1. 愛麗絲用私鑰建立簽章"] --> A2["S ≡ M^d (mod N)"]
A2 --> A3["發送訊息 M 與簽章 S"]
A3 --> B1["2. 鮑勃用公鑰驗證簽章"]
B1 --> B2["計算 M' ≡ S^e (mod N)"]
B2 --> B3["確認 M' 是否與 M 一致"]&lt;/div>
&lt;p>愛麗絲使用自己的私鑰 $d$ 來轉換訊息（這就是簽章 $S$），然後發送給鮑勃。鮑勃使用愛麗絲的公鑰 $e$ 來進行驗證計算。如果計算結果與原本的訊息一致，就能同時證明「這是只有愛麗絲的私鑰才能建立的資料」，以及「訊息在途中沒有被篡改」。&lt;/p>
&lt;hr>
&lt;h2 id="10-透過程式體驗rsa加密">10. 透過程式體驗RSA加密
&lt;/h2>&lt;p>手動計算很辛苦的次方運算，只要用Python就能非常簡單地實作出來。以下是能體驗RSA加密核心邏輯的Python程式碼。&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;求最大公因數&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;求私鑰 d（使用 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. 密鑰生成&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;公鑰: (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">), 私鑰: 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. 加密&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;密文: &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. 解密&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;解密後的訊息: &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的 &lt;code>pow(base, exp, mod)&lt;/code> 函數在內部使用了名為「反覆平方法（快速冪）」的高速演算法，因此即使是幾百位數的數字，也能瞬間完成計算。&lt;/p>
&lt;hr>
&lt;h2 id="11-總結與未來的密碼技術">11. 總結與未來的密碼技術
&lt;/h2>&lt;p>我們以高中數學知識為基礎，解開了RSA加密的原理。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>質因數分解的困難度:&lt;/strong> $p \times q = N$ 很簡單，但從 $N$ 找出 $p, q$ 非常困難。&lt;/li>
&lt;li>&lt;strong>同餘與歐拉定理:&lt;/strong> 根據 $a^{\phi(N)} \equiv 1 \pmod N$ 這個法則，完成了「用某個數做次方運算就能還原」的魔法陷門函數。&lt;/li>
&lt;li>&lt;strong>公鑰與私鑰:&lt;/strong> 任何人都能加密，但只有合法的接收者才能解密。&lt;/li>
&lt;/ol>
&lt;p>現在使用的RSA加密的 $N$ 有600位數以上，即使動用全世界的超級電腦，質因數分解所花的時間也會超過宇宙的年齡。然而，近年來研究不斷進展的「量子電腦」若在未來實用化，透過「秀爾演算法（Shor&amp;rsquo;s algorithm）」，這種質因數分解可能瞬間就被解開。因此，現在全世界都在加速開發連量子電腦也無法破解的「後量子密碼學（抗量子計算機密碼）」。&lt;/p>
&lt;p>常被認為「派不上用場」的高等數學，其實在底層保護著我們的日常生活。RSA加密就是能告訴我們數學有多深奧與優美的絕佳教材。希望透過這篇文章，能讓您稍微感受到密碼學與數學的有趣之處。&lt;/p></description></item><item><title>完全同態加密（FHE）是什麼？解析次世代資安的核心</title><link>http://kenji.blog/zh-tw/p/fully-homomorphic-encryption-fhe-explained/</link><pubDate>Fri, 11 Sep 2026 11:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/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 完全同態加密（FHE）是什麼？解析次世代資安的核心" />&lt;p>隨著雲端運算和 AI 技術逐漸成為社會的基礎，『資料隱私』與『資料活用』之間的權衡，已成為最重要的課題之一。越來越多的需求希望能在雲端上讓 AI 分析醫療數據、金融資訊、個人生物特徵等高機密性資料，但由於資安上的疑慮，許多企業對於將資料外傳感到猶豫。&lt;/p>
&lt;p>傳統的加密技術（如 AES 或 RSA 等）非常擅長保護儲存中的資料（Data at Rest）以及在網路上傳輸的資料（Data in Transit）。然而，當伺服器端要對資料進行搜尋或機器學習等&lt;strong>處理（計算）時（Data in Use），就必須先進行解密，將其還原為明文&lt;/strong>。如果在解密的這段期間伺服器遭到駭客攻擊，或是內部的惡意管理者偷窺資料，將直接導致資訊外洩。&lt;/p>
&lt;p>為了克服這種「處理時必須解密」的根本性弱點，有一項夢幻技術應運而生，那就是&lt;strong>完全同態加密（Fully Homomorphic Encryption: FHE）&lt;/strong>。只要使用 FHE，就能在維持資料加密的狀態下進行運算處理，而完全不需要解密，並且僅將計算結果的密文回傳給客戶端。&lt;/p>
&lt;p>本文將從 FHE 的概念與歷史、Craig Gentry 帶來的突破性進展、數學基礎（如 Ring-LWE 等）、其面臨的最大課題「雜訊」與解決方案（自舉，Bootstrapping），一路探討到最新的實作函式庫，為您深入且徹底地解析這項次世代資安的核心技術：FHE。&lt;/p>
&lt;hr>
&lt;h2 id="1-什麼是同態加密基本概念">1. 什麼是同態加密？基本概念
&lt;/h2>&lt;p>「同態（Homomorphic）」是代數學的術語，指在具有某種結構的集合之間，能夠在保持運算結構的情況下進行映射的性質。在密碼學理論中的「同態性」，則是指&lt;strong>在明文空間中的運算，可以對應到密文空間中的運算&lt;/strong>。&lt;/p>
&lt;p>用簡單的數學式來表示，假設對明文 $m_1$ 與 $m_2$ 的加密函數為 $E(\cdot)$，解密函數為 $D(\cdot)$。當明文上的運算（如加法或乘法等）為 $\circ$，而密文上的運算為 $\diamond$ 時，會成立以下關係：&lt;/p>
$$ D(E(m_1) \diamond E(m_2)) = m_1 \circ m_2 $$
&lt;p>也就是說，對密文 $E(m_1)$ 與 $E(m_2)$ 施以某種運算 $\diamond$ 後，將其結果解密，會與原本明文之間進行運算 $\circ$ 的結果完全一致。&lt;/p>
&lt;h3 id="雲端運算中的資料流程">雲端運算中的資料流程
&lt;/h3>&lt;p>使用 FHE 的雲端運算架構與傳統架構截然不同。下圖展示了運用 FHE 的安全資料處理流程。&lt;/p>
&lt;div class="mermaid">graph TD
A["客戶端（持有私鑰）"] -->|1. 將明文 x 加密: E(x)| B["雲端伺服器（僅有加密資料）"]
B -->|2. 在密文狀態下套用函數 f: E(f(x))| B
B -->|3. 計算結果的密文 E(y)| A
A -->|4. 使用私鑰解密: y = f(x)| A
style A fill:#d4edda,stroke:#28a745
style B fill:#f8d7da,stroke:#dc3545&lt;/div>
&lt;p>伺服器雖然接收了加密過後的資料 $E(x)$，但因為沒有私鑰，所以絕對無法知道資料的內容。然而，藉由利用 FHE 的性質，可以直接對密文套用函數 $f$（例如機器學習的推論模型），從而產生 $E(f(x))$。客戶端收到此結果後，使用自己的私鑰進行解密，即可獲得最終目標的結果 $y = f(x)$。&lt;/p>
&lt;hr>
&lt;h2 id="2-同態加密的進化歷史phe-she-fhe">2. 同態加密的進化歷史：PHE, SHE, FHE
&lt;/h2>&lt;p>同態加密並非一開始就達到了現在的「完全」型態。根據所能實現的運算種類與次數，它大致可分為三個階段。&lt;/p>
&lt;h3 id="partially-homomorphic-encryption-phe-部分同態加密">Partially Homomorphic Encryption (PHE: 部分同態加密)
&lt;/h3>&lt;p>PHE 是一種只能無限制地執行加法或乘法中&lt;strong>其中一種&lt;/strong>的加密方式。事實上，具備這種性質的加密技術自古便已存在。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>RSA 加密（對乘法的同態性）&lt;/strong>
RSA 加密在無意中具備了對乘法的同態性。若明文為 $m_1, m_2$，公鑰為 $(e, N)$：
$$ E(m_1) = m_1^e \pmod N $$
$$ E(m_2) = m_2^e \pmod N $$
將它們相乘可得：
$$ E(m_1) \times E(m_2) = (m_1 \cdot m_2)^e \pmod N = E(m_1 \times m_2) $$
像這樣，密文之間的相乘就對應到明文的相乘。&lt;/li>
&lt;li>&lt;strong>Paillier 加密（對加法的同態性）&lt;/strong>
於 1999 年發明的 Paillier 加密具備了對加法的同態性。它已被實際應用於電子投票（對加密的選票進行計票，最後只解密總結果）等領域。&lt;/li>
&lt;/ul>
&lt;h3 id="somewhat-homomorphic-encryption-she-淺度同態加密--具界同態加密">Somewhat Homomorphic Encryption (SHE: 淺度同態加密 / 具界同態加密)
&lt;/h3>&lt;p>雖然可以同時執行加法與乘法，但對於能運算的&lt;strong>次數（電路深度）有其限制&lt;/strong>的加密方式。由於後述的「雜訊」累積問題，只要乘法超過一定的次數，就會變得無法解密。2005 年的 BGN (Boneh-Goh-Nissim) 加密等皆屬此類，但要用來進行實用的複雜計算（如深度學習等）仍有極限。&lt;/p>
&lt;h3 id="fully-homomorphic-encryption-fhe-完全同態加密">Fully Homomorphic Encryption (FHE: 完全同態加密)
&lt;/h3>&lt;p>這是一種能夠&lt;strong>無限制次數&lt;/strong>地同時執行加法與乘法的加密方式。就像資訊理論中的圖靈完備性一樣，只要能無限次組合加法（相當於 XOR）與乘法（相當於 AND），就意味著原則上任何可計算的函數或演算法，都能在加密狀態下執行。&lt;/p>
&lt;p>FHE 長期以來被譽為「密碼學界的聖杯」，甚至曾被認為是不可能實現的。然而在 2009 年，當時還在史丹佛大學攻讀博士的 &lt;strong>Craig Gentry&lt;/strong>，提出了首個基於理想格（Ideal Lattices）的 FHE 方案，震驚了全世界。&lt;/p>
&lt;hr>
&lt;h2 id="3-fhe-的數學基礎lwe-問題與-ring-lwe">3. FHE 的數學基礎：LWE 問題與 Ring-LWE
&lt;/h2>&lt;p>目前主流的 FHE 方案中，有許多都是建構在「格密碼學（Lattice-based Cryptography）」（亦被稱為後量子密碼學，Post-Quantum Cryptography）中的一項數學難題上，也就是 &lt;strong>LWE (Learning With Errors) 問題&lt;/strong>。&lt;/p>
&lt;h3 id="lwe-問題的直觀理解">LWE 問題的直觀理解
&lt;/h3>&lt;p>只要使用高斯消去法等方法，解聯立一次方程式非常簡單。&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>然而，如果在這個方程式的結果中，加入極微小的「隨機誤差（雜訊）」$e$ 會發生什麼事呢？&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>只要加上這個誤差 $e$，要找出未知變數向量 $\vec{s}$ 的問題，就會變成即使使用現今的超級電腦或量子電腦都難以破解的 NP 困難問題。這就是 LWE 問題。&lt;/p>
&lt;h3 id="ring-lwe-問題rlwe">Ring-LWE 問題（RLWE）
&lt;/h3>&lt;p>標準的 LWE 問題因為包含矩陣運算，所以密鑰的容量非常大（甚至可能達到 Gigabyte 等級），並且有計算效率低落的問題。為了解決這個問題，於是導入了使用多項式環上運算的 &lt;strong>Ring-LWE (RLWE) 問題&lt;/strong>。&lt;/p>
&lt;p>在 RLWE 中，元素屬於多項式環 $R_q = \mathbb{Z}_q[x] / (x^N + 1)$（其中 $N$ 為 2 的冪次方，$q$ 為做為模數的質數）。
若將私鑰設為多項式 $s(x)$，並有隨機多項式 $a(x)$、微小的雜訊多項式 $e(x)$，則公鑰將會是以下的數對：&lt;/p>
$$ (a(x), b(x)) \quad \text{where} \quad b(x) = -a(x) \cdot s(x) + e(x) \pmod q $$
&lt;p>加密時，會利用這個多項式的性質來將明文 $m(x)$ 進行編碼，進而產生密文。&lt;/p>
&lt;hr>
&lt;h2 id="4-最大的障礙雜訊與-gentry-的自舉bootstrapping">4. 最大的障礙「雜訊」與 Gentry 的自舉（Bootstrapping）
&lt;/h2>&lt;p>在理解 FHE 時，最重要的概念就是**「雜訊的管理」**。&lt;/p>
&lt;p>在基於 LWE/RLWE 的加密演算法中，為了確保安全性，會刻意加入微小的「雜訊（誤差）」。
將明文 $m$ 的密文 $c$ 解密的過程，粗略來說可以用以下數學式表示。&lt;/p>
$$ D(c) = (c \cdot s) \pmod q = m + \text{noise} $$
&lt;p>解密時，可以透過捨入（rounding）等處理來消除這個 &lt;code>noise&lt;/code>，從而獲得正確的明文 $m$。然而，當我們在密文之間進行同態運算（特別是乘法）時，這個雜訊將會急遽放大。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>同態加法&lt;/strong>: 雜訊是以相加的方式增加（$e_1 + e_2$）。這種增長相對來說比較平緩。&lt;/li>
&lt;li>&lt;strong>用同態加法來表示的同態性數學式&lt;/strong>:
$$ E(m_1) \oplus E(m_2) = E(m_1 + m_2) $$&lt;/li>
&lt;li>&lt;strong>同態乘法&lt;/strong>: 雜訊會呈乘法級數爆發增長（因為包含了 $e_1 \times e_2$ 等）。只要進行幾次乘法，雜訊就會超過臨界值 $q/2$，導致無法進行正確的捨入處理而解密失敗。&lt;/li>
&lt;li>&lt;strong>用同態乘法來表示的同態性數學式&lt;/strong>:
$$ E(m_1) \otimes E(m_2) = E(m_1 \times m_2) $$&lt;/li>
&lt;/ul>
&lt;p>這就是為何長久以來 FHE 都無法實現，只能停留在 SHE（限制次數）的原因。&lt;/p>
&lt;h3 id="自舉bootstrapping的魔法">自舉（Bootstrapping）的魔法
&lt;/h3>&lt;p>Craig Gentry 天才般的貢獻，就是發明了被稱為**「自舉（Bootstrapping）」**的雜訊消除手法。這是密碼學界的一次典範轉移。&lt;/p>
&lt;p>直觀來說，這個操作就是「在密文因為充滿雜訊而損壞之前，在保持加密的狀態下進行『解密』以清理雜訊，然後重新放入新的密文之中」。&lt;/p>
&lt;ol>
&lt;li>假設有一個雜訊變得很大的密文 $C_{noisy}$。&lt;/li>
&lt;li>客戶端會將私鑰 $sk$ 事先「用公鑰加密」成 $E_{pk}(sk)$（這稱為 Bootstrapping key，自舉密鑰），並交給伺服器。&lt;/li>
&lt;li>伺服器針對 $C_{noisy}$，以同態的方式執行&lt;strong>解密電路（Decryption Circuit）&lt;/strong>。&lt;/li>
&lt;li>具體來說，就是針對 $E_{pk}(C_{noisy})$ 使用 $E_{pk}(sk)$ 來進行「在加密空間內的解密」。&lt;/li>
&lt;li>由於這個解密電路本身也是同態運算，因此會產生新的雜訊，但所輸出之新密文 $C_{fresh}$ 的雜訊，將被重設到一個固定的「恆定水準」。&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph LR
A["高雜訊密文 C_noisy"] --> B["同態解密電路 (Eval_Dec)"]
C["加密過的私鑰 E(sk)"] --> B
B --> D["低雜訊密文 C_fresh"]
style B fill:#ffeeba,stroke:#ffc107&lt;/div>
&lt;p>只要在計算過程中定期執行這種自舉操作，理論上就能計算無限深度的電路（達成 FHE）。然而，早期 Gentry 的方法，每次自舉處理都需要花費數十分鐘甚至數小時，計算成本高得令人絕望。&lt;/p>
&lt;hr>
&lt;h2 id="5-fhe-的世代與主要方案的進化">5. FHE 的世代與主要方案的進化
&lt;/h2>&lt;p>為了讓 FHE 得以實用化，世界各地的密碼學者爭相改良演算法。現在，FHE 主要分為四個世代或家族。&lt;/p>
&lt;h3 id="第-2-世代整數的精確運算-bgv-bfv">第 2 世代：整數的精確運算 (BGV, BFV)
&lt;/h3>&lt;p>於 2011 到 2012 年間登場的 &lt;strong>BGV (Brakerski-Gentry-Vaikuntanathan)&lt;/strong> 與 &lt;strong>BFV (Brakerski/Fan-Vercauteren)&lt;/strong> 方案。這些方案建立在 RLWE 的基礎上，非常適合整數的模數運算（精確計算）。
它們支援類似 SIMD (Single Instruction, Multiple Data) 的批次處理（Batching）技術，其特色是可以在一個巨大的多項式密文當中，塞入數千個資料槽，並一次進行平行運算。&lt;/p>
&lt;h3 id="第-3-世代自舉的加速化-gsw-fhew-tfhe">第 3 世代：自舉的加速化 (GSW, FHEW, TFHE)
&lt;/h3>&lt;p>2013 年的 &lt;strong>GSW (Gentry-Sahai-Waters)&lt;/strong> 方案簡化了 FHE 的結構。而將其進一步發展的，便是目前的主流之一 &lt;strong>TFHE (Fast Fully Homomorphic Encryption over the Torus)&lt;/strong>。
TFHE 的特色在於其自舉速度非常快（達毫秒等級）。它在邏輯閘層級（如 AND、XOR 等邏輯電路）的運算上非常強大，且密文的容量相對較小，因此適合用來高速評估任意的邏輯電路。&lt;/p>
&lt;h3 id="第-4-世代專精於近似計算與機器學習-ckks">第 4 世代：專精於近似計算與機器學習 (CKKS)
&lt;/h3>&lt;p>2017 年由 Cheon 等人所提出的 &lt;strong>CKKS (Cheon-Kim-Kim-Song)&lt;/strong> 方案，可說是目前 AI 與機器學習隱私保護領域的決定性技術。
相較於過去的 FHE 執著於「精確的整數計算」，CKKS 則支援在加密狀態下進行**「浮點數的近似計算」**。在神經網路的訓練或推論等容許微小誤差的實數計算上，它展現了壓倒性的效能。&lt;/p>
&lt;p>下表總結了如何根據不同目的來選擇方案。&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">方案名稱&lt;/th>
&lt;th style="text-align:left">擅長的資料型態&lt;/th>
&lt;th style="text-align:left">推薦的應用場景&lt;/th>
&lt;th style="text-align:left">特色&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">精確的統計計算、金融資料彙總、資料庫搜尋&lt;/td>
&lt;td style="text-align:left">藉由 SIMD 批次處理實現高吞吐量&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>CKKS&lt;/strong>&lt;/td>
&lt;td style="text-align:left">實數 (Real/Complex)&lt;/td>
&lt;td style="text-align:left">機器學習 (DNN、邏輯迴歸)、訊號處理&lt;/td>
&lt;td style="text-align:left">透過近似計算提升速度、重新縮放 (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">任意邏輯電路、字串搜尋、非線性函數評估&lt;/td>
&lt;td style="text-align:left">超高速的自舉（毫秒級別）&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="6-實踐fhe-函式庫與概念性程式碼">6. 實踐：FHE 函式庫與概念性程式碼
&lt;/h2>&lt;p>時至今日，已經有許多開源函式庫釋出，讓開發者不需要具備深厚的密碼學知識也能使用 FHE。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Microsoft SEAL (Simple Encrypted Arithmetic Library)&lt;/strong>: 支援 BFV、BGV、CKKS 的 C++ 函式庫，也是業界標準之一。其 Python 綁定版 &lt;strong>TenSEAL&lt;/strong> 在 AI 工程師之間廣受歡迎。&lt;/li>
&lt;li>&lt;strong>Zama (Concrete)&lt;/strong>: 基於 TFHE 的框架。可用 Rust/Python 編寫，並提供將現有的 PyTorch 模型編譯為在 FHE 上執行的功能（Concrete ML）。&lt;/li>
&lt;li>&lt;strong>OpenFHE&lt;/strong>: PALISADE 的後繼者，是一個支援所有主要方案的全面性 C++ 函式庫。&lt;/li>
&lt;/ul>
&lt;h3 id="使用-python-tenseal-的-fhe-程式設計範例">使用 Python (TenSEAL) 的 FHE 程式設計範例
&lt;/h3>&lt;p>這裡我們展示一段概念性的 Python 程式碼範例，它使用 CKKS 方案，在加密狀態下將實數向量相加與相乘。&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. 建立上下文 (包含金鑰生成)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 使用 CKKS 方案，並設定多項式的次數為 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"># 實數的縮放係數&lt;/span>
&lt;/span>&lt;/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. 客戶端：將資料加密&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"># 將明文向量轉換為密文 (實際上這會在客戶端執行)&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. 伺服器端：在維持加密的狀態下運算 (保護 Data in Use)&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="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. 客戶端：解密結果&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="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;解密後的加法結果: &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"># 輸出範例: [3.5000001, 5.5000001, 7.5000002] (因為是近似計算，所以會包含微小誤差)&lt;/span>
&lt;/span>&lt;/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;解密後的乘法結果: &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"># 輸出範例: [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>從上述的程式碼可以看出，我們能夠像 &lt;code>enc_v1 + enc_v2&lt;/code> 這樣，透過多載 (overload) 一般的 Python 運算子，直觀地撰寫密文之間的計算。而在伺服器端，不需要知道向量的內容也能完成向量運算。&lt;/p>
&lt;hr>
&lt;h2 id="7-fhe-的課題效能與硬體加速">7. FHE 的課題：效能與硬體加速
&lt;/h2>&lt;p>雖然 FHE 在理論上提供了完美的安全性，但實用化上的最大課題在於**「效能的負擔（Overhead）」**。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>計算的負擔&lt;/strong>: 與在明文下計算相比，密文下的計算在 CPU 上會慢了數千到數萬倍。多項式的乘法或自舉需要進行龐大的 FFT（快速傅立葉轉換）或 NTT（數論轉換）計算。&lt;/li>
&lt;li>&lt;strong>資料容量膨脹 (Ciphertext Expansion)&lt;/strong>: 只有幾個位元組的明文，在加密後可能會變成幾十 MB。這會對記憶體頻寬與網路頻寬造成巨大的壓力。&lt;/li>
&lt;/ol>
&lt;h3 id="透過硬體解決的方法">透過硬體解決的方法
&lt;/h3>&lt;p>為克服這種效能負擔，世界各地正積極開發專門針對 FHE 的硬體加速器（支援 ASIC、FPGA、GPU）。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>GPU 加速&lt;/strong>: 使用 NVIDIA 等強大的 GPU，以平行化處理 NTT 運算或自舉的技術正持續發展，已有報告指出比軟體實作快上數十倍（例如：100x.ai、Zama 的 TFHE-rs CUDA backend）。&lt;/li>
&lt;li>&lt;strong>DARPA DPRIVE 專案&lt;/strong>: 美國國防高等研究計劃署（DARPA）正在推動名為「DPRIVE (Data Protection in Virtual Environments)」的專屬硬體開發專案，目標是將 FHE 的計算速度提升至與明文處理相同的等級（負擔在 10 倍以內），參與者包括 Intel、Microsoft、Intellectual Ventures 等。&lt;/li>
&lt;li>&lt;strong>FPU (FHE Processing Unit) 的出現&lt;/strong>: Cornami 與 Optalysys 等新創公司，已經開始著手開發運用光學運算或特殊矽架構的 FHE 專用晶片。&lt;/li>
&lt;/ul>
&lt;p>或許在不久的將來，會像現在 AI 領域中的 NPU（神經網路處理器）一樣，迎來伺服器或雲端基礎架構將「FPU」列為標準配備的時代。&lt;/p>
&lt;hr>
&lt;h2 id="8-備受期待的應用場景">8. 備受期待的應用場景
&lt;/h2>&lt;p>隨著 FHE 逐漸達到具備實用性的速度，人們也期待它能在以下領域帶來破壞式的創新。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>醫療與基因解析的隱私保護&lt;/strong>:
在不違反隱私法規（如 HIPAA 或 GDPR）的情況下，能將多家醫院所擁有的病患病歷或 DNA 資料，在以 FHE 加密的狀態下交由雲端 AI 進行訓練，藉此建立出高準確度的癌症診斷模型或進行新藥開發。&lt;/li>
&lt;li>&lt;strong>金融機構的防詐欺與洗錢防制 (AML)&lt;/strong>:
互相競爭的銀行之間，可以在不公開客戶帳戶資訊或交易紀錄的情況下，以加密狀態比對彼此的資料，進行跨銀行的分析以偵測出龐大的非法匯款網路。&lt;/li>
&lt;li>&lt;strong>安全的 AI 推論 API (MaaS: Model as a Service)&lt;/strong>:
使用者可以將自己的聲音、臉部影像或提示詞加密後，再傳送給 AI 服務（如 ChatGPT 等 LLM）。AI 提供商能在完全不知道使用者輸入內容的情況下生成回答，並以密文形式傳回。這將徹底消除人們對於「個人資料會被 AI 學習或偷窺」的疑慮。&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="9-結論密碼學的未來將邁向看不見的計算">9. 結論：密碼學的未來將邁向「看不見的計算」
&lt;/h2>&lt;p>就像 1970 年代發明了公開金鑰加密（RSA）後，網際網路上的安全通訊（如 HTTPS 等）才得以實現一樣，Craig Gentry 發明 FHE 的創舉，同樣是密碼學歷史上最重要的里程碑之一。&lt;/p>
&lt;p>現在，完全同態加密（FHE）已走出實驗室的理論階段，並進入 Microsoft、IBM、Intel、Google 以及許多新創公司為了商業化而激烈競爭的階段。儘管計算成本與資料容量的課題依然存在，但隨著演算法的精進與硬體加速器的發展，其效能正以超越摩爾定律的速度持續提升中。&lt;/p>
&lt;p>幾年之後，「將資料加密並維持該狀態進行計算」將不再是什麼特別的事情，而是會成為雲端服務中保護資料的標準最佳實踐。FHE 正是在數據驅動的社會中，能夠實現&lt;strong>極致隱私與資料活用兼得&lt;/strong>的次世代資安核心技術。&lt;/p></description></item><item><title>橢圓曲線密碼學（ECC）的數學基礎與C++實作</title><link>http://kenji.blog/zh-tw/p/elliptic-curve-cryptography-math-cpp/</link><pubDate>Fri, 11 Sep 2026 10:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/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 橢圓曲線密碼學（ECC）的數學基礎與C++實作" />&lt;h1 id="橢圓曲線密碼學ecc的數學基礎與c實作">橢圓曲線密碼學（ECC）的數學基礎與C++實作
&lt;/h1>&lt;p>在現代密碼學中，**橢圓曲線密碼學（Elliptic Curve Cryptography: ECC）**扮演著極其重要的角色。從我們日常的網際網路通訊（HTTPS/TLS），到智慧型手機的安全隔離區（Secure Enclave）、SSH伺服器認證、FIDO等無密碼認證，甚至是比特幣和以太坊等加密資產，可以說現代數位社會的信任基礎都是由ECC所支撐的。&lt;/p>
&lt;p>本文將從橢圓曲線密碼學如何運作出發，深入探討其背後優美卻深奧的數學理論（有限體上的代數幾何），並介紹如何使用C++進行實際實作，甚至涵蓋如何防範旁路攻擊（計時攻擊）的安全程式設計方法，以壓倒性的篇幅為您徹底解析。&lt;/p>
&lt;hr>
&lt;h2 id="1-為什麼選擇橢圓曲線密碼學與rsa的比較">1. 為什麼選擇橢圓曲線密碼學？（與RSA的比較）
&lt;/h2>&lt;p>長期以來，公鑰密碼學的代名詞一直是&lt;strong>RSA密碼&lt;/strong>。RSA密碼的安全性建立在「大整數質因數分解的困難度」之上。然而，隨著電腦運算能力的提升，為了維持安全性，必須不斷增加RSA的金鑰長度（模數的位元數）。如今，建議的最低金鑰長度為2048位元，若要追求更高的安全性，則建議使用3072位元或4096位元。&lt;/p>
&lt;p>相對地，橢圓曲線密碼學（ECC）則以另一種數學難題——**「橢圓曲線上的離散對數問題（ECDLP）」**作為其安全性的基礎。直到現在，尚未發現能有效解決ECDLP的演算法（如次指數時間演算法），即使是目前已知最有效的攻擊方法，也需要指數級的時間。&lt;/p>
&lt;p>這個特性讓ECC擁有了一個決定性的優勢：&lt;strong>能以非常短的金鑰長度實現與RSA同等的安全強度&lt;/strong>。&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:center">安全強度（位元）&lt;/th>
&lt;th style="text-align:center">RSA密碼金鑰長度（位元）&lt;/th>
&lt;th style="text-align:center">橢圓曲線密碼金鑰長度（位元）&lt;/th>
&lt;th style="text-align:center">金鑰長度比例&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>如上表所示，為了達到128位元的安全強度（目前標準的強度），RSA需要3072位元的金鑰，而ECC只需要短短的256位元。這使得減少計算量、降低記憶體使用量、節省網路頻寬成為可能，特別是在資源受限的物聯網（IoT）設備或智慧卡環境中，展現出壓倒性的優勢。&lt;/p>
&lt;hr>
&lt;h2 id="2-數學準備群論與有限體的世界">2. 數學準備：群論與有限體的世界
&lt;/h2>&lt;p>要真正理解橢圓曲線密碼學，必須掌握抽象代數（群論與體論）的基本概念。在這裡，我們簡明扼要地總結建構ECC所需的預備知識。&lt;/p>
&lt;h3 id="21-群group與阿貝爾群">2.1. 群（Group）與阿貝爾群
&lt;/h3>&lt;p>**群（Group）**是指一個集合 $G$ 及其上的一種二元運算（此處以加法 $+$ 表示）所組成的結構 $(G, +)$，並且滿足以下四個公理：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>封閉性（Closure）&lt;/strong>: 對於任意 $a, b \in G$，$a + b \in G$。&lt;/li>
&lt;li>&lt;strong>結合律（Associativity）&lt;/strong>: 對於任意 $a, b, c \in G$，$(a + b) + c = a + (b + c)$ 成立。&lt;/li>
&lt;li>&lt;strong>單位元素的存在性（Identity element）&lt;/strong>: 存在一個元素 $e \in G$，使得對任意 $a \in G$，$a + e = e + a = a$。在加法群中，這個單位元素通常記為 $0$ 或 $\mathcal{O}$。&lt;/li>
&lt;li>&lt;strong>反元素的存在性（Inverse element）&lt;/strong>: 對於任意 $a \in G$，存在一個元素 $b \in G$ 使得 $a + b = b + a = e$。這個 $b$ 記為 $-a$。&lt;/li>
&lt;/ol>
&lt;p>此外，如果運算的順序對調也不會改變結果，也就是滿足以下條件的群，我們稱之為&lt;strong>阿貝爾群（交換群）&lt;/strong>：&lt;/p>
&lt;ol start="5">
&lt;li>&lt;strong>交換律（Commutativity）&lt;/strong>: 對於任意 $a, b \in G$，$a + b = b + a$ 成立。&lt;/li>
&lt;/ol>
&lt;p>橢圓曲線上的點的集合，透過定義特定的加法規則，便構成了一個&lt;strong>阿貝爾群&lt;/strong>。&lt;/p>
&lt;h3 id="22-有限體finite-field">2.2. 有限體（Finite Field）
&lt;/h3>&lt;p>在密碼學中，我們不使用像實數或複數那樣連續且具有無限元素的體，而是使用元素數量有限的**有限體（Finite Field）**或稱伽羅瓦體（Galois Field）。&lt;/p>
&lt;p>最基本的有限體是使用質數 $p$ 建構的&lt;strong>質數體 $\mathbb{F}_p$&lt;/strong>。這是在整數集合 $\{0, 1, 2, \dots, p-1\}$ 上定義模 $p$（除以 $p$ 的餘數）的四則運算（加、減、乘、除）。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>加法&lt;/strong>: $(a + b) \pmod p$&lt;/li>
&lt;li>&lt;strong>減法&lt;/strong>: $(a - b) \pmod p$&lt;/li>
&lt;li>&lt;strong>乘法&lt;/strong>: $(a \times b) \pmod p$&lt;/li>
&lt;li>&lt;strong>除法&lt;/strong>: $a \times b^{-1} \pmod p$ （這裡 $b^{-1}$ 是 $b$ 在模 $p$ 下的乘法反元素）&lt;/li>
&lt;/ul>
&lt;p>**乘法反元素（Modular Multiplicative Inverse）**的計算在密碼學實作中非常重要。要找到滿足 $b \times b^{-1} \equiv 1 \pmod p$ 的 $b^{-1}$，主要使用以下兩種演算法：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>擴展歐幾里得演算法（Extended Euclidean Algorithm）&lt;/strong>: 速度快，但根據實作方式，處理時間可能會依賴於輸入值，從而存在計時攻擊的風險。&lt;/li>
&lt;li>&lt;strong>費馬小定理（Fermat&amp;rsquo;s Little Theorem）&lt;/strong>: 當 $p$ 為質數且 $b \neq 0$ 時，$b^{p-1} \equiv 1 \pmod p$ 成立。兩邊同除以 $b$，可得 $b^{p-2} \equiv b^{-1} \pmod p$。也就是說，透過計算 $b$ 的 $p-2$ 次方即可求得反元素。因為指數運算較容易以常數時間（Constant-time）實作，密碼學實作中通常偏好此方法。&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="3-橢圓曲線方程式與幾何學">3. 橢圓曲線方程式與幾何學
&lt;/h2>&lt;h3 id="31-魏爾斯特拉斯標準式">3.1. 魏爾斯特拉斯標準式
&lt;/h3>&lt;p>**橢圓曲線（Elliptic Curve）&lt;strong>通常是指由以下被稱為&lt;/strong>魏爾斯特拉斯標準式（Weierstrass normal form）**的方程式所定義的平面曲線：&lt;/p>
$$ y^2 = x^3 + ax + b $$
&lt;p>其中，$a$ 和 $b$ 為常數，為了讓曲線不具有奇異點（自我交叉或尖點），也就是維持曲線的光滑性，必須滿足以下&lt;strong>判別式（Discriminant） $\Delta$&lt;/strong> 不為零的條件：&lt;/p>
$$ \Delta = -16(4a^3 + 27b^2) \neq 0 $$
&lt;p>具有奇異點的曲線會損害密碼學上的安全性，因此務必選擇滿足此條件的係數 $a, b$。&lt;/p>
&lt;h3 id="32-無窮遠點point-at-infinity">3.2. 無窮遠點（Point at Infinity）
&lt;/h3>&lt;p>為了讓橢圓曲線在數學上成為一個完美的群，除了平面上的點之外，還引入了一個虛擬的點，稱為**「無窮遠點（Point at Infinity）」**。我們將其記為 $\mathcal{O}$。&lt;/p>
&lt;p>無窮遠點 $\mathcal{O}$ 被定義為所有垂直線在無限遠處相交的點。在群論中，這個無窮遠點 $\mathcal{O}$ 扮演著&lt;strong>加法單位元素&lt;/strong>（零）的角色。&lt;/p>
&lt;p>也就是說，對於曲線上的任意點 $P$，以下等式成立：
&lt;/p>
$$ P + \mathcal{O} = \mathcal{O} + P = P $$
&lt;p>此外，點 $P = (x, y)$ 的反元素 $-P$ 被定義為與x軸對稱的點 $(x, -y)$。因此：
&lt;/p>
$$ P + (-P) = \mathcal{O} $$
&lt;p>
成立。&lt;/p>
&lt;hr>
&lt;h2 id="4-橢圓曲線上的群運算點的加法與二倍運算">4. 橢圓曲線上的群運算（點的加法與二倍運算）
&lt;/h2>&lt;p>構成橢圓曲線密碼學核心的，是曲線上點與點之間的**「加法（Addition）」**運算。這與一般的整數加法不同，它是基於幾何操作所定義的。&lt;/p>
&lt;h3 id="41-幾何加法tangent-and-chord-method">4.1. 幾何加法（Tangent and Chord Method）
&lt;/h3>&lt;p>將曲線上兩個不同的點 $P$ 和 $Q$ 相加，求得新點 $R$ ($R = P + Q$) 的步驟如下：&lt;/p>
&lt;ol>
&lt;li>畫一條連接點 $P$ 和點 $Q$ 的直線（割線）。&lt;/li>
&lt;li>這條直線必然會與橢圓曲線交於另一個點（我們稱之為 $-R$）。（※根據代數幾何定理）&lt;/li>
&lt;li>將交點 $-R$ 沿x軸對稱翻轉（即改變y座標的符號），得到的點即為所求的 $R$ 點。&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph TD
Step1["畫一條連接 P(x1, y1) 和 Q(x2, y2) 的直線"] --> Step2["找到與曲線的第三個交點 -R"]
Step2 --> Step3["將 -R 沿 x 軸翻轉，得到 R(x3, y3)"]
Step3 -.-> Result["這就是 R = P + Q"]&lt;/div>
&lt;h3 id="42-點的二倍運算point-doubling">4.2. 點的二倍運算（Point Doubling）
&lt;/h3>&lt;p>當我們要將點 $P$ 加上其自身（$P + P = 2P$）時，無法畫出一條穿過兩個相異點的直線。此時，我們改為畫出&lt;strong>曲線在點 $P$ 處的切線（Tangent）&lt;/strong>。&lt;/p>
&lt;ol>
&lt;li>畫出曲線在點 $P$ 處的切線。&lt;/li>
&lt;li>這條切線會與曲線交於另一個點 $-R$。&lt;/li>
&lt;li>將此交點沿x軸對稱翻轉，得到的點即為所求的 $R = 2P$。&lt;/li>
&lt;/ol>
&lt;h3 id="43-代數計算公式">4.3. 代數計算公式
&lt;/h3>&lt;p>我們可以將上述的幾何操作轉換為代數公式，以便讓電腦進行計算。
所有的運算都是在**有限體 $\mathbb{F}_p$ 上（模 $p$）**進行的。&lt;/p>
&lt;p>設點 $P = (x_1, y_1)$，點 $Q = (x_2, y_2)$。
並設計算結果的點為 $R = P + Q = (x_3, y_3)$。&lt;/p>
&lt;p>設直線的斜率為 $\lambda$（Lambda）。&lt;/p>
&lt;p>&lt;strong>【情況1：當 $P \neq Q$ 時（點的加法）】&lt;/strong>
斜率 $\lambda$ 是兩點間的變化率。
&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>使用這個 $\lambda$，我們可以如下求出 $x_3, y_3$：
&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>【情況2：當 $P = Q$ 時（點的二倍運算）】&lt;/strong>
斜率 $\lambda$ 會變成透過微分求得的切線斜率。（隱函數微分 $y^2 = x^3 + ax + b$）
&lt;/p>
$$ 2y \cdot y' = 3x^2 + a \implies y' = \frac{3x^2 + a}{2y} $$
&lt;p>
因此，
&lt;/p>
$$ \lambda \equiv (3x_1^2 + a) \cdot (2y_1)^{-1} \pmod p $$
&lt;p>$x_3, y_3$ 的公式與加法的形式相同，但因為 $x_2 = x_1$，所以變成如下形式：
&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]
這些公式包含了 $(x_2 - x_1)^{-1}$ 和 $(2y_1)^{-1}$ 等&lt;strong>除法（計算模反元素）&lt;/strong>。因為模反元素的計算成本極高，所以在實際實作中，通常會使用**「雅可比座標系（Jacobian Coordinates）」**等射影座標系來延遲除法的運算。&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h2 id="5-純量乘法與橢圓曲線離散對數問題ecdlp">5. 純量乘法與橢圓曲線離散對數問題（ECDLP）
&lt;/h2>&lt;p>在橢圓曲線密碼學中，計算量最大且構成安全核心的運算是&lt;strong>純量乘法（Scalar Multiplication）&lt;/strong>。&lt;/p>
&lt;h3 id="51-什麼是純量乘法">5.1. 什麼是純量乘法
&lt;/h3>&lt;p>將某個點 $P$ 連續相加 $k$ 次的操作稱為純量乘法，記為 $kP$。
&lt;/p>
$$ kP = \underbrace{P + P + \dots + P}_{k\text{次}} $$
&lt;p>這裡的 $k$ 是一個非常大的整數（例如256位元的整數）。&lt;/p>
&lt;h3 id="52-橢圓曲線離散對數問題ecdlp">5.2. 橢圓曲線離散對數問題（ECDLP）
&lt;/h3>&lt;p>橢圓曲線密碼學的安全性仰賴於以下問題的困難度：&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>橢圓曲線離散對數問題 (Elliptic Curve Discrete Logarithm Problem: ECDLP)&lt;/strong>
給定已知的點 $P$（基點）以及計算結果的點 $Q$，請求出滿足 $Q = kP$ 的純量 $k$。&lt;/p>
&lt;/blockquote>
&lt;p>從 $k$ 和 $P$ 計算出 $Q$（順向）利用後述的演算法非常簡單（多項式時間），但是從 $P$ 和 $Q$ 反推 $k$（逆向），除了暴力破解外，目前沒有高效的解法，實際上是不可能的（單向函數）。
在密碼協定中，&lt;strong>$k$ 對應「私鑰」，而 $Q$ 對應「公鑰」&lt;/strong>。&lt;/p>
&lt;h3 id="53-double-and-add-演算法">5.3. Double-and-Add 演算法
&lt;/h3>&lt;p>當 $k$ 是一個巨大數字（例如：$2^{256}$）時，單純將 $P$ 相加 $k$ 次，就算到了宇宙的盡頭也算不完。因此，為了快速進行純量乘法，我們會使用&lt;strong>Double-and-Add方法（二進位法）&lt;/strong>。&lt;/p>
&lt;p>這是快速計算整數冪的「重複平方法」的橢圓曲線版本。我們將純量 $k$ 表示為二進位數，並從最高位元開始依序處理。&lt;/p>
&lt;ol>
&lt;li>將保存結果的點 $R$ 初始化為 $\mathcal{O}$。&lt;/li>
&lt;li>從 $k$ 的最高位元到最低位元重複以下步驟：
&lt;ul>
&lt;li>將 $R$ 乘以 2（Point Doubling: $R = 2R$）&lt;/li>
&lt;li>如果當前位元為 &lt;code>1&lt;/code>，則將 $R$ 加上 $P$（Point Addition: $R = R + P$）&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>透過這個演算法，計算量從 $O(k)$ 劇烈減少到 $O(\log_2 k)$，使得在現實時間（毫秒級別）內完成計算成為可能。&lt;/p>
&lt;hr>
&lt;h2 id="6-橢圓曲線迪菲-赫爾曼ecdh金鑰交換">6. 橢圓曲線迪菲-赫爾曼（ECDH）金鑰交換
&lt;/h2>&lt;p>在此，我們將解說ECC最具代表性的應用例子——&lt;strong>ECDH（Elliptic Curve Diffie-Hellman）金鑰交換協定&lt;/strong>的運作原理。ECDH 是一種讓 Alice 和 Bob 在可能被竊聽的通訊通道上，安全地產生並共享共通私鑰（會話金鑰）的機制（這是TLS交握的核心）。&lt;/p>
&lt;p>&lt;strong>【前提參數（領域參數）】&lt;/strong>
雙方預先共享要使用的橢圓曲線 $E$、質數 $p$ 以及基點 $G$。（例如 NIST P-256 或 secp256k1 等）&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant Alice as "Alice (愛麗絲)"
participant Bob as "Bob (鮑勃)"
Note over Alice,Bob: "公開參數: 曲線 E, 基點 G, 質數 p"
Alice->>Alice: "產生私鑰 d_A (隨機整數)"
Alice->>Alice: "計算公鑰 Q_A = d_A * G"
Bob->>Bob: "產生私鑰 d_B (隨機整數)"
Bob->>Bob: "計算公鑰 Q_B = d_B * G"
Alice->>Bob: "發送公鑰 Q_A (明文)"
Bob->>Alice: "發送公鑰 Q_B (明文)"
Alice->>Alice: "計算共享秘密 S = d_A * Q_B"
Bob->>Bob: "計算共享秘密 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: "雙方的計算結果 S 完全一致！"&lt;/div>
&lt;p>竊聽者（Eve）雖然能攔截通訊路徑上的 $G$、$Q_A$、$Q_B$，但由於 ECDLP 的困難性，無法從 $Q_A = d_A \cdot G$ 推導出 Alice 的私鑰 $d_A$。此外，即使將 $Q_A$ 和 $Q_B$ 相乘，也不會得到共享金鑰 $S$，因此竊聽者無法計算出 $S$。&lt;/p>
&lt;hr>
&lt;h2 id="7-實作的陷阱旁路攻擊與對策">7. 實作的陷阱：旁路攻擊與對策
&lt;/h2>&lt;p>即使是理論上完美的密碼演算法，在將其編寫為程式的過程中，也可能產生漏洞。這就是**「旁路攻擊（Side-Channel Attack）」**。&lt;/p>
&lt;h3 id="71-計時攻擊timing-attack">7.1. 計時攻擊（Timing Attack）
&lt;/h3>&lt;p>讓我們回顧一下前面提到的 Double-and-Add 演算法。&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">// 脆弱的 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">// 總是會執行
&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">// 只有當位元為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>這個實作有一個致命的缺陷。因為當位元為 &lt;code>1&lt;/code> 時會執行 Point Addition，所以計算時間會比位元為 &lt;code>0&lt;/code> 時&lt;strong>稍微長一點&lt;/strong>。此外，處理器的分支預測和快取記憶體的行為也會改變。
攻擊者藉由統計觀察這微小的計算時間（或耗電量）差異數千次，就能&lt;strong>將私鑰 $k$ 的位元序列逐位元完全還原&lt;/strong>。這就是計時攻擊。&lt;/p>
&lt;h3 id="72-常數時間constant-time實作montgomery-ladder">7.2. 常數時間（Constant-Time）實作：Montgomery Ladder
&lt;/h3>&lt;p>為了防範計時攻擊，我們必須採用**無論私鑰位元值為何，執行的指令序列和計算時間都始終保持恆定（Constant-Time）**的演算法。&lt;/p>
&lt;p>最具代表性的例子就是&lt;strong>Montgomery Ladder（蒙哥馬利階梯）&lt;/strong>。&lt;/p>
&lt;div class="mermaid">graph TD
Start["初始化: R0 = O, R1 = P"] --> LoopStart["對於每個位元 i (從最高位起)"]
LoopStart --> Cond{"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["前往下一個位元"]
Branch1 --> LoopEnd
LoopEnd --> LoopStart
LoopStart -.->|"所有位元處理完畢"| End["結束: R0 即為結果 (kP)"]&lt;/div>
&lt;p>Montgomery Ladder的優美之處在於，無論位元是 &lt;code>0&lt;/code> 還是 &lt;code>1&lt;/code>，都**「始終會執行1次 Point Addition 和1次 Point Doubling」**。這徹底消除了計算時間的資料依賴性。&lt;/p>
&lt;p>然而，只要分支（&lt;code>if (k_i == 0)&lt;/code>）本身存在，編譯器的最佳化或 CPU 的分支預測仍可能帶來執行時間波動的風險。因此，在實際的常數時間實作中，我們會消除條件分支（&lt;code>if&lt;/code> 敘述），並使用&lt;strong>位元運算來進行條件式交換（Conditional Swap）&lt;/strong>。&lt;/p>
&lt;hr>
&lt;h2 id="8-使用c實作橢圓曲線密碼學">8. 使用C++實作橢圓曲線密碼學
&lt;/h2>&lt;p>從這裡開始，我們將把理論轉化為C++程式碼。實用的密碼學函式庫（如 OpenSSL 或 libsodium 等）採用了高度的組合語言最佳化和雅可比座標系，但在這裡，為了加深對數學的理解，我們將展示一個&lt;strong>使用仿射座標系（Affine Coordinates）、容易理解的常數時間實作&lt;/strong>架構。&lt;/p>
&lt;p>我們假設使用 &lt;code>boost::multiprecision::cpp_int&lt;/code> 來處理大整數運算。&lt;/p>
&lt;h3 id="81-模運算與反元素">8.1. 模運算與反元素
&lt;/h3>&lt;p>首先，定義有限體上運算的輔助函式。我們實作利用費馬小定理計算反元素的方法。&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">// 以 secp256k1 的質數 p 與參數為例
&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">// 回傳正餘數的模運算
&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">// 模冪運算 (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">// 使用費馬小定理計算模反元素
&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">// 假設 m 是質數: 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-點的表示與群運算加法二倍運算">8.2. 點的表示與群運算（加法、二倍運算）
&lt;/h3>&lt;p>我們將無窮遠點以旗標（flag）來管理，建立 &lt;code>Point&lt;/code> 結構體，並實作加法公式。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;/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">// 產生無窮遠點
&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">// 產生一般的點
&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">// 橢圓曲線上的點加法 (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) = 無窮遠點
&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 (當 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 (當 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-constant-time-conditional-swap-的實作">8.3. Constant-Time Conditional Swap 的實作
&lt;/h3>&lt;p>在根據私鑰位元值來交換變數內容時，我們不使用 &lt;code>if&lt;/code> 敘述，而是僅透過位元運算（遮罩）來進行交換。如此一來，執行路徑將保持絕對一致。&lt;/p>
&lt;blockquote>
&lt;p>[!TIP]
在實際的實作中，像 &lt;code>cpp_int&lt;/code> 這種動態配置記憶體的多倍長整數類別並不適合常數時間處理。因為記憶體配置或陣列大小的變動可能會洩漏時間資訊。在實用的函式庫中，通常會以固定長度（例如 uint64_t × 4個元素的陣列）來表示，並實作位元層級的遮罩處理。以下僅為概念性的範例。&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">// 概念性的常數時間交換 (假設為固定長度整數)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 如果 bit 為 1 則交換 P1 和 P2，若為 0 則不交換
&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 為 0 或 1。遮罩在 bit=1 時全為1 (0xFF..)，在 0 時全為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">// (這裡為了說明，假設固定長度的 BigInt 類別每個 word 為 w)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="cm">/*
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> uint64_t mask = 0 - (uint64_t)bit;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> for (int i = 0; i &amp;lt; NUM_WORDS; i++) {
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> uint64_t dummy = mask &amp;amp; (P1.x.words[i] ^ P2.x.words[i]);
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> P1.x.words[i] ^= dummy;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> P2.x.words[i] ^= dummy;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> // y座標與 isInfinity 旗標也同樣處理
&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">// ※ 在 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">// 在此僅以分支條件來模擬，幫助理解邏輯。
&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-使用-montgomery-ladder-進行純量乘法">8.4. 使用 Montgomery Ladder 進行純量乘法
&lt;/h3>&lt;p>結合前面的 &lt;code>pointAdd&lt;/code> 和 &lt;code>cswap&lt;/code>，我們來實作安全的純量乘法。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;/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">// 純量乘法 k * P (Montgomery Ladder 方式)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="nf">scalarMultiply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">k&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Point&lt;/span> &lt;span class="n">R0&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// 無窮遠點
&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">// 取得 k 的位元長度 (secp256k1 為 256 位元)
&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">// 取得第 i 個位元的值 (0 或 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">// 如果 bit == 1，則交換 R0 和 R1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cswap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">bit&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 始終執行相同的運算 (Point Addition 和 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">// 如果 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>透過這樣的實作邏輯，無論純量 $k$ 的各個位元是 &lt;code>0&lt;/code> 還是 &lt;code>1&lt;/code>，在每次迴圈疊代中執行的運算（&lt;code>cswap&lt;/code> $\to$ &lt;code>pointAdd&lt;/code> $\to$ &lt;code>pointAdd&lt;/code> $\to$ &lt;code>cswap&lt;/code>）都會完全相同，從而有效防止攻擊者透過計時或快取存取模式的差異來竊取機密資訊。&lt;/p>
&lt;hr>
&lt;h2 id="9-總結">9. 總結
&lt;/h2>&lt;p>初次接觸橢圓曲線密碼學（ECC）時，可能會對「為什麼畫一條直線並將交點翻轉這種幾何操作能成為密碼？」感到不可思議。然而，這正是將其映射到有限體這個離散世界後，所建構出完美的單向函數（離散對數問題），可說是數學與密碼學奇蹟般融合的產物。&lt;/p>
&lt;p>本文解說了以下幾個重點：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>對 RSA 的優勢&lt;/strong>: 能以極短的金鑰長度提供強大的安全性，是現代行動裝置與物聯網（IoT）時代的最佳選擇。&lt;/li>
&lt;li>&lt;strong>群論與有限體基礎&lt;/strong>: 構成 ECC 基礎的數學結構。&lt;/li>
&lt;li>&lt;strong>加法與二倍運算公式&lt;/strong>: 使用魏爾斯特拉斯方程式的代數群運算實作方法。&lt;/li>
&lt;li>&lt;strong>旁路攻擊的威脅&lt;/strong>: 依賴於私鑰位元的條件分支會造成致命的漏洞。&lt;/li>
&lt;li>&lt;strong>常數時間（Constant-Time）實作&lt;/strong>: 採用 Montgomery Ladder 和 Conditional Swap，使硬體層級的行為均勻化以防止攻擊的 C++ 程式設計技巧。&lt;/li>
&lt;/ol>
&lt;p>一般極不建議自行編寫應用於正式生產環境的密碼學函式庫（&amp;ldquo;Don&amp;rsquo;t roll your own crypto&amp;rdquo;），因為這伴隨著極高的安全風險。然而，對於設計和維護高安全性、高效能系統的工程師來說，深入了解其內部運作的演算法及數學背景，無疑是一項極其寶貴且強大的武器。&lt;/p>
&lt;p>在下一篇文章中，我們將進一步探討利用這條橢圓曲線所建立的數位簽章演算法——&lt;strong>ECDSA (Elliptic Curve Digital Signature Algorithm)&lt;/strong> 的機制，以及比特幣所採用的 &lt;strong>Schnorr 簽章&lt;/strong>。&lt;/p></description></item><item><title>超越 GNFS（一般數體篩法）的演算法存在嗎？</title><link>http://kenji.blog/zh-tw/p/beyond-gnfs-integer-factorization-algorithms/</link><pubDate>Fri, 11 Sep 2026 09:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/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 超越 GNFS（一般數體篩法）的演算法存在嗎？" />&lt;h2 id="1-簡介質因數分解與現代密碼學的基礎">1. 簡介：質因數分解與現代密碼學的基礎
&lt;/h2>&lt;p>現代社會中網際網路通訊的安全性，很大程度上仰賴於公開金鑰密碼系統（即 RSA 密碼）的安全性。而 RSA 密碼的安全性則是基於「巨大合成數質因數分解的困難度」這項數學假設。如果發現了極高效率的質因數分解演算法，全球的通訊基礎設施將會從根本上崩潰。&lt;/p>
&lt;p>目前，在使用古典電腦進行巨大整數質因數分解的領域中，最快速且最強大的演算法為&lt;strong>一般數體篩法（GNFS: General Number Field Sieve）&lt;/strong>。GNFS 是擴充了 1980 年代後半所提出的特殊數體篩法（SNFS）而誕生的，時至今日，它已經創下了 RSA-768 和 RSA-250 等巨大合成數質因數分解的紀錄。&lt;/p>
&lt;p>然而，密碼學家與數學家們始終抱持著以下疑問：「超越 GNFS 的古典演算法存在嗎？」「古典電腦的極限在哪裡？」以及「量子電腦將如何打破這個局面？」&lt;/p>
&lt;p>本文將徹底解剖 GNFS 背後深奧的數學結構，並針對多項式選擇、篩選處理、基於區塊魏德曼（Block Wiedemann）法的線性代數步驟等進行詳細的技術分析。此外，我們將探討藉由 Coppersmith 改良等對 GNFS 的擴充方法，並從數學的觀點比較與解說古典的次指數時間（Sub-exponential time）演算法與量子多項式時間演算法的決定性差異。&lt;/p>
&lt;hr>
&lt;h2 id="2-漸近複雜度與-l-符號l-notation">2. 漸近複雜度與 L 符號（L-notation）
&lt;/h2>&lt;p>在評估質因數分解演算法的計算複雜度時，通常不使用標準的多項式時間表示法（如 $O(n^k)$ 等），而是使用**L 符號（L-notation）**來表達相對於輸入 $n$ 之位數的次指數時間。L 符號定義如下：&lt;/p>
$$
L_n[\alpha, c] = \exp \left( (c + o(1)) (\ln n)^\alpha (\ln \ln n)^{1-\alpha} \right)
$$
&lt;p>這裡，$n$ 是質因數分解的目標整數，$\ln n$ 是自然對數，且與 $n$ 的位元長度成正比。&lt;/p>
&lt;ul>
&lt;li>當 $\alpha = 0$ 時：$L_n[0, c] = \exp(c \ln \ln n) = (\ln n)^c$，這表示相對於位元長度的&lt;strong>多項式時間（Polynomial time）&lt;/strong>。&lt;/li>
&lt;li>當 $\alpha = 1$ 時：$L_n[1, c] = \exp(c \ln n) = n^c$，這表示相對於位元長度的&lt;strong>指數時間（Exponential time）&lt;/strong>。&lt;/li>
&lt;li>當 $0 &lt; \alpha &lt; 1$ 時：這介於多項式時間與指數時間之間，稱為&lt;strong>次指數時間（Sub-exponential time）&lt;/strong>。&lt;/li>
&lt;/ul>
&lt;p>過去質因數分解演算法的演進，其實就是逐漸縮小這個 $\alpha$ 值的歷史。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>連分數法（CFRAC）或多重多項式二次篩法（MPQS）&lt;/strong>：屬於 $\alpha = 1/2$ 的類別，複雜度大約為 $L_n[1/2, 1]$。&lt;/li>
&lt;li>&lt;strong>一般數體篩法（GNFS）&lt;/strong>：達到了 $\alpha = 1/3$，這在目前已知的古典演算法中擁有最快的 $L_n[1/3, (64/9)^{1/3}]$ 複雜度。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="3-gnfs一般數體篩法的演算法全貌與數學結構">3. GNFS（一般數體篩法）的演算法全貌與數學結構
&lt;/h2>&lt;p>GNFS 擁有非常複雜且高度的數學基礎。其基本概念是費馬小定理和二次篩法（QS）的延伸，透過找到滿足同餘式 $X^2 \equiv Y^2 \pmod n$ 且 $X \not\equiv \pm Y \pmod n$ 的非平凡解 $(X, Y)$，進而導出 $n$ 的因數 $\gcd(X-Y, n)$。&lt;/p>
&lt;p>然而，GNFS 的精髓在於，它並非僅在有理數體 $\mathbb{Q}$ 上進行，而是同時在稱為代數數體（Algebraic Number Field）的擴充體 $\mathbb{Q}(\alpha)$ 及有理數體兩端探索「平滑數（Smooth numbers）」，並透過同態映射來建構同餘關係。&lt;/p>
&lt;p>GNFS 的過程大致可以分為 5 個階段。&lt;/p>
&lt;div class="mermaid">graph TD
A["質因數分解問題 (輸入 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["輸出質因數 p, q"]&lt;/div>
&lt;h3 id="31-階段-1多項式選擇-polynomial-selection">3.1 階段 1：多項式選擇 (Polynomial Selection)
&lt;/h3>&lt;p>GNFS 的成功很大程度上取決於選擇適當的多項式。目標是找到擁有共同根 $m$ 的兩個不可約多項式 $f_1(x)$（有理數側）與 $f_2(x)$（代數數側）。也就是說，
必須滿足 $f_1(m) \equiv f_2(m) \equiv 0 \pmod n$。&lt;/p>
&lt;p>通常，有理數側的多項式選擇一次式 $f_1(x) = x - m$，而代數數側的多項式 $f_2(x)$ 則選擇次數為 $d$（典型為 5 或 6）的首一多項式。最經典的方法是 &lt;strong>Base-$m$ 方法&lt;/strong>。
選擇接近 $n$ 的 $1/(d+1)$ 次方的整數 $m = \lfloor n^{1/(d+1)} \rfloor$，並將 $n$ 展開為 $m$ 進位。
$n = c_d m^d + c_{d-1} m^{d-1} + \dots + c_1 m + c_0$
藉此，可以獲得多項式 $f_2(x) = c_d x^d + c_{d-1} x^{d-1} + \dots + c_0$。很明顯地，$f_2(m) = n \equiv 0 \pmod n$。&lt;/p>
&lt;p>然而，現代的實作中會使用 &lt;strong>Kleinjung 的演算法&lt;/strong>。此方法在確保多項式係數不會變得極端巨大的同時（偏態/Skewness 的最佳化），還會最佳化代數性質（Murphy 的 $E$ 值或 $\alpha$ 值），以尋找容易在篩選處理中產生平滑數的多項式。僅僅是這個步驟就會投入龐大的運算資源。&lt;/p>
&lt;h3 id="32-階段-2篩選處理-sieving-phase">3.2 階段 2：篩選處理 (Sieving Phase)
&lt;/h3>&lt;p>當多項式決定後，就會進入演算法中運算負載最重的「篩選（Sieving）」階段。在這裡，我們要探索一對互質的數組 $(a, b)$，這對數組必須滿足以下兩個值同時為「平滑（Smooth）」：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>有理數側的範數&lt;/strong>: $F_1(a, b) = b \cdot f_1(a/b) = a - bm$&lt;/li>
&lt;li>&lt;strong>代數數側的範數&lt;/strong>: $F_2(a, b) = b^d \cdot f_2(a/b)$&lt;/li>
&lt;/ol>
&lt;p>「平滑」意味著該數字僅能被小於或等於指定上限（Sieve bound）的質數進行因數分解。準備好有理數側的質數基底（Factor base）與代數數側的質數基底，並在龐大的探索空間上，利用類似埃拉托斯特尼篩法的方式，高效率地找出平滑數。
目前主流是稱為**晶格篩法（Lattice Sieving）**的技術，藉由固定特定的質數 $q$，僅對有理數側與代數數側皆為 $q$ 的倍數的部分晶格上的 $(a, b)$ 數組進行篩選，從而實現了極高的效率。&lt;/p>
&lt;h3 id="33-階段-3濾波階段-filtering-phase">3.3 階段 3：濾波階段 (Filtering Phase)
&lt;/h3>&lt;p>在篩選處理中找到的平滑關係式（Relations）數量高達數億、甚至數十億。然而，這些也包含了許多無用的資訊。
濾波的目的，是在建構龐大的稀疏矩陣（Sparse Matrix）時，盡可能縮小其維度。&lt;/p>
&lt;p>具體來說，會進行以下操作：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Singleton removal&lt;/strong>: 刪除包含只出現 1 次質因數的關係式。&lt;/li>
&lt;li>&lt;strong>Clique removal / Merging&lt;/strong>: 將擁有出現 2 次以上質因數的關係式互相相乘，以消去變數，從而縮減成密度較高、但維度較小的方程式系統。&lt;/li>
&lt;/ul>
&lt;p>透過這個過程，數十億行的矩陣將會被壓縮成擁有數千萬行規模的巨大稀疏矩陣 $\mathbf{A}$（元素為體 $\mathbb{F}_2$ 上的 0 與 1）。&lt;/p>
&lt;h3 id="34-階段-4線性代數-linear-algebra-phase">3.4 階段 4：線性代數 (Linear Algebra Phase)
&lt;/h3>&lt;p>在這個階段中，要找到方程式 $\mathbf{A} \mathbf{x} \equiv \mathbf{0} \pmod 2$ 的非平凡解向量 $\mathbf{x}$。換句話說，這是一個求取巨大稀疏矩陣之左零空間（Left Nullspace）的問題。&lt;/p>
&lt;p>由於矩陣尺寸極端巨大，使用一般的高斯消去法（$O(N^3)$）根本無法計算。因此，會採用克雷洛夫子空間（Krylov subspace）方法的一種迭代法。歷史上曾使用過&lt;strong>區塊蘭佐斯法（Block Lanczos）&lt;/strong>，但在當前的分散式運算環境中，能大幅減少通訊額外開銷的**區塊魏德曼法（Block Wiedemann Algorithm）**才是主流。&lt;/p>
&lt;p>區塊魏德曼法會從矩陣 $\mathbf{A}$ 和向量序列中計算最小多項式，並利用貝利坎普-馬西（Berlekamp-Massey）演算法來建構零空間的基底。這個步驟非常難以平行化，且需要超級電腦或大規模叢集的緊密耦合通訊網路，是 GNFS 最大的瓶頸之一。&lt;/p>
&lt;h3 id="35-階段-5平方根-square-root-phase">3.5 階段 5：平方根 (Square Root Phase)
&lt;/h3>&lt;p>從線性代數的解中，將在有理數側與代數數側各自建構出成為「完全平方」的乘積。
在有理數側，$\prod (a-bm)$ 會成為某個整數 $X$ 的平方 $X^2$；而在代數數側，對應的理想的乘積會在代數數體上成為完全平方 $\gamma^2$。
藉由在代數數體上計算出這個 $\gamma$，並套用映射到有理整數環的同態映射 $\phi: \alpha \mapsto m \pmod n$，便可得到同餘式：
$X^2 \equiv \phi(\gamma)^2 \equiv Y^2 \pmod n$&lt;/p>
&lt;p>計算代數數體上的平方根需要使用如 **Montgomery 方法（Montgomery&amp;rsquo;s Method）**等複雜演算法，且需要深厚的代數數論知識。最後只要計算出 $\gcd(X-Y, n)$，若獲得非平凡的因數，便完成了質因數分解。&lt;/p>
&lt;hr>
&lt;h2 id="4-超越-gnfs-的古典演算法存在嗎">4. 超越 GNFS 的古典演算法存在嗎？
&lt;/h2>&lt;p>截至目前為止，在一般整數的質因數分解中，尚未發現漸近複雜度低於 $L_n[1/3, c]$ 的古典演算法。然而，為了突破理論上與實務上的極限，存在著一些嘗試與衍生的演算法。&lt;/p>
&lt;h3 id="41-多重數體篩法-mnfs-multiple-number-field-sieve">4.1 多重數體篩法 (MNFS: Multiple Number Field Sieve)
&lt;/h3>&lt;p>作為 GNFS 的擴充方法，有 D. Coppersmith 所提出的&lt;strong>多重數體篩法（MNFS）&lt;/strong>。GNFS 使用了 2 個多項式（有理數側與代數數側），而 MNFS 則是對 1 個有理數側多項式，同時使用多個不同的代數數側多項式。&lt;/p>
$$ f_1(x), f_{2,1}(x), f_{2,2}(x), \dots, f_{2,V}(x) $$
&lt;p>透過利用多個代數數體，可以在每個篩選步驟中，飛躍性地提高「在其中一個代數數體中變得平滑」的機率。Coppersmith 成功地藉由這種方法讓複雜度 $L_n[1/3, c]$ 中的常數 $c$ 些微減少。
具體來說，GNFS 的常數為 $c = (64/9)^{1/3} \approx 1.923$，而理論上已經證明透過最佳化 MNFS，可以將計算複雜度降低到 $c \approx 1.902$ 左右。
但在實務上，管理多個數體會帶來巨大的額外開銷，因此並未在實用規模的 RSA 模數分解上達到決定性的突破。&lt;/p>
&lt;h3 id="42-l_n14-類別的演算法有可能嗎">4.2 $L_n[1/4]$ 類別的演算法有可能嗎？
&lt;/h3>&lt;p>關於質因數分解古典演算法的極限，數學家們長年討論的一個主題就是「指數 $\alpha = 1/4$ 的演算法存在嗎？」這個問題。
目前的 GNFS 及其衍伸演算法，受到透過篩法進行「尋找平滑數」這種框架的強烈限制，而在這種典範中，人們普遍相信 $\alpha = 1/3$ 就是極限。從使用迪克曼函數（Dickman function）來分析平滑整數的分佈機率也可以看出，目前的代數數體建構法與篩法的結合，無論如何最佳化，都被認為無法跨越 $O(L_n[1/3])$ 的障礙。&lt;/p>
&lt;p>如果存在 $L_n[1/4]$ 或是古典的多項式時間演算法，那它必定依賴於一種與 GNFS 這類「基於平滑數」的方法完全不同、目前人類意想不到的全新數學結構（例如，針對橢圓曲線密碼學的 Schoof 演算法這種更為進階的代數幾何學方法）。然而，目前尚未看到這樣的跡象。&lt;/p>
&lt;hr>
&lt;h2 id="5-量子運算的突破shor-演算法">5. 量子運算的突破：Shor 演算法
&lt;/h2>&lt;p>在古典電腦面臨 $L_n[1/3]$ 障礙的同時，Peter Shor 於 1994 年發表的 &lt;strong>Shor 演算法（Shor&amp;rsquo;s Algorithm）&lt;/strong> 透過從根本上改變運算模型，粉碎了這個障礙。&lt;/p>
&lt;h3 id="51-量子多項式時間的衝擊">5.1 量子多項式時間的衝擊
&lt;/h3>&lt;p>Shor 演算法將質因數分解問題化約為「求階問題（Order Finding Problem）」。對於某個整數 $a$，這是一個找出函數 $f(x) = a^x \pmod n$ 之週期（階數）$r$ 的問題。
古典電腦在尋找這個週期時需要耗費指數時間，但透過在量子電腦上使用&lt;strong>量子相位估計（QPE: Quantum Phase Estimation）&lt;strong>與&lt;/strong>量子傅立葉轉換（QFT: Quantum Fourier Transform）&lt;/strong>，可以對所有狀態的疊加態（Superposition）進行平行的評估，並以極高的機率萃取出週期 $r$。&lt;/p>
&lt;p>從計算複雜度的角度來看，Shor 演算法的執行時間屬於&lt;strong>量子多項式時間&lt;/strong>，具體如下所示：
&lt;/p>
$$ O((\log n)^3) $$
&lt;p>
若考慮到近年來經過最佳化的電路實作，被認為可進一步縮減至 $O((\log n)^2 \log \log n)$。&lt;/p>
&lt;div class="mermaid">graph LR
A["古典演算法 (GNFS)"] -->|極限| B["次指數時間 L_n[1/3]"]
C["量子演算法 (Shor)"] -->|突破| D["多項式時間 O((log n)^3)"]
B --> E["持續使用 RSA 密碼 (增加金鑰長度)"]
D --> F["RSA 密碼完全崩潰"]&lt;/div>
&lt;h3 id="52-古典次指數時間-vs-量子多項式時間">5.2 古典次指數時間 vs 量子多項式時間
&lt;/h3>&lt;p>這兩個複雜度類別的差異，在現實世界的密碼安全上具有決定性的意義。&lt;/p>
&lt;p>舉例來說，考慮將 RSA-2048（2048 位元的合成數）進行因數分解的情況。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>GNFS (古典)&lt;/strong>: 將 $n \approx 2^{2048}$ 代入 $L_n[1/3, 1.923]$ 中，大約需要進行 $2^{112}$ 次運算。這是即使集結目前地球上所有運算資源，也需要超過宇宙壽命才能完成的天文數字般的運算量。&lt;/li>
&lt;li>&lt;strong>Shor&amp;rsquo;s Algorithm (量子)&lt;/strong>: 在 $O((\log n)^3)$ 的演算法中，大約只需要進行 $2048^3 \approx 8.5 \times 10^9$ 次的邏輯閘操作。這意味著只要有適當的硬體（具備數百萬物理量子位元與錯誤更正能力的通用量子電腦）存在，計算便能在短短數小時到數天內完成。&lt;/li>
&lt;/ul>
&lt;p>從「指數 $\alpha=1/3$」的次指數時間到「多項式時間」的典範轉移，將使藉由增加金鑰長度來確保安全性的傳統密碼學策略變得毫無招架之力。&lt;/p>
&lt;hr>
&lt;h2 id="6-總結對次世代的展望">6. 總結：對次世代的展望
&lt;/h2>&lt;p>對於「超越 GNFS 的古典演算法存在嗎？」這個問題，目前科學界的共識如下：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>實務上的改良仍會持續，但不會有漸進複雜度上的飛躍&lt;/strong>: 像是 MNFS、多項式選擇的最佳化、區塊魏德曼法的平行化等，改善 GNFS 常數項 $c$ 的嘗試仍持續進行中。然而，一般認為發現低於 $\alpha = 1/3$ 古典演算法的可能性極低。&lt;/li>
&lt;li>&lt;strong>在古典電腦上的 RSA 安全性依然堅固&lt;/strong>: GNFS 的運算量依然非常龐大，RSA-2048 或 RSA-4096 應對古典電腦攻擊的安全性，在未來的數十年間仍會保持穩固。&lt;/li>
&lt;li>&lt;strong>真正的威脅是量子演算法&lt;/strong>: 跨越計算複雜度障礙的是基於量子力學原理的 Shor 演算法。這也迫使世界必須向後量子密碼學（PQC: Post-Quantum Cryptography）過渡。轉向即使是量子電腦也難以破解（無法在多項式時間內解開）的全新數學問題，例如晶格密碼學或基於雜湊的密碼學等，已成為當前密碼學的最前線。&lt;/li>
&lt;/ol>
&lt;p>一般數體篩法（GNFS）是人類挑戰古典數學與演算法設計極限所達到的「最高成就」之一。了解 GNFS 深奧的數學結構，不僅僅是學習密碼破解的歷史，更是一趟接觸計算複雜度理論與代數數論之美的知識探索之旅。在量子電腦真正普及的那一天到來之前，GNFS 將會持續穩坐最強質因數分解演算法的寶座。&lt;/p></description></item><item><title>用Python模擬秀爾演算法</title><link>http://kenji.blog/zh-tw/p/shors-algorithm-simulation-python/</link><pubDate>Fri, 11 Sep 2026 08:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/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 用Python模擬秀爾演算法" />&lt;h1 id="1-簡介量子電腦帶來的密碼危機">1. 簡介：量子電腦帶來的密碼危機
&lt;/h1>&lt;p>現代網際網路社會中的安全性，大部分依賴於&lt;strong>公鑰加密系統&lt;/strong>（尤其是RSA加密）。當我們在線上購物傳送信用卡資訊，或是傳遞高機密性資料時，這些通訊內容都受到RSA加密的強力保護。&lt;/p>
&lt;p>RSA加密的安全性基礎，仰賴於一個數學事實：「&lt;strong>將極大的整數進行質因數分解，對古典電腦（我們平時使用的PC或超級電腦）來說是極度困難的&lt;/strong>」。然而，彼得·秀爾（Peter Shor）在1994年發表的「&lt;strong>秀爾演算法（Shor&amp;rsquo;s Algorithm）&lt;/strong>」，卻從根本上推翻了這個前提。數學上已經證明，如果在大規模的量子電腦上執行秀爾演算法，原本古典電腦需要耗費超過宇宙年齡才能完成的質因數分解，只需短短幾分鐘到幾小時就能解開。&lt;/p>
&lt;p>本文將詳細解說秀爾演算法是如何高速進行質因數分解，從其數學原理，到使用Python與量子計算框架&lt;strong>Qiskit&lt;/strong>的具體模擬實作，進行徹底且深入的剖析。&lt;/p>
&lt;hr>
&lt;h1 id="2-計算複雜度的劇烈變化從指數函數到多項式時間">2. 計算複雜度的劇烈變化：從指數函數到多項式時間
&lt;/h1>&lt;p>為什麼質因數分解這麼困難？即使使用已知在古典電腦上最佳的質因數分解演算法「普通數域篩法（General Number Field Sieve, GNFS）」，其計算複雜度依然是次指數時間的。&lt;/p>
&lt;p>使用古典方法，對一個位數為 $N$ 的合成數進行質因數分解的時間複雜度如下：&lt;/p>
$$ O\left(\exp\left( c (\log N)^{1/3} (\log \log N)^{2/3} \right)\right) $$
&lt;p>正因如此，只要增加金鑰長度（例如增加到2048位元或4096位元），使用古典電腦破解就需要數千年、數萬年這種不切實際的時間。&lt;/p>
&lt;p>但是，如果在量子電腦上使用&lt;strong>秀爾演算法&lt;/strong>，相對於輸入的位元數 $\log N$，計算複雜度將會劇烈縮減至多項式時間。&lt;/p>
$$ O((\log N)^3) $$
&lt;p>這意味著，當位元數增加為2倍時，古典電腦的計算時間將呈天文數字般暴增，而量子電腦的計算時間頂多只會增加大約8倍。這種**將計算複雜度層級從指數時間縮減到多項式時間（包含於BQP複雜度類別）**的特性，正是秀爾演算法真正的厲害之處。&lt;/p>
&lt;div class="mermaid">graph TD
A["輸入大小(位元數) N的增加"] --> B{"演算法的選擇"}
B -->|古典: 普通數域篩法| C["次指數級增加 O(exp(...))"]
B -->|量子: 秀爾演算法| D["多項式時間 O((log N)^3)"]
C --> E["數千年〜數十億年 (無法破解)"]
D --> F["數分鐘〜數小時 (現實時間內可破解)"]&lt;/div>
&lt;hr>
&lt;h1 id="3-演算法全貌與數學背景">3. 演算法全貌與數學背景
&lt;/h1>&lt;p>其實秀爾演算法並非全部都在量子電腦上執行。它是透過古典電腦的預先處理與後續處理，加上量子電腦負責核心部分（週期尋找演算法）的相互配合所構成。&lt;/p>
&lt;p>演算法的整體流程如下：&lt;/p>
&lt;div class="mermaid">graph TD
A["輸入: 想要進行質因數分解的合成數 N"] --> B["選擇一個小於 N 的隨機數 a"]
B --> C{"gcd(a, N) > 1 ?"}
C -- "Yes" --> D["輸出明顯的因數 gcd(a, N) 並結束"]
C -- "No" --> E["用量子演算法尋找 f(x) = a^x mod N 的週期 r"]
E --> F{"r 為偶數 且 a^(r/2) ≢ -1 mod N ?"}
F -- "No" --> B
F -- "Yes" --> G["計算因數 p = gcd(a^(r/2) - 1, N), q = gcd(a^(r/2) + 1, N)"]
G --> H["輸出: p, q"]&lt;/div>
&lt;h2 id="從質因數分解化約為週期尋找問題">從質因數分解化約為週期尋找問題
&lt;/h2>&lt;p>秀爾天才般的靈感在於，他將「&lt;strong>質因數分解問題&lt;/strong>」轉換成了「&lt;strong>週期尋找問題（Order Finding Problem）&lt;/strong>」。&lt;/p>
&lt;p>假設有一個整數 $N$（想要質因數分解的數字），以及一個與其互質的整數 $a$（$1 &lt; a &lt; N$）。我們定義以下模指數函數：&lt;/p>
$$ f(x) = a^x \bmod N $$
&lt;p>這個函數具有某個週期 $r$。也就是說，對任意的 $x$ 皆滿足 $f(x+r) = f(x)$。特別是當 $x=0$ 時，&lt;/p>
$$ a^r \equiv 1 \pmod N $$
&lt;p>能滿足此條件的最小正整數 $r$，我們稱為「$a$ 模 $N$ 的階（Order）」。只要能找到這個週期 $r$，就可以透過以下方式導出質因數。&lt;/p>
&lt;p>將式子變形後得到：
&lt;/p>
$$ a^r - 1 \equiv 0 \pmod N $$
&lt;p>
如果 $r$ 是偶數，就可以利用平方差公式進行因式分解：
&lt;/p>
$$ (a^{r/2} - 1)(a^{r/2} + 1) \equiv 0 \pmod N $$
&lt;p>這意味著 $N$ 與 $(a^{r/2} - 1)$ 或是 $(a^{r/2} + 1)$ 其中之一擁有公因數（不過必須滿足 $a^{r/2} \not\equiv -1 \pmod N$ 這個條件）。因此，我們可以使用輾轉相除法計算：&lt;/p>
$$ p = \gcd(a^{r/2} - 1, N) $$
$$ q = \gcd(a^{r/2} + 1, N) $$
&lt;p>藉此就可以找到 $N$ 的非平凡質因數 $p, q$。這些計算（計算最大公因數與產生隨機數）在古典電腦上可以非常高速地完成。因此問題就集中在&lt;strong>如何高速地找到週期 $r$&lt;/strong>。在古典電腦上，單是尋找這個週期 $r$ 本身就需要耗費指數時間。這時候就是量子電腦發揮作用的時刻了。&lt;/p>
&lt;hr>
&lt;h1 id="4-量子演算法部分尋找週期的機制">4. 量子演算法部分：尋找週期的機制
&lt;/h1>&lt;p>使用量子電腦尋找週期 $r$ 的副程式，由以下4個步驟組成。&lt;/p>
&lt;div class="mermaid">graph LR
subgraph "量子狀態的轉移"
S1["|0⟩|0⟩ (初始化)"] --> S2["H閘: 疊加 Σ|x⟩|0⟩"]
S2 --> S3["神諭 U: Σ|x⟩|a^x mod N⟩"]
S3 --> S4["QFT: 透過干涉萃取週期"]
S4 --> S5["測量: 取得近似值 y"]
end&lt;/div>
&lt;h2 id="步驟1量子暫存器的初始化與疊加">步驟1：量子暫存器的初始化與疊加
&lt;/h2>&lt;p>首先準備兩個量子暫存器。第一個暫存器用來輸入狀態，第二個暫存器用來儲存函數的計算結果。
初始狀態全部為 $|0\rangle$。&lt;/p>
$$ |\psi_0\rangle = |0\rangle_1 |0\rangle_2 $$
&lt;p>對第一個暫存器的所有量子位元套用阿達馬閘（Hadamard Gate），產生所有可能輸入 $x$ （從 $0$ 到 $Q-1$，$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>如此一來，量子電腦就能在一次運算中同時保有對應 $Q$ 個所有輸入的狀態。這正是&lt;strong>量子平行性&lt;/strong>強大的來源。&lt;/p>
&lt;h2 id="步驟2套用神諭函數模指數運算">步驟2：套用神諭函數（模指數運算）
&lt;/h2>&lt;p>接下來，使用量子運算電路 $U_f$ 計算函數 $f(x) = a^x \bmod N$，並將結果儲存於第二個暫存器中。&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>此時，第一暫存器與第二暫存器處於**量子糾纏（Entanglement）**狀態。如果（假設）我們觀測第二暫存器並得到特定的值 $k = a^{x_0} \bmod N$，那麼第一暫存器的狀態就會塌縮為所有能給出該值 $k$ 的 $x$ 的疊加態。因為函數的週期為 $r$，所以留下來的狀態會是 $x_0, x_0+r, x_0+2r, \dots$ 這樣以 $r$ 為間隔的值。&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>但是，我們想知道的並不是 $x_0$，而是週期 $r$ 本身。從這個狀態直接觀測出 $r$ 是不可能的。於是，我們使用量子傅立葉轉換。&lt;/p>
&lt;h2 id="步驟3透過量子傅立葉轉換qft進行相位干涉">步驟3：透過量子傅立葉轉換（QFT）進行相位干涉
&lt;/h2>&lt;p>對第一個暫存器套用&lt;strong>量子傅立葉轉換（Quantum Fourier Transform, QFT）&lt;/strong>。QFT是古典離散傅立葉轉換的量子版，能夠轉換狀態向量的振幅。QFT對基底狀態 $|x\rangle$ 的作用定義如下：&lt;/p>
$$ QFT |x\rangle = \frac{1}{\sqrt{Q}} \sum_{y=0}^{Q-1} \omega^{xy} |y\rangle $$
&lt;p>這裡的 $\omega = e^{2\pi i / Q}$。&lt;/p>
&lt;p>套用QFT後，狀態的振幅會產生干涉。雖然省略了數學細節，但當對具有週期 $r$ 的狀態套用QFT時，只有在 $y$ 極為接近 $Q/r$ 的整數倍時，波才會產生&lt;strong>建設性干涉（Constructive Interference）&lt;/strong>。除此之外的其他狀態，會因為**破壞性干涉（Destructive Interference）**使機率振幅互相抵消並趨近於零。&lt;/p>
&lt;h2 id="步驟4測量與連分數展開">步驟4：測量與連分數展開
&lt;/h2>&lt;p>最後測量第一個暫存器。測量所得的值 $y$，有極高的機率會滿足以下條件：&lt;/p>
$$ y \approx c \frac{Q}{r} \implies \frac{y}{Q} \approx \frac{c}{r} $$
&lt;p>（$c$ 是一個滿足 $0 \le c &lt; r$ 的未知整數）&lt;/p>
&lt;p>對得到的有理數 $y/Q$ 套用古典演算法&lt;strong>連分數展開（Continued Fraction Expansion）&lt;/strong>，便可計算出近似分數 $c/r$，並從分母萃取出週期 $r$。&lt;/p>
&lt;hr>
&lt;h1 id="5-使用python與qiskit的模擬實作">5. 使用Python與Qiskit的模擬實作
&lt;/h1>&lt;p>只看理論很難有實際體會，所以讓我們實際使用Python與IBM的量子計算框架&lt;strong>Qiskit&lt;/strong>，來模擬看看秀爾演算法。&lt;/p>
&lt;p>在這裡，我們將實作最經典且著名的例子：&lt;strong>「使用 $a=7$ 將 $N=15$ 進行質因數分解」&lt;/strong>。&lt;/p>
&lt;h2 id="執行環境準備">執行環境準備
&lt;/h2>&lt;p>請事先安裝好Qiskit。&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="python實作程式碼全貌">Python實作程式碼全貌
&lt;/h2>&lt;p>以下程式碼是專門針對 $N=15, a=7$ 的秀爾演算法實作範例。由於建立通用的模指數運算電路對現在的模擬器來說計算成本太高，因此我們將針對 $a=7$ 情況下的閘道動作進行寫死（hardcoding）。&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. 建構反量子傅立葉轉換 (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;產生n個量子位元的反量子傅立葉轉換電路&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閘&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"># 套用受控相位閘與H閘&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">j&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">m&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">cp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pi&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="nb">float&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">)),&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">j&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">h&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;QFT_dagger&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">qc&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. 建構 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;針對特定的a與次方產生受控U閘(N=15專用)&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">U&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">QuantumCircuit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">power&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># a=7的情況下 7^x mod 15 的寫死邏輯&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. 主要的量子電路構成&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: 控制暫存器的位元數&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 目標暫存器為了表現 0〜15 因此使用 4位元&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"># 第一暫存器（控制暫存器）的初始化（產生疊加態）&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"># 將第二暫存器（目標暫存器）初始化為 |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"># 套用受控模指數運算（神諭）&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"># 套用 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"># 對第一暫存器套用反量子傅立葉轉換&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"># 測量第一暫存器&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"># --- 執行區塊 ---&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"># 控制暫存器使用8個量子位元 (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;探索設定: 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">, 控制量子位元數=&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"># 產生電路&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"># 在模擬器上執行&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"># 最新的Qiskit建議使用transpile&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">測量結果(位元字串: 觀測次數):&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">次&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"># 古典後處理: 透過連分數展開找出週期r&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">--- 週期的計算與質因數分解 ---&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"># 將位元字串轉換為十進位&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"># 相位 = 測量值 / 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"># 透過連分數展開取得近似分數。分母上限為 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;觀測值: &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"> | 相位: &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"> | 連分數: &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"> | 估計週期 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"># 確認週期 r 是否為偶數且能帶來有效結果&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; 成功！ &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"> 的質因數是 &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"> 與 &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; 只有平凡因數。請重試。&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; 週期為奇數因此失敗。&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="程式碼解說與執行結果解析">程式碼解說與執行結果解析
&lt;/h2>&lt;p>執行上述程式碼後，作為控制暫存器的測量結果，有極高機率會得到特定的峰值（觀測值）。在 &lt;code>n_count=8&lt;/code>（$Q=256$）的情況下，如果是理想的量子電腦（或模擬器），像 &lt;code>0&lt;/code>, &lt;code>64&lt;/code>, &lt;code>128&lt;/code>, &lt;code>192&lt;/code> 這類的數值會以壓倒性的機率作為觀測值出現。&lt;/p>
&lt;p>將這些數值除以 $Q=256$ 後，相位 $y/Q$ 分別為 $0.0$, $0.25$, $0.5$, $0.75$。
將這些相位進行連分數展開：&lt;/p>
&lt;ul>
&lt;li>$0.25 \to 1/4$ （估計週期 $r=4$）&lt;/li>
&lt;li>$0.50 \to 1/2$ （估計週期 $r=2$）&lt;/li>
&lt;li>$0.75 \to 3/4$ （估計週期 $r=4$）&lt;/li>
&lt;/ul>
&lt;p>利用這裡得到的週期 $r=4$ 來計算質因數。
因為 $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>漂亮地成功將 $15$ 質因數分解為 $3 \times 5$。&lt;/p>
&lt;blockquote>
&lt;p>[!TIP]
如果得到的測量值為 $y=128$（相位 $0.5$），分母將會是 $2$，這樣會得到真正的週期 $r=4$ 的因數而非本身。在這種情況下，只要將演算法執行多次，或是檢查所得到 $r$ 的倍數，最終就能找出真正的週期。&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h1 id="6-邁向實用化的挑戰與-nisq-時代的極限">6. 邁向實用化的挑戰與 NISQ 時代的極限
&lt;/h1>&lt;p>雖然在模擬器上將 $N=15$ 進行質因數分解非常簡單，但要在現實中的量子電腦上分解社會中實際使用的 RSA-2048（617位數的十進位數），目前還存在著許多難以跨越的障礙。&lt;/p>
&lt;p>我們現在所處的時代，被稱為 &lt;strong>NISQ（Noisy Intermediate-Scale Quantum：含雜訊中等規模量子）時代&lt;/strong>。量子位元對外部環境的雜訊極度敏感，計算途中容易發生「退相干（Decoherence）」導致狀態崩壞。&lt;/p>
&lt;p>為了能準確執行像秀爾演算法這種具有深度（閘數量多）的電路，能修正雜訊的**量子錯誤更正（Quantum Error Correction）**是不可或缺的。為了創造出一個沒有雜訊的「邏輯量子位元」，需要透過表面碼（Surface Code）等方式將數千個「實體量子位元」進行編碼。&lt;/p>
&lt;p>據估計，要破解2048位元的RSA加密，需要數千個完美的邏輯量子位元，這意味著必須要有搭載&lt;strong>數百萬至數千萬個實體量子位元&lt;/strong>的容錯（Fault-tolerant）量子電腦才能實現。而目前最先進的量子處理器也只有幾百到幾千個實體量子位元左右，因此全世界的密碼並不會立刻被破解。&lt;/p>
&lt;blockquote>
&lt;p>[!WARNING]
然而，存在著一種名為「Store Now, Decrypt Later（現在儲存，日後解密）」的威脅模型。攻擊者可能會將目前加密的機密通訊資料大量儲存起來，等到10至20年後強大的量子電腦問世時，再將其全部解密，這是一種非常可能的策略。&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h1 id="7-轉移至後量子密碼學pqc">7. 轉移至後量子密碼學（PQC）
&lt;/h1>&lt;p>為了因應這種「Q-Day（量子電腦破解密碼之日）」的到來，以美國國家標準暨技術研究院（NIST）為首，全世界的密碼學家正在積極制定**後量子密碼學（Post-Quantum Cryptography, PQC）**標準。&lt;/p>
&lt;p>PQC 建立在被認為即使使用秀爾演算法（或葛羅佛演算法）也無法在數學上有效解開的全新數學問題（如晶格問題、多變數多項式問題、雜湊函數等）基礎上。目前像是「CRYSTALS-Kyber」與「CRYSTALS-Dilithium」等演算法已經被選為標準規格，並正逐漸導入 Apple 的 iMessage 或是各大網頁瀏覽器的通訊協定中。&lt;/p>
&lt;p>對管理IT基礎設施的工程師來說，在系統中導入從現有 RSA 或橢圓曲線密碼轉換到 PQC 的「密碼敏捷性（Crypto-Agility：能快速切換密碼系統的設計）」，將會是未來的一大任務。&lt;/p>
&lt;hr>
&lt;h1 id="8-結語">8. 結語
&lt;/h1>&lt;p>本文從秀爾演算法的理論數學背景開始，介紹了使用量子傅立葉轉換萃取週期的機制，並深入到使用Python與Qiskit的具體模擬程式碼，以約一萬字的篇幅進行了徹底的解說。&lt;/p>
&lt;p>量子力學這種微觀世界的物理法則，竟然能從根本推翻作為宏觀資訊科學基礎的計算複雜度理論與密碼理論，這是科學史上最令人興奮的典範轉移之一。未來我們也絕對不能將目光從持續發展的量子運算技術，以及與之抗衡的新型密碼技術的攻防戰中移開。&lt;/p>
&lt;p>請務必在您自己的環境中執行本次介紹的Python程式碼，親身體驗量子狀態的疊加與干涉所創造出來的「計算魔法」。&lt;/p>
&lt;hr>
&lt;p>&lt;strong>參考文獻&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>【圖解PQC】抗量子密碼學的主要演算法比較</title><link>http://kenji.blog/zh-tw/p/post-quantum-cryptography-algorithms-comparison/</link><pubDate>Fri, 11 Sep 2026 07:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/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 【圖解PQC】抗量子密碼學的主要演算法比較" />&lt;h2 id="1-前言量子電腦帶來的密碼危機">1. 前言：量子電腦帶來的「密碼危機」
&lt;/h2>&lt;p>在現代的網際網路社會中，為了保護通訊的機密性與資料的完整性，公開金鑰密碼技術是不可或缺的基礎設施。目前廣泛使用的RSA密碼與橢圓曲線密碼（ECC），分別依賴於「大質數整數分解的困難度」與「橢圓曲線上的離散對數問題的困難度」等數學壁壘來確保安全性。在古典電腦（包含超級電腦在內，我們現在正在使用的電腦）上，要解開這些數學問題所需的時間被證明比宇宙的年齡還要長，這一直以來都是安全性的依據。&lt;/p>
&lt;p>然而，這個堅固的前提正因為&lt;strong>量子電腦&lt;/strong>的理論與實用化進展而面臨徹底被推翻的危機。1994年，密碼學家彼得·秀爾（Peter Shor）發表的「&lt;strong>Shor演算法（秀爾演算法）&lt;/strong>」在理論上證明，只要在具備足夠效能的容錯通用量子電腦（CRQC: Cryptographically Relevant Quantum Computer）上執行，就能在「多項式時間」內破解整數分解問題與離散對數問題。這意味著目前使用的公開金鑰密碼將全部失效。&lt;/p>
&lt;div class="mermaid">graph TD
A["大規模的量子電腦 (CRQC)"] -->|執行| B["Shor演算法"]
B -->|以多項式時間破解| C["整數分解問題 (RSA)"]
B -->|以多項式時間破解| D["離散對數問題 (ECC / ECDSA)"]
C --> E["密碼通訊的竊聽、資料竄改、身分冒用"]
D --> E
F["Store Now, Decrypt Later (SNDL)"] --> E&lt;/div>
&lt;p>認為「量子電腦真正完成還需要幾十年，所以現在沒問題」是非常危險的。因為被稱為&lt;strong>Store Now, Decrypt Later (SNDL：現在儲存，稍後解密)&lt;/strong> 的攻擊手法已經成為現實的威脅。這是指惡意的國家或駭客組織將目前加密的通訊資料（如TLS流量等）大量儲存起來，等到未來強大的量子電腦可用的瞬間，再將其全部解密的攻擊。國家機密、基礎設施資訊、需要長期保護的醫療資料等，已經暴露在這個威脅之下。&lt;/p>
&lt;p>此外，針對對稱金鑰密碼（如AES）與雜湊函數（如SHA-256），也存在1996年發現的&lt;strong>Grover演算法&lt;/strong>。這能將暴力破解攻擊（Brute-force）的運算量減少到平方根。也就是說，AES-128的安全級別實質上將減半至2的64次方，因此在量子時代，建議使用如AES-256或SHA-384等更長長度的金鑰與雜湊值。&lt;/p>
&lt;p>為對抗這場前所未有的密碼危機而誕生的，就是即使使用量子電腦也難以破解、基於全新數學問題的&lt;strong>抗量子密碼學（Post-Quantum Cryptography: PQC）&lt;/strong>。本文將根據美國國家標準暨技術研究院（NIST）主導的PQC標準化流程結果，針對主要的PQC演算法，從其數學背景、機制到架構比較進行極為詳細的解說。&lt;/p>
&lt;hr>
&lt;h2 id="2-nist的pqc標準化專案全貌與歷史">2. NIST的PQC標準化專案全貌與歷史
&lt;/h2>&lt;p>密碼技術的過渡（包含協定重新設計、系統更新、硬體更換等）需要花費數年到數十年的時間。因此，世界各地的密碼學家從很早以前就開始進行PQC的研究。其中扮演核心角色的是美國的NIST（國家標準暨技術研究院）。NIST在2016年公開徵求PQC標準化流程，接受來自全球密碼社群提出的全新密碼演算法。&lt;/p>
&lt;p>標準化的對象主要分為以下兩個類別：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>公開金鑰密碼 / 金鑰封裝機制 (KEM: Key Encapsulation Mechanism)&lt;/strong>：在TLS連線等情境中，為了加密通訊路徑，安全地共享（配送）共同金鑰的機制。&lt;/li>
&lt;li>&lt;strong>數位簽章 (Digital Signatures)&lt;/strong>：在軟體更新或電子憑證中，證明資料未被竄改以及發送者未被冒用（真實性）的機制。&lt;/li>
&lt;/ol>
&lt;p>經歷了約6年非常激烈的評估、分析與密碼破解競爭（Round 1～Round 3）後，更針對部分演算法進行了Round 4的追加評估。其結果是，在2024年，以下演算法正式成為聯邦資訊處理標準（FIPS），並確立為未來的世界標準。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>FIPS 203 (ML-KEM)&lt;/strong>：基於CRYSTALS-Kyber的KEM&lt;/li>
&lt;li>&lt;strong>FIPS 204 (ML-DSA)&lt;/strong>：基於CRYSTALS-Dilithium的數位簽章&lt;/li>
&lt;li>&lt;strong>FIPS 205 (SLH-DSA)&lt;/strong>：基於SPHINCS+的無狀態雜湊基數位簽章&lt;/li>
&lt;li>&lt;strong>（預計未來制定）FN-DSA&lt;/strong>：基於FALCON的數位簽章&lt;/li>
&lt;/ul>
&lt;p>這些被選定的演算法所依賴的數學「困難度問題」各不相同，這是為了確保即使某一個演算法在未來被發現有致命漏洞，整個系統也不會崩潰的「密碼敏捷性 (Crypto Agility)」。在標準化過程中，雖然晶格密碼 (Lattice-based cryptography) 因為效能優勢成為主角，但雜湊基密碼與編碼基密碼也被採用作為強大的後盾。&lt;/p>
&lt;hr>
&lt;h2 id="3-pqc主要數學方法的分類">3. PQC主要數學方法的分類
&lt;/h2>&lt;p>PQC演算法根據其安全性基礎的數學問題，主要可分為以下5大類。本文將特別針對前3類進行深入探討。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>晶格密碼 (Lattice-based Cryptography)&lt;/strong>：
基於多維晶格空間中的最短向量問題（SVP）與最近向量問題（CVP），以及由此衍生出的LWE問題。這是NIST標準化的核心，Kyber、Dilithium、FALCON皆屬此類。其處理速度、公開金鑰大小與密文大小的平衡最為優異，適合通用。&lt;/li>
&lt;li>&lt;strong>雜湊基密碼 (Hash-based Cryptography)&lt;/strong>：
僅將安全性基礎建立在密碼學雜湊函數（如SHA-2或SHAKE等）的「抗碰撞性」與「單向性」上。雖然只能應用於數位簽章（如SPHINCS+等），但其安全性證明最為強固，對未知數學攻擊的抵抗力極高。&lt;/li>
&lt;li>&lt;strong>編碼基密碼 (Code-based Cryptography)&lt;/strong>：
基於錯誤更正碼理論，依賴於症狀解碼問題（Syndrome Decoding Problem）的困難度。1970年代提出的Classic McEliece是其代表，雖然擁有非常悠久的歷史與經過驗證的安全性，但公開金鑰的尺寸會極端龐大（達到MB等級）。&lt;/li>
&lt;li>&lt;strong>多變數多項式密碼 (Multivariate Polynomial Cryptography)&lt;/strong>：
基於在有限體上求解多變數聯立二次方程式（MQ問題）的困難度。主要被提案作為數位簽章（如Rainbow等），但在NIST最後一輪評估期間，被發現能用一台普通電腦在幾天內破解的強大攻擊手法，導致許多演算法退出了標準化。&lt;/li>
&lt;li>&lt;strong>同源密碼 (Isogeny-based Cryptography)&lt;/strong>：
基於橢圓曲線同源（Isogeny）圖上的路徑搜尋問題。金鑰尺寸非常小，曾被期待作為ECC的正統繼承者，但在2022年，最終候選者「SIKE」被利用古典數學（如Castryck-Decru攻擊）在一般PC上僅花幾小時就完全破解，以戲劇性的方式落幕，象徵了PQC設計的困難與可怕。&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="4-晶格密碼的深淵lwe問題與module-lwe的數學基礎">4. 晶格密碼的深淵：LWE問題與Module-LWE的數學基礎
&lt;/h2>&lt;p>目前最被看好且成為標準化核心的&lt;strong>晶格密碼&lt;/strong>，其安全性根基在於&lt;strong>LWE問題 (Learning with Errors: 帶誤差學習問題)&lt;/strong>。2005年由Oded Regev提出，他並憑藉這項劃時代的貢獻獲得了哥德爾獎（Gödel Prize）。若不了解LWE問題，就無法談論現代的PQC。&lt;/p>
&lt;h3 id="41-什麼是lwe問題-learning-with-errors">4.1. 什麼是LWE問題 (Learning with Errors)
&lt;/h3>&lt;p>首先，讓我們考慮一個簡單的聯立一次方程式。假設在某個模數 $q$ （modulo $q$）下，有一個已知的隨機矩陣 $A$ ，與一個未知的秘密向量 $\vec{s}$ ，並給定兩者的乘積 $\vec{b}$ 。&lt;/p>
$$ \vec{b} = A\vec{s} \pmod q $$
&lt;p>此時，從公開資訊 $A$ 與 $\vec{b}$ 中，要找出未知的 $\vec{s}$ 非常簡單。只要使用古典的演算法「高斯消去法」，就能在多項式時間內輕鬆計算出 $\vec{s}$ 。&lt;/p>
&lt;p>然而，如果在方程式中加入「微小的刻意誤差（雜訊）」，問題的難度就會劇烈攀升。這就是&lt;strong>LWE問題&lt;/strong>。&lt;/p>
&lt;p>準備一個未知的秘密向量 $\vec{s} \in \mathbb{Z}_q^n$ ，與一個隨機挑選的矩陣 $A \in \mathbb{Z}_q^{m \times n}$ 。接著，再準備一個依照常態分佈或二項分佈挑選、且「元素值足夠小」的誤差向量 $\vec{e} \in \mathbb{Z}_q^m$ ，然後以下列方式計算 $\vec{b}$ ：&lt;/p>
$$ \vec{b} = A\vec{s} + \vec{e} \pmod q $$
&lt;p>&lt;strong>Search LWE問題&lt;/strong>是指「從公開資訊 $(A, \vec{b})$ 中求出秘密資訊 $\vec{s}$ 」的問題。由於存在這個誤差 $\vec{e}$ ，當我們嘗試使用高斯消去法等代數解法時，在方程式加減的過程中，誤差 $\vec{e}$ 會像雪球一樣越滾越大，最終與隨機值無法區分而導致解法失敗。&lt;/p>
&lt;p>LWE問題的厲害之處在於，它具有強大的理論證明（歸約）：除非存在能夠解開晶格上「最壞情況複雜度問題 (Worst-case hardness)」如GapSVP（判定最短向量問題）或SIVP（最短獨立向量問題）的量子演算法，否則LWE問題在「平均情況 (Average-case)」下也無法被解開。也就是說，即使是隨機產生的加密金鑰，也能保證擁有由理論上限作為後盾的強固安全性。&lt;/p>
&lt;h3 id="42-透過ring-lwe與module-lwe帶來的劇烈效率提升">4.2. 透過Ring-LWE與Module-LWE帶來的劇烈效率提升
&lt;/h3>&lt;p>一般的LWE問題（Standard LWE）雖然安全性基礎非常明確，但矩陣 $A$ 的尺寸會變得非常大，導致金鑰尺寸達到MB等級，因此不具實用性。於是提出了利用多項式環（Polynomial Rings）來賦予代數結構的方法。&lt;/p>
&lt;p>在&lt;strong>Ring-LWE問題&lt;/strong>中，不再使用單純的向量或矩陣，而是使用某個多項式環 $R_q$ 的元素（多項式）。NIST標準中一般使用的是如下的分圓多項式環：&lt;/p>
$$ R_q = \mathbb{Z}_q[X]/(X^n + 1) $$
&lt;p>這裡，$n$ 是2的次方（例如：256），$q$ 是適當的質數。在這個環上，使用元素 $a, s, e \in R_q$ 來計算 $b = a \cdot s + e \pmod q$ 。因為一個多項式 $a$ 就有 $n$ 個係數，這能大幅壓縮資料，且透過稱為&lt;strong>NTT (Number Theoretic Transform: 數論轉換)&lt;/strong> 的有限體版本快速傅立葉轉換（FFT），能以 $O(n \log n)$ 的運算量超高速地進行多項式乘法。&lt;/p>
&lt;p>然而，Ring-LWE存在「可能因為環的特殊代數結構而存在未知漏洞」的隱憂。此外，當需要變更安全級別（例如相當於AES-128、192、256等）時，必須改變多項式的次數 $n$ 本身，這會伴隨著必須重寫NTT演算法等整個實作的工程問題。&lt;/p>
&lt;p>因此，被標準化演算法Kyber與Dilithium所採用的，就是&lt;strong>Module-LWE (M-LWE) 問題&lt;/strong>。Module-LWE是位於無結構的Standard LWE與過度結構化的Ring-LWE之間的一種折衷方案，它使用以多項式環 $R_q$ 的元素為成分的 $k \times k$ 矩陣（模組）。&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>Module-LWE最大的優點在於，可以保持多項式的次數 $n$ 固定（在NIST標準中 $n=256$），只需改變矩陣的維度 $k$ ，就能輕易地擴展安全級別。
例如在Kyber中，維度 $k$ 調整如下：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Kyber512 (Level 1)&lt;/strong>: $k = 2$ （相當於 AES-128）&lt;/li>
&lt;li>&lt;strong>Kyber768 (Level 3)&lt;/strong>: $k = 3$ （相當於 AES-192）&lt;/li>
&lt;li>&lt;strong>Kyber1024 (Level 5)&lt;/strong>: $k = 4$ （相當於 AES-256）&lt;/li>
&lt;/ul>
&lt;p>這使得底層的NTT程式碼或多項式運算的硬體電路可以在所有安全級別中達到100%的重複使用，讓實作的安全性與效率都獲得了劇烈提升。&lt;/p>
&lt;hr>
&lt;h2 id="5-crystals-kyber-ml-kem次世代的金鑰封裝機制">5. CRYSTALS-Kyber (ML-KEM)：次世代的金鑰封裝機制
&lt;/h2>&lt;p>正式被標準化為&lt;strong>FIPS 203 (ML-KEM)&lt;/strong> 的CRYSTALS-Kyber，是基於前述Module-LWE問題的金鑰封裝機制 (KEM)。未來，它將成為在TLS 1.3或SSH等協議中安全共享會話金鑰 (Session Key) 的實質世界標準。&lt;/p>
&lt;h3 id="51-kem-key-encapsulation-mechanism-的架構">5.1. KEM (Key Encapsulation Mechanism) 的架構
&lt;/h3>&lt;p>在PQC時代，標準將不再是像RSA那樣「由客戶端建立共同金鑰並用伺服器的公開金鑰加密傳送」的直接作法，而是採用KEM這種封裝框架。&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant Client as "客戶端 (Alice)"
participant Server as "伺服器 (Bob)"
Note over Client: "ML-KEM KeyGen()"
Client->>Client: "產生秘密金鑰 (sk) 與公開金鑰 (pk)"
Client->>Server: "傳送公開金鑰 (pk)"
Note over Server: "ML-KEM Encaps()"
Server->>Server: "產生隨機的共同金鑰 (K)"
Server->>Server: "用pk將K封裝，建立密文 (c)"
Server->>Client: "傳送密文 (c)"
Note over Client: "ML-KEM Decaps()"
Client->>Client: "使用秘密金鑰 (sk) 解密密文 (c)"
Client->>Client: "解除封裝，取出共同金鑰 (K)"
Note over Client, Server: "使用共享的共同金鑰 (K)，開始透過AES等進行加密通訊"&lt;/div>
&lt;h3 id="52-kyber的內部演算法機制與藤崎-岡本轉換">5.2. Kyber的內部演算法機制與藤崎-岡本轉換
&lt;/h3>&lt;p>Kyber的設計非常精練。首先，建構出只對CPA（選擇明文攻擊）安全的公開金鑰密碼系統（Kyber.CPAPKE），然後對其套用被稱為&lt;strong>藤崎-岡本轉換 (Fujisaki-Okamoto Transform)&lt;/strong> 的密碼學強大手法，將其升級為對CCA（適應性選擇密文攻擊）也安全的完整KEM設計。&lt;/p>
&lt;p>CPAPKE核心的加密與解密機制如下：&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>金鑰生成 (Key Generation)&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>從隨機的種子值，在NTT網域上產生矩陣 $A \in R_q^{k \times k}$ 。模數 $q$ 使用 $3329$ 。&lt;/li>
&lt;li>從中心二項分佈（CBD）中，取樣出具有微小係數的秘密向量 $\vec{s}$ 與誤差向量 $\vec{e}$ 。&lt;/li>
&lt;li>計算 $\vec{t} = A\vec{s} + \vec{e}$ 。公開金鑰為 $(A, \vec{t})$ ，秘密金鑰為 $\vec{s}$ 。（實際上 $A$ 是作為種子值公開，以節省頻寬）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>加密 (Encryption)&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>將想要共享的32位元組訊息（共同金鑰材料） $m$ 編碼為多項式。&lt;/li>
&lt;li>產生新的隨機向量 $\vec{r}$ 與微小誤差 $\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>密文為 $(\vec{u}, v)$ 。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>解密 (Decryption)&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>接收者計算 $v - \vec{s}^T\vec{u}$ 。&lt;/li>
&lt;li>將這個算式展開如下：
$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>這裡將 $\vec{t} = A\vec{s} + \vec{e}$ 代入，主項 $\vec{s}^TA^T\vec{r}$ 就會互相抵銷。&lt;/li>
&lt;li>剩下的部分為 $\lfloor q/2 \rceil \cdot m + (\vec{e}^T\vec{r} + e_2 - \vec{s}^T\vec{e_1})$ 。&lt;/li>
&lt;li>括號內的項目是「微小誤差之間的乘積與和」，所以整體來說也只是一個夠小的值（雜訊）。因此，只要透過閾值判定各係數是接近 $0$ 還是接近 $q/2$ ，就能完美、毫無錯誤地還原出原始訊息 $m$ 的位元（0或1）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>Kyber最大的優勢在於其壓倒性的&lt;strong>處理速度&lt;/strong>與&lt;strong>適中的金鑰尺寸&lt;/strong>。以Kyber768為例，公開金鑰尺寸為1,184位元組，密文尺寸為1,088位元組，雖然與RSA-3072（金鑰尺寸約384位元組）等相比來得大，但可以不用切割封包，直接容納在現代網際網路通訊的MTU（Maximum Transmission Unit）內，對網路的延遲幾乎沒有不良影響。&lt;/p>
&lt;hr>
&lt;h2 id="6-crystals-dilithium-ml-dsa基於晶格的通用數位簽章">6. CRYSTALS-Dilithium (ML-DSA)：基於晶格的通用數位簽章
&lt;/h2>&lt;p>在數位簽章的標準化過程中，即使在同樣的晶格密碼方法中，也有著不同設計理念的演算法互相競爭。其中被選為通用數位簽章&lt;strong>FIPS 204 (ML-DSA)&lt;/strong> 的，就是&lt;strong>CRYSTALS-Dilithium&lt;/strong>。&lt;/p>
&lt;h3 id="61-fiat-shamir-with-aborts-典範">6.1. Fiat-Shamir with Aborts 典範
&lt;/h3>&lt;p>Dilithium與Kyber同樣是基於Module-LWE（以及Module-SIS問題）的數位簽章機制。其設計基礎採用了名為「&lt;strong>Fiat-Shamir with Aborts (伴隨中斷的Fiat-Shamir轉換)&lt;/strong>」的極為重要之典範 (Paradigm)。&lt;/p>
&lt;p>Fiat-Shamir轉換本身是將互動式零知識證明協定轉換為非互動式數位簽章的標準手法。證明者（簽章者）產生承諾 (Commitment) $y$ ，計算 $w = Ay$ 並輸入雜湊函數，從而獲得隨機的挑戰 $c$ ，再計算回應 $z = y + cs$ 。&lt;/p>
&lt;p>然而，如果將其單純地應用在晶格密碼上，回應 $z$ 的分佈將會依賴於秘密金鑰 $s$ 的值而產生扭曲。這會導致觀察了大量簽章的攻擊者能一點一滴地取得秘密金鑰 $s$ 的資訊，這是一個致命的問題（側信道般的數學外洩）。&lt;/p>
&lt;p>Dilithium的設計團隊（Lyubashevsky等人）導入了一種名為「&lt;strong>拒絕取樣 (Rejection Sampling)&lt;/strong>」的手法：如果簽章的計算結果 $z$ 的係數沒有落在預先設定的安全閾值範圍內，就將整個簽章過程作廢（Abort），並使用新的亂數 $y$ 從頭開始計算。&lt;/p>
&lt;p>透過這種方式，最終輸出的簽章 $z$ 會呈現完全獨立於秘密金鑰的均勻分佈，在數學上完美地防止了資訊外洩。&lt;/p>
&lt;h3 id="62-dilithium的優點與實作的容易度">6.2. Dilithium的優點與實作的容易度
&lt;/h3>&lt;p>Dilithium在設計上的一大優勢是，在簽章生成過程中&lt;strong>完全不使用&lt;/strong>複雜的「高斯分佈取樣」或「浮點數運算」。因為只需透過均勻分佈取樣、單純的整數模數運算、NTT以及雜湊函數（SHAKE）就能實作，這讓它在從嵌入式微控制器到雲端伺服器等廣泛的環境中，都很容易進行安全且常數時間（Constant-time）的實作。這使得它對計時攻擊（Timing Attack）等物理側信道攻擊也擁有強大的抵抗力。&lt;/p>
&lt;hr>
&lt;h2 id="7-falcon-fn-dsa極致精巧的晶格簽章">7. FALCON (FN-DSA)：極致精巧的晶格簽章
&lt;/h2>&lt;p>NIST選擇了與Dilithium具備不同特性的另一個晶格基簽章——&lt;strong>FALCON (Fast-Fourier Lattice-based Compact Signatures over NTRU)&lt;/strong>，作為標準化候選者（目前正作為FN-DSA制定草案中）。&lt;/p>
&lt;h3 id="71-ntru晶格與高斯取樣">7.1. NTRU晶格與高斯取樣
&lt;/h3>&lt;p>FALCON最大的特徵在於，它使用的不是LWE問題，而是從1996年就存在、歷史悠久的&lt;strong>NTRU (N-th degree Truncated polynomial Ring Units) 晶格&lt;/strong>。此外，它採用了基於GPV (Gentry-Peikert-Vaikuntanathan) 框架的「&lt;strong>雜湊與簽章 (Hash-and-Sign)&lt;/strong>」典範。&lt;/p>
&lt;p>在Hash-and-Sign中，會將訊息的雜湊值作為空間內的目標點，並尋找晶格上最接近該點的點（最近向量問題的近似解）來作為簽章。為此，必須使用作為秘密金鑰的「高品質的短基底」，並依據離散高斯分佈進行點的取樣。&lt;/p>
&lt;p>FALCON利用被稱為「&lt;strong>快速傅立葉正交化 (Fast Fourier Orthogonalization: FFO)&lt;/strong>」的手法，將這種繁重的計算進行了劇烈的加速。&lt;/p>
&lt;h3 id="72-falcon的優缺點">7.2. FALCON的優缺點
&lt;/h3>&lt;p>FALCON壓倒性的優勢在於其&lt;strong>簽章尺寸與公開金鑰尺寸極為精巧（Compact）&lt;/strong>。相較於Dilithium3的簽章尺寸約為3,309位元組，FALCON-512的簽章尺寸僅有約666位元組。公開金鑰也非常小，只有897位元組，在通訊頻寬極度受限的環境、IoT裝置，或是特定的網路協定中，它將成為救星。&lt;/p>
&lt;p>然而，它存在一個重大的缺點。由於生成簽章時必須進行伴隨著複雜**浮點數運算（64-bit IEEE 754）**的離散高斯取樣，使得要防止計時外洩的常數時間實作（Constant-time implementation）變得極為困難，程式碼也會變得龐大。因此，FALCON相對於通用型（Dilithium），定位為專為特定用途設計的強大特化型演算法。&lt;/p>
&lt;div class="mermaid">graph LR
A["數位簽章的需求"] --> B{"最優先的限制條件是？"}
B -->|"實作的簡單性、通用性、常數時間實作的容易度"| C["Dilithium (ML-DSA)"]
B -->|"通訊頻寬的最小化、資料尺寸的精巧度"| D["FALCON (FN-DSA)"]
C --> E["通用的TLS憑證、軟體的電子簽章"]
D --> F["封包尺寸限制嚴格的協定、特殊環境"]&lt;/div>
&lt;hr>
&lt;h2 id="8-sphincs-slh-dsa擁有最強安全性的雜湊基簽章">8. SPHINCS+ (SLH-DSA)：擁有最強安全性的雜湊基簽章
&lt;/h2>&lt;p>為了防範未來晶格密碼的安全性被天才數學家的突破所瓦解的最壞情況（萬一發生），NIST制定了與晶格密碼方法完全不同的標準 &lt;strong>FIPS 205 (SLH-DSA)&lt;/strong>，也就是 &lt;strong>SPHINCS+&lt;/strong>。&lt;/p>
&lt;p>SPHINCS+被分類為&lt;strong>雜湊基簽章&lt;/strong>。其安全性基礎僅依賴於「所使用的密碼學雜湊函數（如SHA-2或SHAKE256等）具備抗碰撞性與單向性」這一點上。因為它不依賴如LWE或整數分解等具有特定代數結構的數學問題，所以未來無論出現多麼強大的量子演算法，只需單純增加雜湊函數的輸出長度就能對抗，擁有極度強固的安全性（最保守的安全等級）。&lt;/p>
&lt;h3 id="81-wots-與-fors-的無狀態架構">8.1. WOTS+ 與 FORS 的無狀態架構
&lt;/h3>&lt;p>雜湊基簽章的歷史悠久，可追溯至1970年代的Lamport簽章與Winternitz單次簽章（WOTS）。這些都是「只能安全簽章1次」的拋棄式金鑰。為了使其能使用多次，開發了結合默克爾樹（Merkle Tree），將無數的單次金鑰透過一個根雜湊來管理的XMSS（eXtended Merkle Signature Scheme）與LMS等演算法。&lt;/p>
&lt;p>然而，XMSS與LMS有一個致命的缺點，那就是它們是「&lt;strong>有狀態的 (Stateful)&lt;/strong>」。每次簽章時，都必須將「使用了第幾個單次金鑰」的索引狀態嚴格記錄在非揮發性記憶體中。如果因為虛擬機器的快照還原等原因導致狀態回溯，而不小心使用了同一個單次金鑰兩次，秘密金鑰就會立刻外洩，導致系統崩潰。&lt;/p>
&lt;p>SPHINCS+解決了這種狀態管理的麻煩，是一種「&lt;strong>無狀態 (Stateless)&lt;/strong>」的雜湊基簽章。
其核心技術是以下技術的組合：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>WOTS+ (Winternitz One-Time Signature Plus)&lt;/strong>：基本的單次簽章。&lt;/li>
&lt;li>&lt;strong>FORS (Forest of Random Subsets)&lt;/strong>：少次簽章（Few-Time Signature）技術。同一個金鑰重複使用幾次仍能保持安全。&lt;/li>
&lt;li>&lt;strong>Hyper-Tree (巨大樹狀結構)&lt;/strong>：將默克爾樹多層疊加的巨大結構。&lt;/li>
&lt;/ol>
&lt;p>在進行簽章時，SPHINCS+不進行狀態管理，而是從Hyper-Tree底層數量龐大的FORS金鑰中，利用偽亂數隨機挑選一個來進行簽章。由於樹葉的數量達到天文數字，不小心挑選到同一個金鑰的機率（碰撞）小到可以忽略，結果成功實現了無狀態設計。&lt;/p>
&lt;p>SPHINCS+唯一也是最大的弱點在於，&lt;strong>簽章尺寸非常巨大&lt;/strong>。依據參數不同，簽章尺寸會達到17KB～49KB，且簽章生成速度與晶格密碼相比也壓倒性地慢。因此，相較於日常的網頁瀏覽，它更適合用於軟體更新簽章或根憑證授權單位（CA）憑證等，不需頻繁簽章且強烈要求長期絕對安全性的用途。&lt;/p>
&lt;hr>
&lt;h2 id="9-編碼基密碼classic-mceliece這位美好的老巨人">9. 編碼基密碼：Classic McEliece這位美好的老巨人
&lt;/h2>&lt;p>在NIST的標準化流程中，目前作為Round 4最終候選者持續接受評估的重要方法，是&lt;strong>編碼基密碼&lt;/strong>的&lt;strong>Classic McEliece&lt;/strong>。&lt;/p>
&lt;p>這個由Robert McEliece於1978年提出的演算法，在公開金鑰密碼的歷史中與RSA並列為最古老的演算法之一。它利用了被稱為「Goppa碼（戈帕碼）」的代數幾何碼，刻意在訊息中加入錯誤（雜訊向量）進行加密，只有擁有Goppa碼同位檢查矩陣作為秘密金鑰的人，才能利用強大的錯誤更正能力去除錯誤，解密出原始訊息，這是基於「&lt;strong>症狀解碼問題 (Syndrome Decoding Problem)&lt;/strong>」。&lt;/p>
$$ \vec{c} = \vec{m} G + \vec{e} $$
&lt;p>
（$G$ 為公開金鑰，即打亂後的生成矩陣，$\vec{e}$ 為權重為 $t$ 的錯誤向量）&lt;/p>
&lt;p>Classic McEliece令人驚訝之處在於，&lt;strong>從提出至今已經超過40年，歷經全球密碼學家猛烈的破解研究，卻從未被發現有本質上的漏洞&lt;/strong>，擁有壓倒性的實績。它是PQC中擁有「最經過時間考驗的強固安全性」的演算法。&lt;/p>
&lt;p>此外，它還具備密文尺寸非常小（僅約100～200位元組）的優點。然而，它存在一個致命的缺點，就是&lt;strong>公開金鑰的尺寸會達到MB (Megabyte) 等級&lt;/strong>。即便是最低的安全級別（相當於AES-128），公開金鑰也大約有250KB，而在更高的安全級別中會超過1MB。&lt;/p>
&lt;p>因此，它完全無法適用於像TLS交握這種每次通訊都需要在網路上傳送公開金鑰的用途。不過，在VPN的預先共享金鑰交換、將公開金鑰硬編碼到韌體中，或是衛星通訊等可以預先將公開金鑰部署在系統中的特殊使用案例裡，由於其強固的安全性，它仍持續被視為極具潛力的選擇。&lt;/p>
&lt;hr>
&lt;h2 id="10-各pqc演算法的效能比較與取捨">10. 各PQC演算法的效能比較與取捨
&lt;/h2>&lt;p>針對目前為止解說過的主要演算法，在一般安全級別（相當於NIST Level 2〜3，AES-128〜192級別）下的效能特性整理如下表。&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">演算法 (標準名稱)&lt;/th>
&lt;th style="text-align:left">類別&lt;/th>
&lt;th style="text-align:left">數學基礎&lt;/th>
&lt;th style="text-align:left">公開金鑰尺寸&lt;/th>
&lt;th style="text-align:left">秘密金鑰尺寸&lt;/th>
&lt;th style="text-align:left">密文/簽章尺寸&lt;/th>
&lt;th style="text-align:left">處理速度傾向&lt;/th>
&lt;th style="text-align:left">主要特徵與用途&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">非常快&lt;/td>
&lt;td style="text-align:left">金鑰尺寸與速度平衡最佳。TLS 1.3等的通用KEM標準。&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">簽章&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">生成與驗證皆快&lt;/td>
&lt;td style="text-align:left">實作簡單。通用的數位簽章標準。&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">簽章&lt;/td>
&lt;td style="text-align:left">NTRU晶格&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">簽章生成偏慢，驗證超快&lt;/td>
&lt;td style="text-align:left">簽章尺寸極小。但需要浮點數運算。適合嵌入式、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">簽章&lt;/td>
&lt;td style="text-align:left">雜湊函數&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">約 17,000 Bytes&lt;/td>
&lt;td style="text-align:left">生成非常慢&lt;/td>
&lt;td style="text-align:left">數學破綻風險幾乎為零。根憑證等高安全需求用途。&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碼&lt;/td>
&lt;td style="text-align:left">&lt;strong>約 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">封裝快&lt;/td>
&lt;td style="text-align:left">40年安全性實績。公開金鑰巨大。適合可硬編碼的環境。&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="理解取捨-trade-offs">理解取捨 (Trade-offs)
&lt;/h3>&lt;p>在PQC的世界裡，不存在「尺寸小、速度快且數學保證完美」這種魔法般的單一演算法。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>網際網路標準 (Kyber / Dilithium)&lt;/strong>：效能平衡最好，最適合目前RSA/ECC的直接替換（Drop-in replacement）。&lt;/li>
&lt;li>&lt;strong>極致的保守性 (SPHINCS+)&lt;/strong>：在犧牲資料尺寸與處理速度的情況下，為了防範未來的數學突破而選擇的絕對保險。&lt;/li>
&lt;li>&lt;strong>針對特殊環境 (FALCON / Classic McEliece)&lt;/strong>：為了適應通訊頻寬極度狹窄，或是可以預先派發金鑰等環境限制所選擇的特化型武器。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="11-邁向實用化的課題與混合密碼的現實解方">11. 邁向實用化的課題與「混合密碼」的現實解方
&lt;/h2>&lt;p>隨著NIST完成標準化並正式發布FIPS標準，全球IT基礎設施的PQC過渡（&lt;strong>PQC轉移 (PQC Migration)&lt;/strong>）已正式展開。Google的Chrome瀏覽器、Apple的iMessage（PQ3協定）以及Cloudflare等網路供應商，已經將PQC的支援實作到協定中並開始實際上線運作。&lt;/p>
&lt;p>然而，突然完全切換到新的密碼演算法伴隨著極高的風險。假設幾年後有天才數學家對Kyber等晶格密碼發現了致命的攻擊手法（如在古典電腦上也能解開的數學缺陷），那麼依賴該演算法的整個系統就會在一瞬間形同裸奔。&lt;/p>
&lt;p>為減輕這種不確定性風險，既現實又被推薦的方法就是「&lt;strong>混合密碼 (Hybrid Cryptography)&lt;/strong>」。&lt;/p>
&lt;p>在混合密碼中，會同時使用擁有長年實績的現行古典密碼（例如：X25519等橢圓曲線密碼）與新的PQC（例如：Kyber768）來進行金鑰交換。各演算法分別生成共同金鑰成分，最後再使用安全的金鑰衍生函數（KDF）將兩個成分混合，生成最終的主秘密金鑰 (Master Secret)。&lt;/p>
&lt;div class="mermaid">graph TD
A["客戶端"] -->|① 傳送 X25519 的公開金鑰 + Kyber 的公開金鑰| B["伺服器"]
B -->|② 回傳 X25519 的共享金鑰 + Kyber 的封裝密文| A
A --> C{"衍生主秘密金鑰 (KDF)"}
B --> C
C -->|輸入: (X25519 的共同金鑰) || (Kyber 的共同金鑰)| D["安全的通訊金鑰 (AES-256 / ChaCha20)"]
D -->|"同時抵抗 量子威脅 ＆ 古典漏洞"| E["安全的混合密碼通訊 (TLS 1.3)"]&lt;/div>
&lt;p>透過這種方式，就能實現「萬一量子電腦實現且ECC被破解，還有Kyber能保護通訊」，反之「萬一Kyber被發現有未知數學缺陷，還有ECC能保護通訊」這種堅固的雙重防護安全性。代表性的例子就是IETF正在進行標準化的 &lt;strong>X25519MLKEM768 (舊稱 X25519Kyber768)&lt;/strong> 草案，目前網頁瀏覽器與最先進的伺服器之間的通訊，正是採用這種混合方式。&lt;/p>
&lt;p>此外，在系統設計時，建立「不過度依賴特定密碼演算法，當演算法崩潰時能迅速切換到另一個演算法（如從Kyber切換到McEliece，從Dilithium切換到SPHINCS+）的架構」，這種被稱為 &lt;strong>密碼敏捷性 (Crypto Agility)&lt;/strong> 的概念，將成為未來系統開發中不可或缺的需求。&lt;/p>
&lt;hr>
&lt;h2 id="12-總結密碼技術的新視野">12. 總結：密碼技術的新視野
&lt;/h2>&lt;p>量子電腦這項人類夢想中的科技，諷刺地成為了打破我們長年信賴的「整數分解」與「離散對數問題」等數學防壁的最大威脅。然而，世界各地的密碼學家並沒有因此屈服，反而開拓了晶格理論、雜湊函數樹、錯誤更正碼等更複雜深奧的多維數學領域，築起了名為抗量子密碼學（PQC）的新防線。&lt;/p>
&lt;p>NIST完成 FIPS 203 (ML-KEM)、FIPS 204 (ML-DSA)、FIPS 205 (SLH-DSA) 的標準化並非終點，這只是接下來將持續數十年的PQC轉移這趟壯闊旅程的第一步。對軟體工程師與系統架構師而言，如何將這些新演算法帶來的「金鑰尺寸增加」與「運算成本改變」最佳地適應到網路協定與系統中，將是未來的重大技術課題。&lt;/p>
&lt;p>量子電腦與密碼的戰爭，是人類數學探索與科技進化最激烈交會的刺激領域。希望透過本文，能讓您深入了解PQC背後優美的數學理論，以及形塑網路安全未來的各演算法令人驚嘆的機制。&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>量子電腦實用化之日：2026年的現狀</title><link>http://kenji.blog/zh-tw/p/quantum-computing-2026-current-status/</link><pubDate>Fri, 11 Sep 2026 06:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/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 量子電腦實用化之日：2026年的現狀" />&lt;h2 id="1-前言2026年量子電腦發展到了什麼程度">1. 前言：2026年，量子電腦發展到了什麼程度
&lt;/h2>&lt;p>2026年現在，量子運算已經從過去的「理論上的夢想」經歷了決定性的轉變，成為了「工程上的現實」。隨著幾年前仍是主流的**NISQ（Noisy Intermediate-Scale Quantum，雜訊中型量子）**裝置的極限變得明確，世界各地的研究機構與科技巨頭已將發展方向轉向實現「容錯量子運算（FTQC: Fault-Tolerant Quantum Computing）」。&lt;/p>
&lt;p>在本文中，我們將結合2026年的最新突破，深入探討量子電腦的現狀。特別是將詳細解說量子錯誤更正（表面碼）、物理量子位元與邏輯量子位元的差異、拓撲量子運算的進展，以及超導與離子阱方式的最前線。&lt;/p>
&lt;hr>
&lt;h2 id="2-量子態的基礎與保真度fidelity">2. 量子態的基礎與保真度（Fidelity）
&lt;/h2>&lt;p>作為量子電腦基本單位的量子位元（Qubit），不同於古典位元（0或1），可以呈現0與1的疊加態（Superposition）。單一量子位元的狀態在希爾伯特空間中以向量表示如下：&lt;/p>
$$
|\psi\rangle = \alpha|0\rangle + \beta|1\rangle
$$
&lt;p>這裡，$\alpha$ 與 $\beta$ 為複數的機率幅，並滿足以下的歸一化條件：&lt;/p>
$$
|\alpha|^2 + |\beta|^2 = 1
$$
&lt;p>在衡量量子運算效能時，一個極為重要的指標是&lt;strong>保真度（Fidelity）&lt;/strong>。理想的量子態 $|\psi\rangle$ 與受到雜訊退化而成為混合態的實際密度矩陣 $\rho$ 之間的保真度 $F$ 定義如下：&lt;/p>
$$
F(\rho, |\psi\rangle) = \langle \psi | \rho | \psi \rangle
$$
&lt;p>在2026年的現在，2量子位元閘（例如：CNOT閘或CZ閘）的保真度，在超導方式中已能穩定突破**99.99%**的障壁（即所謂的「四個九」）。這大幅超越了表面碼進行錯誤更正的閾值（約99%），是邁向實用化的最大突破之一。&lt;/p>
&lt;hr>
&lt;h2 id="3-nisq時代的極限與向ftqc的典範轉移">3. NISQ時代的極限與向FTQC的典範轉移
&lt;/h2>&lt;p>從2010年代後半到2020年代前半，是屬於不具備錯誤更正、擁有數十至數百個量子位元裝置的NISQ（Noisy Intermediate-Scale Quantum）時代。然而，NISQ有著明確的極限。&lt;/p>
&lt;p>隨著電路深度（Depth）增加，錯誤會呈指數級累積，使得獲得有意義的運算結果變得不可能。在電路深度 $D$ 下的整體成功機率 $P_{success}$，相對於單一閘的保真度 $f$ 與閘的數量 $N$，會以下列方式衰減：&lt;/p>
$$
P_{success} \approx f^N
$$
&lt;p>如果 $f = 0.99$ 且套用了1000個閘，則 $0.99^{1000} \approx 4.3 \times 10^{-5}$，結果將幾乎被隨機雜訊所掩蓋。因此，在2026年，比起直接擴展NISQ演算法（如VQE或QAOA），資源更集中於**邏輯量子位元（Logical Qubit）**的生成。&lt;/p>
&lt;hr>
&lt;h2 id="4-量子錯誤更正與邏輯量子位元表面碼的最前線">4. 量子錯誤更正與邏輯量子位元：表面碼的最前線
&lt;/h2>&lt;p>量子錯誤更正（QEC: Quantum Error Correction）是一種將多個「物理量子位元」編碼以創造出1個「邏輯量子位元」，並檢測與更正錯誤的技術。目前最被看好的是&lt;strong>表面碼（Surface Code）&lt;/strong>。&lt;/p>
&lt;h3 id="41-表面碼surface-code的結構">4.1 表面碼（Surface Code）的結構
&lt;/h3>&lt;p>在表面碼中，量子位元被配置為二維的網格狀。資料量子位元（保存實際資訊）與測量量子位元（用於症狀測量）如棋盤格般排列。&lt;/p>
&lt;div class="mermaid">graph TD
A["資料量子位元 (D1)"] --- B["測量量子位元 (M1)"]
B --- C["資料量子位元 (D2)"]
C --- D["測量量子位元 (M2)"]
D --- E["資料量子位元 (D3)"]
B --- F["資料量子位元 (D4)"]
D --- G["資料量子位元 (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>利用穩定子算符 $S_x$ 與 $S_z$，持續監控位元反轉（X錯誤）與相位反轉（Z錯誤）。&lt;/p>
$$
S_x = \prod_{i \in \text{star}} X_i, \quad S_z = \prod_{j \in \text{plaquette}} Z_j
$$
&lt;p>2026年的重大進展，是完全突破了「損益平衡點（Break-even point）」。也就是說，因執行錯誤更正而消除的雜訊，已大於額外電路所引入的雜訊，使得邏輯量子位元的壽命比物理量子位元的壽命高出了好幾個數量級。&lt;/p>
&lt;h3 id="42-量子錯誤更正的循環">4.2 量子錯誤更正的循環
&lt;/h3>&lt;p>錯誤更正作為一個持續的回饋迴圈運作。&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant D as "資料量子位元"
participant M as "輔助/測量量子位元"
participant C as "古典控制器"
loop "症狀提取循環 (約 1 微秒)"
D->>M: "糾纏 (CNOT/CZ)"
M->>C: "測量狀態 (症狀)"
C->>C: "解碼症狀 (例如：最小權重完美匹配)"
C-->>D: "應用包立更正 (如有必要)"
end&lt;/div>
&lt;p>現在，使用FPGA或專用ASIC以奈秒為單位執行這種古典解碼處理（症狀分析）的技術已經確立，即時錯誤更正已進入實用階段。&lt;/p>
&lt;hr>
&lt;h2 id="5-硬體架構的進化2026年版">5. 硬體架構的進化（2026年版）
&lt;/h2>&lt;p>2026年的量子硬體主要在「超導方式」、「離子阱方式」及「拓撲方式」三個軸向上持續進化。&lt;/p>
&lt;h3 id="51-超導量子位元的整合">5.1 超導量子位元的整合
&lt;/h3>&lt;p>超導方式是由IBM與Google領軍的領域，主要使用以約瑟夫森接面（Josephson Junction）構成的傳輸子（Transmon）量子位元。2026年，在單一晶片上整合數千至一萬個物理量子位元的巨型晶片已經實現。&lt;/p>
&lt;p>值得特別提及的是**模組間量子通訊（Quantum Interconnects）**的確立。使用微波光子進行晶片間的量子遙傳已達商業級實作，使得繞過單一稀釋冷凍機的尺寸限制成為可能。&lt;/p>
&lt;h3 id="52-離子阱的二維擴展與光互連">5.2 離子阱的二維擴展與光互連
&lt;/h3>&lt;p>離子阱方式（由Quantinuum與IonQ等主導）使用懸浮在真空中的離子的內部能量狀態作為量子位元。與超導方式相比，其具有T1/T2同調時間極長，且可實現全連接（All-to-All Connectivity）的優點。&lt;/p>
&lt;p>2026年的突破在於QCCD（Quantum Charge Coupled Device）架構的二維化，以及利用光子互連（Photonic Interconnects）在多個阱之間快速生成糾纏。這大幅改善了過去離子阱在「閘速度緩慢」與「擴展性」上的弱點。&lt;/p>
&lt;h3 id="53-拓撲量子運算任意子的控制">5.3 拓撲量子運算：任意子的控制
&lt;/h3>&lt;p>長期以來被認為僅存在於理論上的&lt;strong>拓撲量子運算&lt;/strong>，終於在2026年進入了實驗證實的階段。由Microsoft等推動的此種方式，使用了被稱為「馬約拉納零模（Majorana Zero Modes）」的非阿貝爾任意子（Non-Abelian Anyons）。&lt;/p>
&lt;p>透過交換任意子粒子位置的「編織（Braiding）」操作來執行量子閘。&lt;/p>
$$
|\psi_{final}\rangle = B_{ij} |\psi_{initial}\rangle
$$
&lt;p>這裡 $B_{ij}$ 為編織算符。拓撲方式由於資訊的保存不依賴於粒子的局部狀態，而是依賴整體「紐結」的拓撲結構，因此在本質上對環境雜訊具有抵抗力（硬體級別的容錯性）。2026年，世界上首次確認了高保真度拓撲邏輯量子位元的生成，作為通往FTQC的強大捷徑而備受矚目。&lt;/p>
&lt;hr>
&lt;h2 id="6-邁向實用化的路線圖與展望">6. 邁向實用化的路線圖與展望
&lt;/h2>&lt;p>為了讓量子電腦在「化學計算」、「材料科學」、「金融建模」等領域中，真正展現出壓倒古典電腦（超級電腦）的&lt;strong>量子霸權（Quantum Advantage）&lt;/strong>，需要數千個邏輯量子位元。&lt;/p>
&lt;div class="mermaid">gantt
title "量子運算路線圖 (2026年修訂版)"
dateFormat YYYY
axisFormat %Y
section "NISQ 時代"
"含雜訊的量子位元 (&lt;1000)" :done, 2018, 2024
section "早期 FTQC"
"突破損益平衡點的展示" :done, 2024, 2026
"數百個邏輯量子位元" :active, 2026, 2028
section "全面 FTQC"
"1000+ 個邏輯量子位元 (商業應用)" : 2028, 2030
"通用容錯量子電腦" : 2030, 2035&lt;/div>
&lt;h3 id="61-目前面臨的挑戰與未來">6.1 目前面臨的挑戰與未來
&lt;/h3>&lt;p>2026年最大的挑戰，在於維持極低溫的巨大低溫恆溫器（稀釋冷凍機）的冷卻能力，以及連接室溫控制裝置與極低溫量子晶片的線路（I/O瓶頸）。為了解決這個問題，能在極低溫環境下運作的CMOS（Cryo-CMOS）控制器晶片的開發正以極快的速度推進。&lt;/p>
&lt;h3 id="結論">結論
&lt;/h3>&lt;p>2026年將被記錄為量子電腦歷史上的「邏輯量子位元擴展元年」。藉由錯誤更正演算法的證實、硬體的模組化，以及拓撲方法的快速進展，「實用化的日子」已不再是遙遠未來的空談，而是可以在未來數年內預見的具體里程碑。對於量子演算法的開發者與企業而言，現在正是正式投資於量子原生解決方案的最佳時機。&lt;/p>
&lt;hr>
&lt;p>&lt;em>本文是基於2026年最新的量子運算研究論文與業界動態所撰寫。&lt;/em>&lt;/p></description></item></channel></rss>