<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Cryptography on kenji.blog</title><link>http://kenji.blog/zh-tw/tags/cryptography/</link><description>Recent content in Cryptography on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>zh-tw</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 21:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/zh-tw/tags/cryptography/index.xml" rel="self" type="application/rss+xml"/><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>密碼學的歷史：從凱撒密碼到後量子密碼（PQC）</title><link>http://kenji.blog/zh-tw/p/history-of-cryptography-caesar-to-pqc/</link><pubDate>Fri, 11 Sep 2026 15:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/p/history-of-cryptography-caesar-to-pqc/</guid><description>&lt;img src="http://kenji.blog/p/history-of-cryptography-caesar-to-pqc/img/eyecatch.jpg" alt="Featured image of post 密碼學的歷史：從凱撒密碼到後量子密碼（PQC）" />&lt;h1 id="1-簡介什麼是密碼學">1. 簡介：什麼是密碼學？
&lt;/h1>&lt;p>密碼學（Cryptography）是為了保持資訊機密性的一門技術，它伴隨著人類歷史不斷演進。從古代戰爭中傳遞秘密指令，到現代網際網路保護信用卡資訊，密碼學的目的始終如一：即「確保只有預期的接收者能理解資訊，而第三方無法解密」。&lt;/p>
&lt;p>在現代資訊安全中，密碼學不僅僅是「隱藏資訊（機密性: Confidentiality）」，它還擔負著確保資料「完整性（Integrity）」、「身分鑑別（Authentication）」與「不可否認性（Non-repudiation）」等重要角色。&lt;/p>
&lt;p>本文將從古代簡單的替換式密碼開始，歷經機械式密碼、現代的對稱金鑰與公開金鑰加密，一直到量子電腦實用化所帶來的「後量子密碼學（PQC）」時代，從技術與數學的角度詳細剖析密碼技術演進的歷史。&lt;/p>
&lt;hr>
&lt;h1 id="2-古典密碼時代文字的替換與重排">2. 古典密碼時代：文字的替換與重排
&lt;/h1>&lt;p>密碼學的起源可追溯至西元前。早期的密碼主要由「換位（重排）」與「替換（代換）」兩種方法構成。&lt;/p>
&lt;h2 id="密碼棒密碼換位式密碼">密碼棒密碼（換位式密碼）
&lt;/h2>&lt;p>西元前 5 世紀古希臘斯巴達所使用的「密碼棒（Scytale）」是最古老的密碼工具之一。將細長的羊皮紙纏繞在特定粗細的木棒上，並在上面橫向寫下訊息。解開羊皮紙後，文字會排列成毫無意義的順序，但擁有相同粗細木棒的接收者只需再次纏繞羊皮紙，便能讀出原始訊息。&lt;/p>
&lt;h2 id="凱撒密碼單表替換式密碼">凱撒密碼（單表替換式密碼）
&lt;/h2>&lt;p>西元前 1 世紀，相傳古羅馬英雄朱利葉斯・凱撒所使用的便是「凱撒密碼」。這是一種將字母平移固定數量（通常為 3 個字母）的單表替換式密碼（Monoalphabetic substitution）。&lt;/p>
&lt;p>在數學上，若將字母視為 $0$ 到 $25$ 的數字，並將平移數量設為 $K$，則從明文 $P$ 轉換為密文 $C$ 的過程可由以下同餘式表示：&lt;/p>
$$C \equiv P + K \pmod{26}$$
&lt;p>解密則是進行反向操作：&lt;/p>
$$P \equiv C - K \pmod{26}$$
&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;/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="c1"># 凱撒密碼的簡單 Python 實作範例&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">caesar_cipher&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">shift&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">mode&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;encrypt&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">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&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">mode&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;decrypt&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">shift&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="n">shift&lt;/span>
&lt;/span>&lt;/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">char&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">text&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">char&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">isalpha&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="nb">ord&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;A&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="n">char&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">isupper&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="nb">ord&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;a&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="c1"># 計算平移&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="nb">chr&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="o">-&lt;/span> &lt;span class="n">base&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">shift&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">26&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">base&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">result&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">char&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>&lt;/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">plaintext&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;HELLO WORLD&amp;#34;&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="n">caesar_cipher&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">plaintext&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;encrypt&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;密文: &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 class="c1"># KHOOR ZRUOG&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>單表替換式密碼後來被 9 世紀阿拉伯學者阿爾・金迪發明的「頻率分析（Frequency Analysis）」輕易破解。這是利用了語言的統計特性，例如在英文中「E」和「T」出現頻率極高。&lt;/p>
&lt;p>為了對抗頻率分析，16 世紀誕生了「維吉尼亞密碼（Vigenère cipher）」。這是一種週期性切換多個平移（金鑰）的多表替換式密碼（Polyalphabetic substitution），大約有 300 年的時間被稱為「無法破解的密碼（Le Chiffre Indéchiffrable）」。&lt;/p>
&lt;p>在數學上，使用明文的第 $i$ 個字母 $P_i$ 以及重複金鑰的第 $i$ 個字母 $K_i$，以如下方式進行加密：&lt;/p>
$$C_i \equiv P_i + K_i \pmod{26}$$
&lt;p>然而進入 19 世紀，查爾斯・巴貝奇與弗里德里希・卡西斯基發明了「卡西斯基試驗（Kasiski examination）」，藉由尋找密文中重複出現的模式來推算出金鑰長度，維吉尼亞密碼也因此被破解。&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "古典密碼的分類"
A["古典密碼"] --> B["換位式密碼"]
A --> C["替換式密碼"]
B --> D["密碼棒密碼"]
C --> E["單表替換式"]
C --> F["多表替換式"]
E --> G["凱撒密碼"]
F --> H["維吉尼亞密碼"]
end&lt;/div>
&lt;hr>
&lt;h1 id="3-機械式密碼與世界大戰恩尼格瑪密碼機與其破解">3. 機械式密碼與世界大戰：恩尼格瑪密碼機與其破解
&lt;/h1>&lt;p>進入 20 世紀後，通訊手段從書信轉變為電報與無線電，對加密的速度與複雜度也產生了更高的需求。這時結合了轉子（旋轉盤）的「機械式密碼」便應運而生。&lt;/p>
&lt;h2 id="恩尼格瑪密碼機enigma的威脅">恩尼格瑪密碼機（Enigma）的威脅
&lt;/h2>&lt;p>第二次世界大戰期間，納粹德國使用的「恩尼格瑪密碼機（Enigma）」是密碼學史上最著名的密碼機。恩尼格瑪密碼機由多個轉子（通常為 3 到 4 個）、用來交換字母線路的接線板（Steckerbrett），以及反射器（反轉轉子）所構成。&lt;/p>
&lt;p>由於在鍵盤上每敲擊一個字母，轉子就會旋轉，因此即使連續敲擊相同的字母，也會輸出不同的密碼字母（多表替換式密碼的極致）。其金鑰空間（設定組合）高達約 $1.58 \times 10^{19}$ 種（約 1580 京），以當時的技術被認為不可能透過暴力破解法解密。&lt;/p>
&lt;h2 id="艾倫圖靈與炸彈機bombe">艾倫・圖靈與「炸彈機（Bombe）」
&lt;/h2>&lt;p>挑戰這台堅不可摧的恩尼格瑪密碼機的，是繼承了波蘭數學家馬里安・雷耶夫斯基等人初期成果的英國布萊切利園密碼破解團隊。&lt;/p>
&lt;p>尤其是艾倫・圖靈（Alan Turing），他利用對應部分密文的明文猜測（Crib），開發出了機電式的破解機「炸彈機（Bombe）」。炸彈機藉由高速檢測邏輯矛盾，不斷排除不可能的轉子設定，成功破解了恩尼格瑪密碼機。這項偉大的成就據說讓同盟國的勝利提早了幾年。&lt;/p>
&lt;hr>
&lt;h1 id="4-現代密碼學的開端對稱金鑰加密des-與-aes">4. 現代密碼學的開端：對稱金鑰加密（DES 與 AES）
&lt;/h1>&lt;p>戰後，隨著電腦的出現，密碼學從「文字」的操作經歷了戲劇性的典範轉移，變成了「位元（0 與 1）」的操作。&lt;/p>
&lt;h2 id="克勞德夏農與資訊理論">克勞德・夏農與資訊理論
&lt;/h2>&lt;p>1949 年，克勞德・夏農發表了論文《保密系統的通訊理論》，奠定了現代密碼學的數學基礎。他提出了安全密碼設計的兩大原則：「混淆（Confusion）」與「擴散（Diffusion）」。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>混淆（Confusion）&lt;/strong>: 讓金鑰與密文之間的關係盡可能變得複雜。（透過替換、S盒來實現）&lt;/li>
&lt;li>&lt;strong>擴散（Diffusion）&lt;/strong>: 讓明文的 1 個位元的改變能夠影響密文中的許多位元。（透過換位、重排來實現）&lt;/li>
&lt;/ul>
&lt;h2 id="des-data-encryption-standard">DES (Data Encryption Standard)
&lt;/h2>&lt;p>1977 年，美國國家標準暨技術研究院（NIST，當時稱 NBS）制定了以 IBM 設計為基礎的「DES」作為標準密碼。
DES 採用了稱為「費斯妥網路（Feistel Network）」的架構，具備 64 位元的區塊長度與 56 位元的金鑰長度。它在實作上的優勢在於加密與解密的演算法結構幾乎完全相同。&lt;/p>
&lt;p>然而，隨著電腦運算能力的提升，56 位元的金鑰長度（約 $7.2 \times 10^{16}$ 種組合）被證實是不夠的。1998 年，電子前哨基金會（EFF）開發了專用機器「Deep Crack」，僅在幾天內就成功破解了 DES。&lt;/p>
&lt;h2 id="aes-advanced-encryption-standard">AES (Advanced Encryption Standard)
&lt;/h2>&lt;p>為了取代 DES 成為新的標準，2001 年制定了「AES」。它採用了透過公開徵選選出的比利時密碼學家設計的「Rijndael」演算法。&lt;/p>
&lt;p>AES 並非採用費斯妥結構，而是採用了「SPN 結構（Substitution-Permutation Network）」，並利用了伽羅瓦體（有限體） $GF(2^8)$ 上的數學運算。金鑰長度可選擇 128、192、256 位元，至今仍是全世界廣泛使用的標準對稱金鑰加密演算法。&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "AES的一輪處理 (SPN結構)"
A["輸入狀態 (128-bit)"] --> B("SubBytes (位元組替換 / S-Box)")
B --> C("ShiftRows (列平移)")
C --> D("MixColumns (行混合 / GF(2^8)上的乘法)")
D --> E("AddRoundKey (與回合金鑰進行 XOR)")
E --> F["前往下一輪"]
end&lt;/div>
&lt;hr>
&lt;h1 id="5-公開金鑰加密的革命從-diffie-hellman-到-rsa">5. 公開金鑰加密的革命：從 Diffie-Hellman 到 RSA
&lt;/h1>&lt;p>對稱金鑰加密存在一個致命的弱點，那就是「金鑰配送問題（Key Distribution Problem）」。也就是在開始加密通訊之前，如何與遠方的對象安全地共享「對稱金鑰」的問題。解決這個問題的正是 1970 年代誕生的「公開金鑰加密」。&lt;/p>
&lt;h2 id="diffie-hellman-金鑰交換">Diffie-Hellman 金鑰交換
&lt;/h2>&lt;p>1976 年，惠特菲爾德・迪菲與馬丁・赫爾曼發表了劃時代的論文《密碼學的新方向》。他們利用了「離散對數問題（Discrete Logarithm Problem）」的數學困難性，提出了一種即使在被竊聽的通訊路徑上，也能安全共享金鑰的方法。&lt;/p>
&lt;ol>
&lt;li>公開一個大質數 $p$ 與生成元 $g$。&lt;/li>
&lt;li>Alice 選擇一個秘密值 $a$，並將 $A = g^a \pmod{p}$ 傳送給 Bob。&lt;/li>
&lt;li>Bob 選擇一個秘密值 $b$，並將 $B = g^b \pmod{p}$ 傳送給 Alice。&lt;/li>
&lt;li>Alice 計算 $K = B^a \pmod{p}$，Bob 計算 $K = A^b \pmod{p}$。&lt;/li>
&lt;li>根據指數定律 $K = (g^b)^a = (g^a)^b = g^{ab} \pmod{p}$，兩人完美地共享了相同的金鑰 $K$。&lt;/li>
&lt;/ol>
&lt;h2 id="rsa-加密">RSA 加密
&lt;/h2>&lt;p>隔年 1977 年，由羅納德・李維斯特、阿迪・薩莫爾和倫納德・阿德曼三人發明了「RSA 加密」。這是基於「巨大的合成數的質因數分解十分困難」的特性。&lt;/p>
&lt;p>&lt;strong>RSA 的數學原理:&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>選擇兩個巨大的質數 $p$ 與 $q$，並計算 $n = p \times q$。&lt;/li>
&lt;li>計算尤拉商數函數 $\phi(n) = (p-1)(q-1)$。&lt;/li>
&lt;li>選擇與 $\phi(n)$ 互質的整數 $e$（公開金鑰）。&lt;/li>
&lt;li>計算能滿足 $e \times d \equiv 1 \pmod{\phi(n)}$ 的整數 $d$（私有金鑰）。&lt;/li>
&lt;/ol>
&lt;p>加密: 對於明文 $M$，計算 $C \equiv M^e \pmod{n}$
解密: 對於密文 $C$，計算 $M \equiv C^d \pmod{n}$&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;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="c1"># 示範 RSA 加密概念的 Python 程式碼（不適用於實際用途）&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">ext_euclid&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="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">b&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="mi">1&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">a&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &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">g&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ext_euclid&lt;/span>&lt;span class="p">(&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 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">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="p">(&lt;/span>&lt;span class="n">a&lt;/span> &lt;span class="o">//&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="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">g&lt;/span>
&lt;/span>&lt;/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">rsa_example&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">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">61&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">53&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>&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">17&lt;/span> &lt;span class="c1"># 與 phi 互質的值&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">_&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ext_euclid&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">d&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">d&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="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;公開金鑰: (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">, 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">)&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=&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">, 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">)&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">message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">65&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="n">decrypted&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>&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">message&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> -&amp;gt; 密文: &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;gt; 解密後: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">decrypted&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">rsa_example&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;h1 id="6-橢圓曲線密碼學ecc的崛起">6. 橢圓曲線密碼學（ECC）的崛起
&lt;/h1>&lt;p>RSA 加密雖然強大，但隨著電腦效能的提升，為了維持安全性必須加長金鑰長度（目前為 2048 位元或 3072 位元），這導致了運算成本增加的問題。&lt;/p>
&lt;p>因此在 1985 年提出了「橢圓曲線密碼學（Elliptic Curve Cryptography: ECC）」。這利用了有限體上橢圓曲線（通常為 $y^2 = x^3 + ax + b$ 形式）的點加法。&lt;/p>
&lt;p>橢圓曲線上的離散對數問題（ECDLP）已知比質因數分解問題更難求解，&lt;strong>ECC 只要 256 位元的金鑰長度，就能實現與 RSA 3072 位元同等的安全性&lt;/strong>。這使得在智慧型手機或 IoT 裝置等運算資源有限的環境中，也能進行高速且安全的加密通訊（如 ECDSA 或 ECDH 等）。&lt;/p>
&lt;hr>
&lt;h1 id="7-量子電腦的威脅與後量子密碼學pqc">7. 量子電腦的威脅與後量子密碼學（PQC）
&lt;/h1>&lt;p>密碼技術看似堅若磐石，但 1994 年由彼得・秀爾（Peter Shor）發表的「秀爾演算法」卻帶來了巨大的衝擊。&lt;/p>
&lt;p>量子電腦利用量子力學的「疊加」與「量子纏結」特性來進行運算。在數學上已經證明，如果在效能足夠的量子電腦上執行秀爾演算法，質因數分解問題與離散對數問題就能在「多項式時間」內被解開。也就是說，在實用的量子電腦問世的那一天（Q-Day），現在所使用的 RSA 或 ECC 等公開金鑰加密都將在瞬間崩潰。&lt;/p>
&lt;h2 id="pqc後量子密碼學的登場">PQC（後量子密碼學）的登場
&lt;/h2>&lt;p>為防範這個前所未有的威脅，基於連量子電腦也難以破解的新數學問題的「後量子密碼學（PQC）」研究正快馬加鞭地進行著。NIST（美國國家標準暨技術研究院）長年來持續推動 PQC 的標準化流程，主要以下列數學方法最具潛力。&lt;/p>
&lt;h3 id="1-晶格密碼學lattice-based-cryptography">1. 晶格密碼學（Lattice-based Cryptography）
&lt;/h3>&lt;p>這是目前最有潛力的方法，也被 NIST 的標準化演算法（ML-KEM / Kyber、ML-DSA / Dilithium）所採用。它基於在多維空間的「晶格（Lattice）」上尋找特定點的問題（如最短向量問題: SVP 等），以及 LWE（Learning With Errors: 錯誤學習）問題的困難性。&lt;/p>
&lt;p>LWE 問題的概念利用了當我們在聯立一次方程式中刻意加入「小雜訊（誤差）」時，求解會瞬間變得極為困難的特性。
方程式系統: $\mathbf{A}\mathbf{s} + \mathbf{e} \equiv \mathbf{b} \pmod{q}$
（$\mathbf{A}$ 與 $\mathbf{b}$ 為公開，$\mathbf{s}$ 為私有金鑰，$\mathbf{e}$ 為極小的雜訊）&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;/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="c1"># LWE 問題的概念性虛擬碼（學習用途）&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">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>&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">256&lt;/span> &lt;span class="c1"># 維度&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="mi">3329&lt;/span> &lt;span class="c1"># 模數&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">m&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">512&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"># 私有金鑰 s 與小誤差 e&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">s&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">np&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">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">e&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">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="o">-&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 class="n">size&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>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 公開矩陣 A 與公開向量 b&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">np&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">0&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">size&lt;/span>&lt;span class="o">=&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">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">b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">dot&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">s&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="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>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 即使使用量子電腦，要從 A 和 b 還原 s 也被認為是非常困難的&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="2-雜湊基礎密碼學hash-based-cryptography">2. 雜湊基礎密碼學（Hash-based Cryptography）
&lt;/h3>&lt;p>這是一種僅以雜湊函數的抗碰撞性作為安全性基礎的數位簽章方案。由於不具備數學結構，因此能有效抵抗量子攻擊，但簽章大小往往較大（如 SPHINCS+ 等）。&lt;/p>
&lt;h3 id="3-編碼基礎密碼學code-based-cryptography">3. 編碼基礎密碼學（Code-based Cryptography）
&lt;/h3>&lt;p>這是一種基於錯誤更正碼理論的加密方式。1978 年提出的 McEliece 加密等較為著名，歷史悠久且安全性備受肯定，但存在公開金鑰尺寸極大（有時高達數 MB）的課題。&lt;/p>
&lt;div class="mermaid">timeline
title "密碼技術與計算機演進的歷史"
"古代至中世" : "凱撒密碼" : "維吉尼亞密碼" : "頻率分析的誕生"
"1930至40年代" : "恩尼格瑪密碼機的運用與破解" : "圖靈機・炸彈機的開發"
"1970年代" : "DES標準化 (1977)" : "Diffie-Hellman金鑰交換 (1976)" : "RSA加密的誕生 (1977)"
"1980至90年代" : "橢圓曲線密碼學 (ECC) 的提出" : "發表秀爾演算法 (1994)"
"2000年代" : "AES標準化 (2001)"
"2010年代至今" : "量子電腦研究加速" : "NIST開始PQC標準化計畫"
"近未來 (Q-Day)" : "大型量子電腦的實現？" : "完全轉移至PQC（ML-KEM/ML-DSA）"&lt;/div>
&lt;hr>
&lt;h1 id="8-結論無止盡的矛盾之爭">8. 結論：無止盡的矛盾之爭
&lt;/h1>&lt;p>密碼技術的歷史，就是發明新加密方式（盾）與破解它的新解密手法（矛）之間無止盡的戰鬥歷史。&lt;/p>
&lt;p>凱撒密碼敗給了頻率分析，號稱無敵的恩尼格瑪密碼機則敗給了圖靈的天才頭腦與機器的力量。而現在，支撐現代網際網路社會根基的 RSA 與 ECC 等強大密碼，也正暴露在量子電腦這個全新的「矛」的威脅之下。&lt;/p>
&lt;p>然而，人類已經放眼未來的下一步，正在準備名為後量子密碼學（PQC）的全新「盾」。目前，在全世界的 IT 基礎設施中，確保從現有公開金鑰加密轉移至 PQC 的準備（確保密碼靈活性，Crypto Agility）已成為當務之急。&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>橢圓曲線密碼學（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></channel></rss>