<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Math on kenji.blog</title><link>http://kenji.blog/zh-tw/tags/math/</link><description>Recent content in Math on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>zh-tw</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 22:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/zh-tw/tags/math/index.xml" rel="self" type="application/rss+xml"/><item><title>【初學者指南】解讀Transformer模型的數學結構</title><link>http://kenji.blog/zh-tw/p/transformer-mathematical-structure/</link><pubDate>Fri, 11 Sep 2026 22:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/p/transformer-mathematical-structure/</guid><description>&lt;img src="http://kenji.blog/p/transformer-mathematical-structure/img/eyecatch.jpg" alt="Featured image of post 【初學者指南】解讀Transformer模型的數學結構" />&lt;h1 id="前言為什麼要學習transformer的數學">前言：為什麼要學習Transformer的數學？
&lt;/h1>&lt;p>可以毫不誇張地說，「Transformer」是改寫了現代自然語言處理（NLP）乃至整個人工智慧歷史的架構。這個模型首次由Google研究人員在2017年的論文《Attention Is All You Need》中提出，現在作為席捲全球的大型語言模型（LLM）——如OpenAI的GPT系列（ChatGPT的底層技術）、Google的BERT以及Anthropic的Claude——的核心運作著。&lt;/p>
&lt;p>然而，現狀是我們經常看到關於Transformer機制的定性解釋，例如「使用Attention（注意力機制）來理解上下文」，但針對初學者深入探討其背後&lt;strong>數學結構&lt;/strong>的解說卻意外地少。為了真正理解AI是如何將「語言」作為「數學公式」進行處理，並生成出令人驚訝地自然的文本，解讀其數學機制是不可或缺的。&lt;/p>
&lt;p>本文針對具備數學和程式設計基礎知識（了解高中程度的矩陣和微分概念）的讀者，將徹底且淺顯易懂地解開Transformer核心的「Self-Attention機制」、「Query-Key-Value（Q/K/V）模型」、「透過Softmax函數進行的正規化」，以及「Positional Encoding」等數學結構。&lt;/p>
&lt;p>你可能會被一連串的數學公式給震撼，但每一個計算都有其明確的「意義」。當你讀完這篇文章時，你應該能夠理解Transformer並不僅僅是一個神奇的黑盒子，而是經過精心設計的數學與統計學結晶。&lt;/p>
&lt;hr>
&lt;h1 id="1-傳統方法的局限性與transformer的創新性">1. 傳統方法的局限性與Transformer的創新性
&lt;/h1>&lt;p>在Transformer出現之前，自然語言處理的主流是遞歸神經網路（RNN）及其衍生模型LSTM（Long Short-Term Memory）。RNN專為處理時間序列資料而設計，會從頭開始依序逐個詞地讀取句子。&lt;/p>
&lt;p>然而，RNN有兩個致命的弱點：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>難以學習長期依賴性&lt;/strong>：當句子變長時，最先輸入的詞彙資訊在到達最後時會變得淡薄（梯度消失問題）。&lt;/li>
&lt;li>&lt;strong>無法平行運算&lt;/strong>：因為必須依序處理詞彙，難以使用GPU進行大規模的平行運算，導致訓練需要耗費大量時間。&lt;/li>
&lt;/ol>
&lt;p>Transformer完全捨棄了RNN的結構，引起了僅使用「Attention」來捕捉上下文的典範轉移。藉此，無論序列長度多長都不會遺失資訊，並且能夠將計算平行化，最大限度地發揮GPU的效能。&lt;/p>
&lt;hr>
&lt;h1 id="2-transformer的整體架構">2. Transformer的整體架構
&lt;/h1>&lt;p>首先，讓我們俯瞰Transformer的整體架構。Transformer大致由「Encoder（編碼器）」和「Decoder（解碼器）」兩個區塊組成。以翻譯任務為例，Encoder將輸入語言（例：英語）轉換為數學的向量表示，而Decoder則根據該向量表示生成輸出語言（例：日語或中文）。&lt;/p>
&lt;p>下圖簡化了Encoder區塊的內部結構。&lt;/p>
&lt;div class="mermaid">graph TD
A["輸入標記 (Input Tokens)"] --> B["輸入嵌入 (Input Embedding)"]
B --> C["位置編碼 (Positional Encoding)"]
C --> D["多頭自注意力機制 (Multi-Head Self-Attention)"]
D --> E["相加與層正規化 (Add &amp; Layer Normalization)"]
E --> F["前饋神經網路 (Feed Forward Network)"]
F --> G["相加與層正規化 (Add &amp; Layer Normalization)"]
G --> H["輸出至下一層 (Output to Next Layer)"]
C -.->|"殘差連接 (Residual Connection)"| E
E -.->|"殘差連接 (Residual Connection)"| G&lt;/div>
&lt;p>從這裡開始，我們將逐步探討各個組件中所進行的數學操作。&lt;/p>
&lt;hr>
&lt;h1 id="3-詞彙的向量化與位置編碼positional-encoding">3. 詞彙的向量化與位置編碼（Positional Encoding）
&lt;/h1>&lt;p>電腦無法直接理解文本。輸入的文本會先被分割為稱為「標記（Token）」的單位，並且每一個標記都會被轉換為固定長度的向量。這就是&lt;strong>Input Embedding&lt;/strong>。&lt;/p>
&lt;h2 id="31-input-embedding-的數學">3.1 Input Embedding 的數學
&lt;/h2>&lt;p>假設詞彙表（Vocabulary）的大小為 $V$，嵌入向量的維度數為 $d_{model}$（在原始論文中 $d_{model} = 512$）。每個詞彙 $w_i$ 將使用嵌入矩陣 $W_E \in \mathbb{R}^{V \times d_{model}}$ 轉換為向量 $x_i \in \mathbb{R}^{d_{model}}$。&lt;/p>
$$ x_i = W_E \cdot \text{one\_hot}(w_i) $$
&lt;p>藉此，整篇文章將被表示為矩陣 $X \in \mathbb{R}^{N \times d_{model}}$（其中 $N$ 是文章的長度）。&lt;/p>
&lt;h2 id="32-positional-encoding位置編碼的必要性與數學公式">3.2 Positional Encoding（位置編碼）的必要性與數學公式
&lt;/h2>&lt;p>Transformer並不像RNN那樣依序處理詞彙，而是同時對所有詞彙進行平行處理。這在計算速度上是個巨大的優勢，但同時也引發了**「詞彙順序（語序）」這個重要資訊會遺失**的問題。例如，「狗咬人」與「人咬狗」，雖然輸入的詞彙集合相同，但意義卻完全不同。&lt;/p>
&lt;p>為了將這個語序資訊提供給模型，所發明的方法就是&lt;strong>Positional Encoding&lt;/strong>。
位於位置 $pos$ 的詞彙之第 $i$ 個維度的Positional Encoding $PE$，是使用以下的三角函數來計算的：&lt;/p>
$$ PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d_{model}}}\right) $$
$$ PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d_{model}}}\right) $$
&lt;p>這裡，$pos$ 是詞彙的位置（$0, 1, 2, \dots, N-1$），$i$ 是向量維度的索引（$0, 1, \dots, d_{model}/2 - 1$）。&lt;/p>
&lt;h3 id="為什麼要使用正弦與餘弦">為什麼要使用正弦與餘弦？
&lt;/h3>&lt;p>乍看之下這似乎是個非常複雜且奇怪的數學公式，但這背後有著深刻的數學原因。透過使用三角函數，模型不僅能學習到**「絕對位置」&lt;strong>，也能夠輕易地學習到&lt;/strong>「相對位置」的差異**。&lt;/p>
&lt;p>回想一下高中數學學過的三角函數加法定理：
&lt;/p>
$$ \sin(\alpha + \beta) = \sin\alpha \cos\beta + \cos\alpha \sin\beta $$
$$ \cos(\alpha + \beta) = \cos\alpha \cos\beta - \sin\alpha \sin\beta $$
&lt;p>從某個位置 $pos$ 偏移距離 $k$ 的位置 $pos + k$ 的Positional Encoding，可以表示為位置 $pos$ 的Positional Encoding的線性組合。也就是說，可以使用矩陣 $M_k$ 寫成如下形式：&lt;/p>
$$ PE_{pos+k} = M_k \cdot PE_{pos} $$
&lt;p>這使得Attention機制能夠透過內積計算，輕鬆辨識出詞彙之間「距離有多遠」的相對距離。此外，結合多個不同波長的正弦與餘弦波，還有一個好處，那就是無論文章多長，都能夠生成出唯一的位置向量。&lt;/p>
&lt;p>最終的輸入矩陣 $X_{input}$，就是將詞彙的嵌入向量與這個位置編碼相加的結果：&lt;/p>
$$ X_{input} = X + PE $$
&lt;hr>
&lt;h1 id="4-self-attention自注意力機制的深奧數學">4. Self-Attention（自注意力機制）的深奧數學
&lt;/h1>&lt;p>終於要進入Transformer最重要的組件：&lt;strong>Self-Attention（自注意力機制）&lt;/strong>。Self-Attention的目的是「計算文章內所有詞彙之間的關聯度，並將各個詞彙的向量更新為考慮了上下文的更豐富表示」。&lt;/p>
&lt;p>這裡常使用「搜尋系統」的比喻：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Query (Q)&lt;/strong>: 查詢（搜尋詞）。「我現在正在尋找什麼資訊？」&lt;/li>
&lt;li>&lt;strong>Key (K)&lt;/strong>: 鍵（標題）。「我擁有什麼資訊？」&lt;/li>
&lt;li>&lt;strong>Value (V)&lt;/strong>: 值（實體）。「我實際提供什麼資訊？」&lt;/li>
&lt;/ul>
&lt;h2 id="41-矩陣-q-k-v-的生成">4.1 矩陣 $Q, K, V$ 的生成
&lt;/h2>&lt;p>對於輸入矩陣 $X \in \mathbb{R}^{N \times d_{model}}$（為了簡化說明，這裡忽略批次大小（batch size）），透過乘上可學習的權重矩陣 $W^Q, W^K, W^V \in \mathbb{R}^{d_{model} \times d_k}$，來計算出查詢 $Q$、鍵 $K$、值 $V$。（通常 $d_k = d_v = d_{model} / h$）&lt;/p>
$$ Q = X W^Q $$
$$ K = X W^K $$
$$ V = X W^V $$
&lt;p>這裡，$Q, K, V$ 全部都是 $\mathbb{R}^{N \times d_k}$ 的矩陣。&lt;/p>
&lt;h2 id="42-attention-score的計算內積">4.2 Attention Score的計算（內積）
&lt;/h2>&lt;p>為了衡量每個詞彙的Query與其他所有詞彙的Key之間有多大程度的關聯，我們計算向量的&lt;strong>內積&lt;/strong>。用矩陣運算來寫的話如下：&lt;/p>
$$ \text{Scores} = Q K^T $$
&lt;p>透過這個計算所得到的矩陣 $\text{Scores} \in \mathbb{R}^{N \times N}$ 中的每個元素 $s_{ij}$，代表了第 $i$ 個詞彙的Query與第 $j$ 個詞彙的Key的內積，也就是「關聯度的強度」。&lt;/p>
&lt;h2 id="43-縮放scale">4.3 縮放（Scale）
&lt;/h2>&lt;p>透過內積計算分數有一個問題：當向量的維度 $d_k$ 變大時，內積的值會變得極端的大或極端的小。&lt;/p>
&lt;p>讓我們用數學來證明這一點。
假設查詢的各個元素 $q \sim \mathcal{N}(0, 1)$，鍵的各個元素 $k \sim \mathcal{N}(0, 1)$ 皆服從獨立的標準常態分佈。
求內積 $q \cdot k = \sum_{i=1}^{d_k} q_i k_i$ 的平均值與變異數。
平均值： $\mathbb{E}[q_i k_i] = \mathbb{E}[q_i] \mathbb{E}[k_i] = 0 \times 0 = 0$，因此總和的平均值也為 $0$。
變異數： $q_i k_i$ 的變異數由獨立性可知 $\text{Var}(q_i k_i) = \mathbb{E}[(q_i k_i)^2] - (\mathbb{E}[q_i k_i])^2 = 1 \times 1 - 0 = 1$。
因此，整個內積的變異數等於維度數 $d_k$。&lt;/p>
$$ \text{Var}(q \cdot k) = d_k $$
&lt;p>當變異數變大時，在之後套用Softmax函數時，最大值以外的梯度會變得極端的小，發生「梯度消失」，導致學習無法進行。
為了防止這種情況，將分數除以 $\sqrt{d_k}$（進行縮放），以保持變異數始終為 $1$。&lt;/p>
$$ \text{Scaled Scores} = \frac{Q K^T}{\sqrt{d_k}} $$
&lt;h2 id="44-透過softmax函數轉換為機率">4.4 透過Softmax函數轉換為機率
&lt;/h2>&lt;p>為了將得到的分數轉換為總和為 $1$ 的機率分佈（權重），我們對每一行套用 &lt;strong>Softmax函數&lt;/strong>。&lt;/p>
$$ a_{ij} = \text{softmax}(s_i)_j = \frac{\exp(s_{ij} / \sqrt{d_k})}{\sum_{m=1}^N \exp(s_{im} / \sqrt{d_k})} $$
&lt;p>矩陣 $A \in \mathbb{R}^{N \times N}$ 被稱為Attention Weight（注意力權重）矩陣。觀察這個矩陣的每一行 $i$，它用 0 到 1 的值表達了「在理解詞彙 $i$ 時，應該對其他哪個詞彙 $j$ 投入多少關注（Attention）」。&lt;/p>
&lt;h2 id="45-value的加權總和">4.5 Value的加權總和
&lt;/h2>&lt;p>最後，使用得到的Attention Weight矩陣 $A$，來計算Value矩陣 $V$ 的加權總和。&lt;/p>
$$ \text{Output} = A V = \text{softmax}\left(\frac{Q K^T}{\sqrt{d_k}}\right) V $$
&lt;p>透過這個運算輸出的矩陣 $Z \in \mathbb{R}^{N \times d_v}$，就是「考慮了上下文後所更新的詞彙向量表示」的集合。
這就是論文中所定義的 &lt;strong>Scaled Dot-Product Attention&lt;/strong> 的全貌。&lt;/p>
&lt;hr>
&lt;h1 id="5-multi-head-attention多頭注意力機制">5. Multi-Head Attention（多頭注意力機制）
&lt;/h1>&lt;p>僅靠一次的Attention計算（單頭），可能只能從一個觀點（例如「文法關係」）來捕捉上下文。因此，為了同時捕捉語言擁有的多樣化語意與句法關係（例如「主詞與動詞」、「代名詞與其指代對象」等），引入了 &lt;strong>Multi-Head Attention&lt;/strong>。&lt;/p>
&lt;p>將剛才的 $Q, K, V$ 生成與Attention計算，平行進行 $h$ 次（頭的數量。原始論文中 $h=8$）。&lt;/p>
$$ \text{head}_i = \text{Attention}(X W_i^Q, X W_i^K, X W_i^V) $$
&lt;p>這裡，$W_i^Q, W_i^K, W_i^V \in \mathbb{R}^{d_{model} \times d_k}$ 是專屬於第 $i$ 個頭的可學習權重矩陣。&lt;/p>
&lt;p>將每個頭輸出的結果 $\text{head}_i \in \mathbb{R}^{N \times d_v}$ 在橫向上拼接（Concatenate）起來。&lt;/p>
$$ \text{Concat}(\text{head}_1, \dots, \text{head}_h) \in \mathbb{R}^{N \times (h \cdot d_v)} $$
&lt;p>通常會設定成 $h \cdot d_v = d_{model}$，所以拼接後的維度會再次回到與輸入相同的 $d_{model}$。最後，將這個矩陣乘上權重矩陣 $W^O \in \mathbb{R}^{d_{model} \times d_{model}}$，得到最終的輸出。&lt;/p>
$$ \text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \dots, \text{head}_h) W^O $$
&lt;div class="mermaid">graph TD
X["輸入 X"] --> Q1["Q1"]
X --> K1["K1"]
X --> V1["V1"]
Q1 &amp; K1 &amp; V1 --> H1["頭 1 (Head 1)"]
X --> Q2["Q2"]
X --> K2["K2"]
X --> V2["V2"]
Q2 &amp; K2 &amp; V2 --> H2["頭 2 (Head 2)"]
X --> QN["..."]
X --> KN["..."]
X --> VN["..."]
QN &amp; KN &amp; VN --> HN["頭 h (Head h)"]
H1 &amp; H2 &amp; HN --> C["拼接 (Concatenate)"]
C --> WO["乘以 WO (Multiply by WO)"]
WO --> OUT["多頭輸出 (Multi-Head Output)"]&lt;/div>
&lt;hr>
&lt;h1 id="6-feed-forward-neural-network-ffn">6. Feed-Forward Neural Network (FFN)
&lt;/h1>&lt;p>Multi-Head Attention的輸出，接著會輸入到 &lt;strong>Position-wise Feed-Forward Network (FFN)&lt;/strong> 中。
這是一個對序列的「每個位置（詞彙）獨立地」套用的兩層全連接神經網路。&lt;/p>
&lt;p>用數學公式表示如下：&lt;/p>
$$ \text{FFN}(x) = \max(0, x W_1 + b_1) W_2 + b_2 $$
&lt;p>這裡，$\max(0, z)$ 代表 ReLU（Rectified Linear Unit）激勵函數（在最近的模型中也常使用 GELU 或 SwiGLU）。&lt;/p>
&lt;p>這個網路的作用非常重要。Attention機制學習了「詞彙間的關聯性（空間、序列關係）」，而 FFN 則負責「每個詞彙向量本身的非線性特徵轉換」。
通常，透過第一層的權重 $W_1$ 將維度暫時大幅擴增（例如從 $d_{model}=512$ 擴增4倍至 $d_{ff}=2048$），在特徵空間上進行複雜計算後，再透過第二層的權重 $W_2$ 縮回原本的維度。這種「維度的擴張與縮小」，讓模型的表達能力有了飛躍性的提升。&lt;/p>
&lt;hr>
&lt;h1 id="7-殘差連接residual-connection與-layer-normalization">7. 殘差連接（Residual Connection）與 Layer Normalization
&lt;/h1>&lt;p>在深度學習中，如果網路層數變得太深，在訓練時會發生梯度消失或爆炸，導致無法順利學習的問題。為了防止這種情況，在Transformer每個子層（Attention 與 FFN）的周圍，都配置了 &lt;strong>殘差連接（Residual Connection）&lt;/strong> 與 &lt;strong>Layer Normalization（層正規化）&lt;/strong>。&lt;/p>
&lt;p>用數學公式寫的話，子層的輸出會進行如下處理：&lt;/p>
$$ \text{Output} = \text{LayerNorm}(x + \text{Sublayer}(x)) $$
&lt;h2 id="71-殘差連接-x--textsublayerx">7.1 殘差連接 ($x + \text{Sublayer}(x)$)
&lt;/h2>&lt;p>將輸入 $x$ 直接加到子層的輸出上。藉此，反向傳播時梯度能透過捷徑直接傳遞到較淺的層次，因此即使網路層數很深，訓練也能保持穩定。&lt;/p>
&lt;h2 id="72-layer-normalization的數學">7.2 Layer Normalization的數學
&lt;/h2>&lt;p>Layer Normalization是一種計算特徵維度方向的平均值與變異數，並將資料予以正規化的技術。在批次大小為 $B$、序列長度為 $N$、維度數為 $d_{model}$ 的輸入中，對某單一個詞彙向量 $x \in \mathbb{R}^{d_{model}}$ 進行正規化。&lt;/p>
&lt;p>計算平均值 $\mu$ 與變異數 $\sigma^2$：
&lt;/p>
$$ \mu = \frac{1}{d_{model}} \sum_{i=1}^{d_{model}} x_i $$
$$ \sigma^2 = \frac{1}{d_{model}} \sum_{i=1}^{d_{model}} (x_i - \mu)^2 $$
&lt;p>接著，得到正規化後的輸出 $\hat{x}$：
&lt;/p>
$$ \text{LN}(x) = \frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}} \odot \gamma + \beta $$
&lt;p>
（$\epsilon$ 是一個微小的常數，用來防止除以零。$\gamma, \beta$ 是可學習的縮放（scale）與平移（shift）參數）&lt;/p>
&lt;p>採用沿著層方向正規化（Layer Normalization）而不是沿著批次方向正規化（Batch Normalization）的原因在於，當處理像文章這種長度不固定的序列資料時，批次間的統計量容易變得不穩定。透過 Layer Normalization，Transformer 能夠不依賴批次大小而進行穩定的學習。&lt;/p>
&lt;hr>
&lt;h1 id="8-解碼器特有的結構masked-attention-與-cross-attention">8. 解碼器特有的結構：Masked Attention 與 Cross-Attention
&lt;/h1>&lt;p>到目前為止解說的結構都是屬於編碼器（Encoder）的。在生成文章的解碼器（Decoder）區塊中，結構稍微有些不同。&lt;/p>
&lt;h2 id="81-masked-multi-head-attention">8.1 Masked Multi-Head Attention
&lt;/h2>&lt;p>解碼器的作用是「根據過去的詞彙來預測下一個詞彙」。因此，在訓練時如果看到了「未來的詞彙」就等於是作弊。為了防止這種情況發生的數學操作就是 &lt;strong>Masking（遮罩）&lt;/strong>。&lt;/p>
&lt;p>對於分數矩陣 $Q K^T$，在相當於未來資訊的上三角部分，加上一個設定了接近 $-\infty$ 之極小值的遮罩矩陣 $M$。&lt;/p>
$$ M_{ij} = \begin{cases} 0 &amp; (i \le j) \\ -\infty &amp; (i > j) \end{cases} $$
$$ \text{Masked Attention}(Q, K, V) = \text{softmax}\left(\frac{Q K^T + M}{\sqrt{d_k}}\right) V $$
&lt;p>在計算 Softmax 函數時，因為 $\exp(-\infty) = 0$，所以對未來詞彙的 Attention Weight 會完全變成 $0$。藉此，可以實現保持因果關係（Causality）的自迴歸生成。&lt;/p>
&lt;h2 id="82-encoder-decoder-cross-attention">8.2 Encoder-Decoder Cross-Attention
&lt;/h2>&lt;p>解碼器的第二個子層，是參考編碼器輸出的 &lt;strong>Cross-Attention&lt;/strong>。
在這裡，$Q$ 是從前一層的解碼器層生成的，而 $K$ 和 $V$ 則是從編碼器的最後一層輸出生成的。&lt;/p>
$$ Q_{decoder} = X_{dec} W^Q $$
$$ K_{encoder} = X_{enc} W^K $$
$$ V_{encoder} = X_{enc} W^V $$
&lt;p>透過這個計算，在翻譯任務等情況下，模型就能夠學習到「現在正在翻譯的詞彙，與原文（外語）文章的哪部分有強烈關聯」。&lt;/p>
&lt;hr>
&lt;h1 id="9-計算複雜度與現代最佳化的數學">9. 計算複雜度與現代最佳化的數學
&lt;/h1>&lt;p>Transformer雖然是個很棒的模型，但因為其數學結構也存在著「弱點」。
請注意 Self-Attention 的計算複雜度。在計算分數矩陣 $Q K^T$ 時，需要將 $(N \times d_k)$ 的矩陣與 $(d_k \times N)$ 的矩陣相乘，因此其計算複雜度為 &lt;strong>$O(N^2 \cdot d_{model})$&lt;/strong>。&lt;/p>
&lt;p>換句話說，&lt;strong>相對於序列長度 $N$，計算複雜度與記憶體使用量會呈平方增長&lt;/strong>。
當文章很短時不會成為問題，但如果想將整本書這樣超長的上下文輸入到 LLM 時，$N$ 會達到數萬至數十萬，在傳統的 Attention 計算下，GPU的記憶體會瞬間耗盡。&lt;/p>
&lt;p>為了解開這個 $O(N^2)$ 的詛咒，近年來從數學與硬體角度提出了各種最佳化方法。
其中具代表性的例子就是 &lt;strong>FlashAttention&lt;/strong>。FlashAttention 是一種將 Attention 計算以區塊（Tiling）方式分割進行的演算法，藉此將 GPU 記憶體階層（SRAM 與 HBM）之間的資料傳輸（記憶體存取）降到最低。儘管在數學公式上輸出的結果與標準的 Attention 完全相同（Exact Attention），但透過硬體層級的最佳化實現了戲劇性的加速與記憶體節省，使得像 GPT-4 這種長文本模型成為可能。&lt;/p>
&lt;p>除此之外，也有許多研究正積極探討將計算複雜度近似為 $O(N \log N)$ 或 $O(N)$ 的 Sparse Attention 與 Linear Attention 等技術。&lt;/p>
&lt;hr>
&lt;h1 id="10-實作概念類似-pytorch-的虛擬碼">10. 實作概念（類似 PyTorch 的虛擬碼）
&lt;/h1>&lt;p>將截至目前為止的數學結構落實為實際的程式碼（Python / PyTorch）時，會發現可以寫得驚人地簡潔。以下展示 Self-Attention 核心部分的虛擬碼。&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">torch&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">torch.nn.functional&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">F&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">math&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">scaled_dot_product_attention&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">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">v&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">mask&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">None&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># q, k, v的形狀: [batch_size, num_heads, seq_length, d_k]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">d_k&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">q&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1. 透過內積計算分數: Q * K^T&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">scores&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">matmul&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">k&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">transpose&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/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">scores&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">scores&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">math&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sqrt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">d_k&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. 遮罩 (在Masked Attention的情況下)&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">mask&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">scores&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">scores&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">masked_fill&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mask&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mf">1e9&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"># 4. 透過Softmax轉換為機率&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">attention_weights&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">F&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">softmax&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">scores&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">dim&lt;/span>&lt;span class="o">=-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 5. 乘上Value矩陣&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">matmul&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">attention_weights&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">v&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">output&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">attention_weights&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>可以直觀地看出，用數學公式表達的 $Q K^T / \sqrt{d_k}$ 被實作為 &lt;code>torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(d_k)&lt;/code>。數學理論能藉助高度最佳化的函式庫，只用幾行程式碼就實現出來，這是深度學習非常有趣的一面。&lt;/p>
&lt;hr>
&lt;h1 id="結語從數學公式看見智慧的樣貌">結語：從數學公式看見「智慧」的樣貌
&lt;/h1>&lt;p>在本文中，我們解開了Transformer模型深處的數學結構。&lt;/p>
&lt;p>將詞彙映射到多維向量空間的 Embedding、透過三角波合成來表達位置資訊的 Positional Encoding，以及源自資訊檢索比喻、本質上是矩陣內積計算的 Self-Attention 機制。這些組件每一個都只不過是線性代數、微積分、機率統計等基礎數學的累積。&lt;/p>
&lt;p>然而，當這些單純的矩陣運算層層疊加，並透過數十億、數千億個參數從巨大的資料集中學習模式時，那裡便浮現出一種彷彿能理解我們的「語言」、進行邏輯推論，甚至時而產生創造性想法的「智慧的樣貌」。&lt;/p>
&lt;p>正如《Attention Is All You Need》這個充滿挑釁意味的標題所示，捨棄了複雜的遞歸處理與卷積處理，專注於純粹「注意力（關聯度）」計算的這種架構之美，可以說正是存在於其數學的簡潔性之中。&lt;/p>
&lt;p>未來，或許會出現超越Transformer的全新架構（例如基於狀態空間模型 State Space Model 的 Mamba 等），但Transformer所建立的「透過 Attention 進行上下文理解」的數學框架，想必會永遠銘刻在人工智慧的歷史中。&lt;/p>
&lt;p>如果你未來有機會使用 ChatGPT 或 Claude 等 LLM，請試著想像在它們的背景運作中，每秒正進行著數兆次的 $Q K^T$ 矩陣乘積計算，並由 Softmax 函數計算出機率的模樣。相信你對技術的解析度會隨之提升，也會覺得 AI 的世界更加有趣。&lt;/p>
&lt;h3 id="參考文獻">參考文獻
&lt;/h3>&lt;ul>
&lt;li>Vaswani, A., et al. (2017). &amp;ldquo;Attention Is All You Need.&amp;rdquo; &lt;em>Advances in Neural Information Processing Systems&lt;/em>.&lt;/li>
&lt;li>Alammar, J. (2018). &amp;ldquo;The Illustrated Transformer.&amp;rdquo;&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>&lt;em>本文旨在為學習自然語言處理與 AI 數學基礎的讀者提供指南。如果有任何問題或想討論的地方，歡迎在留言區告訴我們！&lt;/em>&lt;/p></description></item><item><title>利用費馬小定理的加密基礎與實作</title><link>http://kenji.blog/zh-tw/p/fermats-little-theorem-cryptography-implementation/</link><pubDate>Fri, 11 Sep 2026 22:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/p/fermats-little-theorem-cryptography-implementation/</guid><description>&lt;img src="http://kenji.blog/p/fermats-little-theorem-cryptography-implementation/img/eyecatch.jpg" alt="Featured image of post 利用費馬小定理的加密基礎與實作" />&lt;h2 id="1-簡介支撐現代密碼學的數學奧秘">1. 簡介：支撐現代密碼學的數學奧秘
&lt;/h2>&lt;p>在現代數位社會，特別是透過網際網路進行通訊時，「加密」已成為不可或缺的基礎技術。我們能透過網頁瀏覽器經由 HTTPS 安全地瀏覽網站、在網路銀行進行金融交易，以及在通訊應用程式中進行私密對話，全是因為有高度數學理論支持的加密協定在背後運作。其中扮演特別重要角色的就是「公開金鑰加密」，而其代表正是 &lt;strong>RSA 加密&lt;/strong>。&lt;/p>
&lt;p>包含 RSA 加密在內的許多加密演算法，其安全性與正確性在很大程度上依賴於 17 世紀法國數學家皮耶·德·費馬（Pierre de Fermat）所發現的一個非常優美且強大的定理。這就是&lt;strong>費馬小定理（Fermat&amp;rsquo;s Little Theorem）&lt;/strong>。此外，將其一般化的李昂哈德·歐拉（Leonhard Euler）定理，在密碼學理論中也發揮了決定性的作用。&lt;/p>
&lt;p>本篇文章將從基礎開始，徹底解說費馬小定理這個純數學的發現，是如何應用於現代實用的加密技術，特別是「質數判定」與「RSA 加密」。這是一份非常詳細的技術指南，內容涵蓋數學證明、加密與解密機制，以及使用 C++ 與 Python 進行具體演算法實作。&lt;/p>
&lt;hr>
&lt;h2 id="2-同餘與模算數基礎">2. 同餘與模算數基礎
&lt;/h2>&lt;p>為了理解費馬小定理，首先必須熟悉「模算數（同餘式）」這個數學概念。模算數是一種著眼於除以某個固定數字（稱為模數）後的「餘數」之計算系統。因為它像時鐘的表面（每 12 小時繞一圈）一樣運算，所以也被稱為「時鐘數學」。&lt;/p>
&lt;p>當整數 $a$ 和 $b$ 除以正整數 $n$ 的餘數相等時，數學上會以下列方式表示：&lt;/p>
$$
a \equiv b \pmod n
$$
&lt;p>這讀作「在模 $n$ 之下，$a$ 與 $b$ 同餘」。例如，17 除以 5 的餘數是 2，而 12 除以 5 的餘數也是 2。因此，可以寫成如下形式：&lt;/p>
$$
17 \equiv 12 \pmod 5 \equiv 2 \pmod 5
$$
&lt;p>在模算數中，一般的四則運算（加法、減法、乘法）可以直接成立：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>加法&lt;/strong>: 若 $a \equiv b \pmod n$ 且 $c \equiv d \pmod n$，則 $a + c \equiv b + d \pmod n$&lt;/li>
&lt;li>&lt;strong>減法&lt;/strong>: 若 $a \equiv b \pmod n$ 且 $c \equiv d \pmod n$，則 $a - c \equiv b - d \pmod n$&lt;/li>
&lt;li>&lt;strong>乘法&lt;/strong>: 若 $a \equiv b \pmod n$ 且 $c \equiv d \pmod n$，則 $a \times c \equiv b \times d \pmod n$&lt;/li>
&lt;li>&lt;strong>指數&lt;/strong>: 若 $a \equiv b \pmod n$，則對於任意自然數 $k$，$a^k \equiv b^k \pmod n$ 成立&lt;/li>
&lt;/ol>
&lt;p>不過，關於&lt;strong>除法&lt;/strong>必須特別注意。一般來說，即使 $a \times c \equiv b \times c \pmod n$，也不能直接將兩邊除以 $c$ 得出 $a \equiv b \pmod n$。這只有在 $c$ 和 $n$ 互質（最大公因數為 1）的情況下才成立。這個「模反元素（模逆元）」的概念，在後文將提到的 RSA 加密金鑰生成中非常重要。&lt;/p>
&lt;hr>
&lt;h2 id="3-費馬小定理的數學背景與證明">3. 費馬小定理的數學背景與證明
&lt;/h2>&lt;p>掌握了模算數的基礎後，讓我們來看看本篇的主題——費馬小定理。&lt;/p>
&lt;h3 id="31-定理的定義">3.1 定理的定義
&lt;/h3>&lt;p>費馬小定理可以表述如下：&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>費馬小定理 (Fermat&amp;rsquo;s Little Theorem)&lt;/strong>
設 $p$ 為質數，$a$ 為不是 $p$ 的倍數（即 $a$ 與 $p$ 互質）的任意整數。此時，以下同餘式成立：
&lt;/p>
$$ a^{p-1} \equiv 1 \pmod p $$
&lt;/blockquote>
&lt;p>此外，拿掉「$a$ 不是 $p$ 的倍數」的條件，將其表示為對所有整數 $a$ 都成立的形式也很常見。在這種情況下，兩邊同乘 $a$ 可得：&lt;/p>
$$
a^p \equiv a \pmod p
$$
&lt;h3 id="32-透過具體例子確認">3.2 透過具體例子確認
&lt;/h3>&lt;p>為了確認定理是否真的成立，我們用具體的數字來驗證看看。
設質數 $p = 5$。則 $p-1 = 4$。我們選擇不是 $p$ 的倍數的整數作為 $a$。&lt;/p>
&lt;ul>
&lt;li>當 $a = 2$ 時：$2^{5-1} = 2^4 = 16$。$16 \div 5 = 3$ 餘 $1$。因此 $16 \equiv 1 \pmod 5$。（成立）&lt;/li>
&lt;li>當 $a = 3$ 時：$3^{5-1} = 3^4 = 81$。$81 \div 5 = 16$ 餘 $1$。因此 $81 \equiv 1 \pmod 5$。（成立）&lt;/li>
&lt;li>當 $a = 4$ 時：$4^{5-1} = 4^4 = 256$。$256 \div 5 = 51$ 餘 $1$。因此 $256 \equiv 1 \pmod 5$。（成立）&lt;/li>
&lt;/ul>
&lt;p>就這樣，無論選擇什麼樣的 $a$（只要不是 5 的倍數），其 4 次方除以 5 的餘數必然為 1。看起來像魔法一樣，但這源自於質數所具備的優美性質。&lt;/p>
&lt;h3 id="33-定理的數學證明">3.3 定理的數學證明
&lt;/h3>&lt;p>為什麼會成立這樣的事實呢？這裡我們介紹一個使用剩餘系集合的優雅證明。&lt;/p>
&lt;p>考慮集合 $S = \{1, 2, 3, \dots, p-1\}$。這些是除以 $p$ 後餘數為 $1$ 到 $p-1$ 的整數代表元素。
現在，我們將各個元素乘上與 $p$ 互質的整數 $a$，得到一個新集合 $T$：
&lt;/p>
$$ T = \{1a, 2a, 3a, \dots, (p-1)a\} $$
&lt;p>我們考慮這個集合 $T$ 中的各個元素除以 $p$ 的餘數。令人驚訝的是，這些餘數雖然順序可能改變，但與原來集合 $S$ 的元素集合完全一致。
因為：&lt;/p>
&lt;ol>
&lt;li>$T$ 的元素不會是 $p$ 的倍數（因為 $a$ 和原本的元素都不是 $p$ 的倍數）。&lt;/li>
&lt;li>在 $T$ 之中，不存在兩個在模 $p$ 下同餘的不同元素。如果 $ia \equiv ja \pmod p$ （其中 $i \neq j$），因為 $a$ 和 $p$ 互質，我們可以除以 $a$，得到 $i \equiv j \pmod p$，這就產生了矛盾。&lt;/li>
&lt;/ol>
&lt;p>因此，將 $S$ 的所有元素相乘的結果，與將 $T$ 的所有元素相乘的結果，在模 $p$ 之下是同餘的。&lt;/p>
$$
(1a) \times (2a) \times \dots \times ((p-1)a) \equiv 1 \times 2 \times \dots \times (p-1) \pmod p
$$
&lt;p>將左邊整理，因為有 $p-1$ 個 $a$，所以：&lt;/p>
$$
a^{p-1} \cdot (p-1)! \equiv (p-1)! \pmod p
$$
&lt;p>因為 $(p-1)!$ 與 $p$ 互質，所以兩邊可以除以 $(p-1)!$，最終導出以下定理：&lt;/p>
$$
a^{p-1} \equiv 1 \pmod p
$$
&lt;p>這就是費馬小定理的證明。&lt;/p>
&lt;hr>
&lt;h2 id="4-歐拉函數與歐拉定理">4. 歐拉函數與歐拉定理
&lt;/h2>&lt;p>費馬小定理是關於「質數 $p$」的定理，而將其推廣至「任意正整數 $n$」的人，就是李昂哈德·歐拉。為了理解 RSA 加密，這個推廣是不可或缺的。&lt;/p>
&lt;h3 id="41-歐拉函數-phin">4.1 歐拉函數 $\phi(n)$
&lt;/h3>&lt;p>歐拉函數（或稱歐拉 $\phi$ 函數） $\phi(n)$ 是一個表示「在 $1$ 到 $n$ 的整數中，與 $n$ 互質的數字個數」的函數。&lt;/p>
&lt;ul>
&lt;li>當為質數 $p$ 時，由於 $1$ 到 $p-1$ 的所有整數都與 $p$ 互質，因此 $\phi(p) = p - 1$。&lt;/li>
&lt;li>對於兩個相異質數 $p, q$，其乘積 $n = p \times q$ 的情況，$\phi(n)$ 可以用非常簡單的算式求出：
$$ \phi(p \times q) = \phi(p) \times \phi(q) = (p - 1)(q - 1) $$&lt;/li>
&lt;/ul>
&lt;p>這個性質，正是 RSA 加密金鑰生成的根本邏輯。&lt;/p>
&lt;h3 id="42-歐拉定理">4.2 歐拉定理
&lt;/h3>&lt;p>歐拉將費馬小定理推廣如下：&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>歐拉定理 (Euler&amp;rsquo;s Theorem)&lt;/strong>
對於正整數 $n$ 以及與其互質的整數 $a$，以下關係成立：
&lt;/p>
$$ a^{\phi(n)} \equiv 1 \pmod n $$
&lt;/blockquote>
&lt;p>如果 $n$ 是質數 $p$，則 $\phi(p) = p - 1$，這就變成了費馬小定理本身（$a^{p-1} \equiv 1 \pmod p$）。也就是說，費馬小定理只不過是歐拉定理的一個特例。&lt;/p>
&lt;hr>
&lt;h2 id="5-尋找巨大的質數費馬質數判定法">5. 尋找巨大的質數：費馬質數判定法
&lt;/h2>&lt;p>在加密技術（如 RSA 加密與 Diffie-Hellman 金鑰交換等）中，必須能高速找出長達數百位數的「巨大質數」。然而，如果要判定一個巨大數字 $N$ 是否為質數，若使用測試除以從 $2$ 到 $\sqrt{N}$ 的所有數字是否能整除的「試除法」，將會花費等同於宇宙壽命般漫長的時間。&lt;/p>
&lt;p>因此，反過來利用費馬小定理的「機率性質數判定法」，即 &lt;strong>費馬質數判定法（Fermat Primality Test）&lt;/strong> 便應運而生。&lt;/p>
&lt;h3 id="51-什麼是機率性質數判定法">5.1 什麼是機率性質數判定法
&lt;/h3>&lt;p>根據費馬小定理，若 $p$ 為質數，則對於任意的 $a$ ($1 &lt; a &lt; p$)，$a^{p-1} \equiv 1 \pmod p$ 必然成立。
取其逆否命題，可以說「如果對於某個 $a$，得出 $a^{p-1} \not\equiv 1 \pmod p$，那麼 $p$ &lt;strong>絕對不是質數（是合數）&lt;/strong>」。&lt;/p>
&lt;p>因此，如果想判定 $N$ 是否為質數，隨機選擇幾個 $a$，計算 $a^{N-1} \pmod N$ 並確認結果是否為 $1$。如果只要有一次得出 $1$ 以外的答案，就可以確定 $N$ 是合數。如果試了多次結果都是 $1$，則可以高度機率地判斷 $N$ 「大概是質數」。&lt;/p>
&lt;h3 id="52-演算法解說與流程圖">5.2 演算法解說與流程圖
&lt;/h3>&lt;p>費馬質數判定法的演算法如下。&lt;/p>
&lt;div class="mermaid">flowchart TD
Start["開始"] --> Input["輸入判定目標數 p 與測試次數 k"]
Input --> LoopStart["迴圈從 i = 0 到 k-1"]
LoopStart --> Condition{"i &lt; k ?"}
Condition -- "是" --> RandomA["在 1 &lt; a &lt; p-1 範圍內隨機選擇整數 a"]
RandomA --> Calc["計算模冪 a^(p-1) mod p"]
Calc --> CheckPrime{"結果為 1 嗎？"}
CheckPrime -- "否" --> ReturnComposite["p 是合數（確定）"]
CheckPrime -- "是" --> Increment["將 i 加 1"]
Increment --> Condition
Condition -- "否" --> ReturnPrime["p 大概是質數（機率性）"]
ReturnComposite --> End["結束"]
ReturnPrime --> End&lt;/div>
&lt;h3 id="53-卡邁克爾數偽質數的陷阱">5.3 卡邁克爾數（偽質數）的陷阱
&lt;/h3>&lt;p>費馬質數判定法雖然非常快速，但有一個重大的缺點。那就是存在著像惡魔一般的數字，明明是合數，卻對所有的 $a$ 都滿足 $a^{N-1} \equiv 1 \pmod N$。這被稱為 &lt;strong>卡邁克爾數 (Carmichael numbers)&lt;/strong>。最小的卡邁克爾數是 $561$ ($3 \times 11 \times 17$)。&lt;/p>
&lt;p>由於卡邁克爾數的存在，單純的費馬測試無法進行絕對的質數判定。因此，在實際的加密系統（如 OpenSSL 等）中，標準使用的是改良自費馬測試的 &lt;strong>米勒-拉賓（Miller-Rabin）質數判定法&lt;/strong>。因為米勒-拉賓判定法能看穿卡邁克爾數，可將誤判的機率實質上降至零。&lt;/p>
&lt;h3 id="54-高速的模冪運算反覆平方法">5.4 高速的模冪運算（反覆平方法）
&lt;/h3>&lt;p>在質數判定演算法中，需要計算 $a^{N-1} \pmod N$，但當 $N$ 巨大時，$a^{N-1}$ 將成為天文數字級別的位數，無法裝入電腦的記憶體中。
解決這個問題的是 &lt;strong>反覆平方法（Exponentiation by Squaring）&lt;/strong> 或模冪運算。透過在計算的每一個步驟都取餘數（mod N），可以讓數值始終保持小於 $N$，從而能非常高速（計算複雜度為 $O(\log N)$）地進行計算。&lt;/p>
&lt;hr>
&lt;h2 id="6-質數判定與模冪運算的實作">6. 質數判定與模冪運算的實作
&lt;/h2>&lt;p>那麼，我們就來使用 C++ 和 Python 實作費馬質數判定法和反覆平方法吧。&lt;/p>
&lt;h3 id="61-使用-c-實作">6.1 使用 C++ 實作
&lt;/h3>&lt;p>在 C++ 中，標準整數型別容易發生溢位，處理巨大數字時需要多精度整數函式庫（如 GMP 等）。不過，為了理解演算法，這裡展示在 64 位元整數（&lt;code>unsigned long long&lt;/code>）範圍內的實作。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;random&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="k">namespace&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 高速的模冪運算 (a^b mod m) - 反覆平方法
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="nf">power_mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 若 b 的最低位元為 1，則將 result 乘上 a
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">__int128&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="n">result&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// 為防止溢位擴展為 128bit
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 將 a 平方
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">__int128&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="n">a&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 將 b 右移（減半）
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">/=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 費馬質數判定法
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">bool&lt;/span> &lt;span class="nf">fermat_is_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">iterations&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">random_device&lt;/span> &lt;span class="n">rd&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">mt19937_64&lt;/span> &lt;span class="n">gen&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">rd&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">uniform_int_distribution&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">dis&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">iterations&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dis&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">gen&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 若 a^(p-1) mod p 不為 1，則是合數
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">power_mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// 大概是質數
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1000000007&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// 已知的質數
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">fermat_is_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; is probably prime.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; is composite.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="62-使用-python-實作">6.2 使用 Python 實作
&lt;/h3>&lt;p>Python 的標準整數型別支援多精度整數，因此不需擔心位數溢位。此外，Python 的內建函數 &lt;code>pow(a, b, m)&lt;/code> 內部就使用了反覆平方法，因此非常快速。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">random&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">fermat_is_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">iterations&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 使用費馬質數判定法的機率性質數判定
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">iterations&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 在 2 到 p-2 之間隨機選擇一個數字 a&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 計算 a^(p-1) mod p。內建的 pow 很快速。&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span> &lt;span class="c1"># 確定是合數&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">True&lt;/span> &lt;span class="c1"># 大概是質數&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 測試&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">number_to_test&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">104729&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="n">fermat_is_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">number_to_test&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">number_to_test&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> 大概是質數。&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">number_to_test&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> 是合數。&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="7-在-rsa-加密中的應用費馬與歐拉結果的地方">7. 在 RSA 加密中的應用：費馬與歐拉結果的地方
&lt;/h2>&lt;p>費馬小定理（以及歐拉定理）最偉大的應用領域，就是 1977 年由 Rivest、Shamir 與 Adleman 三人所開發的 &lt;strong>RSA 加密&lt;/strong>。
RSA 加密是一個名為「公開金鑰加密」的劃時代系統，它實現了一種機制：用來加密的金鑰（公開金鑰）對全世界公開，但用來解密的金鑰（私鑰）只有接收者本人知道。&lt;/p>
&lt;p>這種不對稱性，是基於「將巨大的合數進行質因數分解是極度困難的」這一計算複雜度上的安全性。&lt;/p>
&lt;h3 id="71-rsa-加密的機制金鑰生成加密解密">7.1 RSA 加密的機制（金鑰生成、加密、解密）
&lt;/h3>&lt;p>讓我們透過 Mermaid 的循序圖來確認 RSA 加密的整體通訊流程。&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant Alice["愛麗絲 (接收者)"]
participant Bob["鮑伯 (發送者)"]
Alice->>Alice: "生成巨大的質數 p, q"
Alice->>Alice: "計算 N = p * q, φ(N) = (p-1)(q-1)"
Alice->>Alice: "計算公開金鑰 e 與私鑰 d (e*d ≡ 1 mod φ(N))"
Alice->>Bob: "傳送公開金鑰 (N, e)"
Note over Bob: "準備明文 M (M &lt; N)"
Bob->>Bob: "計算密文 C = M^e mod N"
Bob->>Alice: "傳送密文 C"
Alice->>Alice: "計算明文 M = C^d mod N 並解密"&lt;/div>
&lt;p>以下解說數學上的詳細步驟。&lt;/p>
&lt;h4 id="步驟-1金鑰的生成接收者愛麗絲的作業">步驟 1：金鑰的生成（接收者愛麗絲的作業）
&lt;/h4>&lt;ol>
&lt;li>隨機生成兩個巨大的質數 $p$ 與 $q$（這裡會用到前述的質數判定法）。&lt;/li>
&lt;li>計算其乘積 $N = p \times q$。這個 $N$ 會被公開。&lt;/li>
&lt;li>使用歐拉函數，計算 $\phi(N) = (p-1)(q-1)$。&lt;/li>
&lt;li>選擇與 $\phi(N)$ 互質的整數 $e$（公開指數）（常使用 $e = 65537$）。&lt;/li>
&lt;li>計算 $e$ 的模反元素 $d$（私密指數）。亦即，找出滿足下式的 $d$：
$$ e \cdot d \equiv 1 \pmod{\phi(N)} $$
這個計算使用了&lt;strong>擴展歐幾里得演算法&lt;/strong>。&lt;/li>
&lt;/ol>
&lt;p>至此，&lt;strong>公開金鑰為 $(N, e)$&lt;/strong>，&lt;strong>私鑰為 $(N, d)$&lt;/strong>。（$p, q, \phi(N)$ 會立即銷毀或嚴格保密）。&lt;/p>
&lt;h4 id="步驟-2加密發送者鮑伯的作業">步驟 2：加密（發送者鮑伯的作業）
&lt;/h4>&lt;p>假設鮑伯想發送訊息 $M$ 給愛麗絲（$M$ 是將文字轉換為數值後的結果，且 $0 \le M &lt; N$）。
鮑伯使用愛麗絲的公開金鑰 $(N, e)$，進行以下計算製作密文 $C$：&lt;/p>
$$
C \equiv M^e \pmod N
$$
&lt;p>透過網路將這個 $C$ 發送給愛麗絲。&lt;/p>
&lt;h4 id="步驟-3解密接收者愛麗絲的作業">步驟 3：解密（接收者愛麗絲的作業）
&lt;/h4>&lt;p>收到密文 $C$ 的愛麗絲，使用只有自己知道的私鑰 $d$ 進行以下計算：&lt;/p>
$$
M' \equiv C^d \pmod N
$$
&lt;p>令人驚奇的是，這個計算結果 $M'$ 會與原始訊息 $M$ 完全一致。&lt;/p>
&lt;h3 id="72-為什麼能解密數學證明">7.2 為什麼能解密？（數學證明）
&lt;/h3>&lt;p>在這裡，費馬小定理（歐拉定理）發揮了它的真正價值。為什麼 $C^d \pmod N$ 能變回 $M$ 呢？&lt;/p>
&lt;p>我們將解密的式子展開。
因為 $C \equiv M^e \pmod N$，所以：
&lt;/p>
$$ C^d \equiv (M^e)^d \equiv M^{ed} \pmod N $$
&lt;p>在金鑰生成的步驟中，我們選擇了 $d$ 使得 $e \cdot d \equiv 1 \pmod{\phi(N)}$。這意味著存在某個整數 $k$，可以寫成如下形式：
&lt;/p>
$$ e \cdot d = 1 + k \cdot \phi(N) $$
&lt;p>將其代入上面的式子：
&lt;/p>
$$ M^{ed} = M^{1 + k \cdot \phi(N)} = M \cdot M^{k \cdot \phi(N)} = M \cdot (M^{\phi(N)})^k \pmod N $$
&lt;p>在這裡&lt;strong>歐拉定理&lt;/strong> ($M^{\phi(N)} \equiv 1 \pmod N$) 登場了。（※嚴格來說，$M$ 和 $N$ 必須互質，但在 RSA 中 $M$ 和 $N$ 不互質的機率是天文數字級別地低，且透過中國剩餘定理可以證明即使不互質也成立）。&lt;/p>
&lt;p>應用歐拉定理，$M^{\phi(N)} \equiv 1$，因此：
&lt;/p>
$$ M \cdot (1)^k \equiv M \pmod N $$
&lt;p>完美地還原了 $M$！費馬與歐拉在幾百年前發現的數之性質，完美地保證了現代數位通訊的機密性。&lt;/p>
&lt;hr>
&lt;h2 id="8-rsa-加密的簡易實作-python">8. RSA 加密的簡易實作 (Python)
&lt;/h2>&lt;p>因為只有理論較難體會，所以我們用 Python 來實際實作 RSA 加密的金鑰生成、加密、解密的過程吧。這是一個供教育用途的「簡易（玩具）實作」，但所使用的數學與真實情況完全相同。&lt;/p>
&lt;p>用來求得模反元素 $d$ 的「擴展歐幾里得演算法」也包含在實作中。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;span class="lnt">74
&lt;/span>&lt;span class="lnt">75
&lt;/span>&lt;span class="lnt">76
&lt;/span>&lt;span class="lnt">77
&lt;/span>&lt;span class="lnt">78
&lt;/span>&lt;span class="lnt">79
&lt;/span>&lt;span class="lnt">80
&lt;/span>&lt;span class="lnt">81
&lt;/span>&lt;span class="lnt">82
&lt;/span>&lt;span class="lnt">83
&lt;/span>&lt;span class="lnt">84
&lt;/span>&lt;span class="lnt">85
&lt;/span>&lt;span class="lnt">86
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">random&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 求最大公因數&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">b&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">a&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 擴展歐幾里得演算法 (求得 ax + by = gcd(a,b) 的 x, y)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 用於尋找 e*d ≡ 1 (mod φ(N)) 中的 d&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">extended_gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">extended_gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">g&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">//&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">mod_inverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">extended_gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">g&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">Exception&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;不存在反元素&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">phi&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 質數生成函數（簡易版：生成小質數）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">generate_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="kc">True&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">p&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">getrandbits&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 用簡單判定來代替前述的費馬測試&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">p&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># RSA 金鑰生成&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">generate_keypair&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">16&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">p&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">generate_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">q&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">generate_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 避免 p 和 q 變成一樣&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">q&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">q&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">generate_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">q&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">phi&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">q&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># e 常使用 65537 等質數，但這裡隨機選擇&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randrange&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">g&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randrange&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 私鑰 d 的計算&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">d&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod_inverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 公開金鑰 (e, n), 私鑰 (d, n)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">((&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">encrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pk&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">plaintext&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pk&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 計算 plaintext^e mod n&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cipher&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">ord&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">char&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">char&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">plaintext&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">cipher&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">decrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sk&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ciphertext&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sk&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 計算 cipher^d mod n，並轉回字元&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">plain&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nb">chr&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">char&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">char&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">ciphertext&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">plain&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 執行範例&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;--- RSA加密 簡易實作 ---&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">public_key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">private_key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">generate_keypair&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">12&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 使用 12bit 的質數&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;公開金鑰 (e, n): &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">public_key&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;私鑰 (d, n): &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">private_key&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Hello Math!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">原始訊息: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 加密&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">encrypted_msg&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">encrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">public_key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;密文: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">encrypted_msg&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 解密&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">decrypted_msg&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">decrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">private_key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">encrypted_msg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;解密後的訊息: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">decrypted_msg&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>執行這段程式碼後，就可以確認字元陣列如何被轉換成不眼熟的數字陣列（密文），然後再透過私鑰完美還原為原始字串的過程。&lt;/p>
&lt;hr>
&lt;h2 id="9-結語數學之美與實用性的交會點">9. 結語：數學之美與實用性的交會點
&lt;/h2>&lt;p>在 17 世紀，當皮耶·德·費馬發現這個「小定理」時，沒有人認為這會有什麼實際用途。費馬本人也是出於純粹的數學探求心在進行數論的研究。&lt;/p>
&lt;p>然而，大約 300 年後的 1970 年代，在電腦網路的黎明期，作為確立安全通訊協定不可或缺的加密技術，費馬定理實現了戲劇性的復活。基於費馬小定理的質數判定技術，以及基於歐拉定理的 RSA 加密，字面上支撐著現代的網際網路基礎設施。&lt;/p>
&lt;p>我們每天不經意發送的 LINE 訊息、在 Amazon 上的購物，全都是在這個 $a^{p-1} \equiv 1 \pmod p$ 簡單而優美的數學公式之上舞動著的。費馬小定理告訴我們，無論數學多麼抽象，總有一天必定會派上用場。&lt;/p>
&lt;p>在學習程式設計或密碼學理論時，理解其基礎的數學結構，將會成為深入理解那些被當作黑盒子般提供的函式庫運作方式，並設計出更安全系統的一大武器。&lt;/p></description></item><item><title>格子密碼學（Lattice-based cryptography）的數學直觀</title><link>http://kenji.blog/zh-tw/p/lattice-based-cryptography-math-intuition/</link><pubDate>Fri, 11 Sep 2026 21:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/p/lattice-based-cryptography-math-intuition/</guid><description>&lt;img src="http://kenji.blog/p/lattice-based-cryptography-math-intuition/img/eyecatch.jpg" alt="Featured image of post 格子密碼學（Lattice-based cryptography）的數學直觀" />&lt;h1 id="1-導入後量子密碼學pqc的黎明與格子密碼學的崛起">1. 導入：後量子密碼學（PQC）的黎明與格子密碼學的崛起
&lt;/h1>&lt;p>支撐現代社會數位基礎設施的是以 RSA 密碼和橢圓曲線密碼（ECC）為首的公鑰密碼技術。這些密碼系統是將安全性的基礎建立在「質因數分解問題」與「離散對數問題」等數學難題上，人們相信傳統古典電腦無法有效率地解決這些問題（需要指數級時間）。&lt;/p>
&lt;p>然而，彼得·秀爾（Peter Shor）於1994年發表的「秀爾演算法（Shor&amp;rsquo;s algorithm）」在密碼學界引發了震撼。該演算法在數學上證明了，一旦大規模的量子電腦問世，就能在多項式時間內解決質因數分解問題與離散對數問題。這意味著目前被廣泛使用的公鑰密碼學，在未來將完全可能被破解。&lt;/p>
&lt;p>為了對抗這種「量子威脅（Quantum Threat）」，迫切需要研究即使使用量子電腦也難以破解的新型密碼系統。這就是被稱為「後量子密碼學（Post-Quantum Cryptography: PQC）」或「抗量子計算密碼學」的領域。&lt;/p>
&lt;p>PQC 有幾個有力的候選方案。包括基於雜湊的密碼學、基於編碼的密碼學、多變數多項式密碼學以及同源密碼學等，但其中目前最受矚目，且處於 NIST（美國國家標準暨技術研究院）PQC 標準化流程核心的，就是「格子密碼學（Lattice-based cryptography）」。與其他方法相比，格子密碼學具有極快的加密和解密處理速度，並具備一個在密碼理論中極為強大的安全性證明：將「最壞情況複雜度（Worst-case complexity）」歸約至「平均情況複雜度（Average-case complexity）」。&lt;/p>
&lt;p>本文將從作為格子密碼學基礎的「格子（Lattice）」的數學定義出發，深入淺出地解說格子上的困難問題，如 SVP（最短向量問題）和 CVP（最近點向量問題），以及可說是現代格子密碼學心臟的「LWE 問題（Learning With Errors，容錯學習問題）」。文中將結合數學公式、幾何直觀，以及具體的數值範例來進行徹底且深入的解說。&lt;/p>
&lt;h1 id="2-格子lattice的數學定義與幾何直觀">2. 格子（Lattice）的數學定義與幾何直觀
&lt;/h1>&lt;h2 id="21-向量空間與格子">2.1 向量空間與格子
&lt;/h2>&lt;p>在數學中，「格子（Lattice）」是指在 $n$ 維實數向量空間 $\mathbb{R}^n$ 內，有規則地排列的離散點的集合。雖然它與線性代數中學到的向量空間（Vector Space）相似，但有著決定性的差異。向量空間是由基底向量以「實數係數」的線性組合所表示的連續空間，而格子則是由基底向量以「整數係數」的線性組合所表示的離散空間。&lt;/p>
&lt;p>讓我們給出數學上嚴格的定義。考慮在 $m$ 維實數向量空間 $\mathbb{R}^m$ 中的 $n$ 個（$n \le m$）線性獨立的向量 $\mathbf{b}_1, \mathbf{b}_2, \dots, \mathbf{b}_n$。將這些向量作為行向量構成的矩陣設為 $B = [\mathbf{b}_1, \mathbf{b}_2, \dots, \mathbf{b}_n] \in \mathbb{R}^{m \times n}$。我們將這個 $B$ 稱為格子的「基底（Basis）」。&lt;/p>
&lt;p>由這個基底 $B$ 所生成的格子 $\mathcal{L}(B)$ 定義如下：&lt;/p>
$$
\mathcal{L}(B) = \left\{ \sum_{i=1}^{n} x_i \mathbf{b}_i \mathrel{\bigg|} x_i \in \mathbb{Z} \right\} = \{ B \mathbf{x} \mid \mathbf{x} \in \mathbb{Z}^n \}
$$
&lt;p>這裡的重點在於，係數 $x_i$ 僅限於整數 $\mathbb{Z}$，而非實數 $\mathbb{R}$。這使得空間內形成的不是無數連續的點，而是像等間距排列的十字路口般的「離散點的集合」。&lt;/p>
&lt;h2 id="22-幾何直觀">2.2 幾何直觀
&lt;/h2>&lt;p>讓我們以二維平面 $\mathbb{R}^2$ 為例來思考。如果選擇基底向量為 $\mathbf{b}_1 = \begin{pmatrix} 1 \\ 0 \end{pmatrix}$ 與 $\mathbf{b}_2 = \begin{pmatrix} 0 \\ 1 \end{pmatrix}$，由它們生成的格子，將會是座標平面上所有整數座標 $(x, y) \in \mathbb{Z}^2$ 的集合。這是最簡單的「正方格子」。&lt;/p>
&lt;p>然而，格子並不總是正交的。例如，如果我們考慮基底 $\mathbf{b}_1 = \begin{pmatrix} 2 \\ 1 \end{pmatrix}$ 與 $\mathbf{b}_2 = \begin{pmatrix} 1 \\ 3 \end{pmatrix}$，所生成的點將會像傾斜扭曲的網格交點。&lt;/p>
&lt;h2 id="23-基底的非唯一性與么模變換">2.3 基底的非唯一性與么模變換
&lt;/h2>&lt;p>這裡有一個攸關格子密碼學安全性根本的重要性質。那就是「能生成相同格子的基底有無數個」。&lt;/p>
&lt;p>例如，前面提到的由基底 $\mathbf{b}_1 = (1, 0)^T, \mathbf{b}_2 = (0, 1)^T$ 生成的 $\mathbb{Z}^2$ 格子，如果使用 $\mathbf{b}'_1 = (1, 1)^T, \mathbf{b}'_2 = (2, 3)^T$ 這個基底，也會生成完全相同的格子 $\mathbb{Z}^2$。&lt;/p>
&lt;p>某個基底 $B$ 和另一個基底 $B'$ 能生成相同格子的充分必要條件是：存在一個元素均為整數的矩陣 $U \in \mathbb{Z}^{n \times n}$，其行列式為 $\det(U) = \pm 1$，並且可以表示為：
&lt;/p>
$$ B' = B U $$
&lt;p>
這樣的矩陣 $U$ 被稱為「么模矩陣（Unimodular matrix）」。&lt;/p>
&lt;p>在密碼學應用上的基本概念是：將「好的基底（接近正交、由較短向量組成的基底）」作為私鑰，並將「壞的基底（互相極度斜交、由非常長的向量組成的基底）」作為公鑰。隨著維度的增加，要透過計算從壞的基底求出好的基底將會變得非常困難。這就是格子密碼學的基本直觀。&lt;/p>
&lt;h1 id="3-格子中的計算困難問題">3. 格子中的計算困難問題
&lt;/h1>&lt;p>格子密碼學的安全性仰賴於解決格子上特定數學問題的困難度。在這裡，我們介紹最基本且最著名的兩個問題。&lt;/p>
&lt;h2 id="31-最短向量問題shortest-vector-problem-svp">3.1 最短向量問題（Shortest Vector Problem: SVP）
&lt;/h2>&lt;p>SVP 是格子理論中最經典且著名的問題。&lt;/p>
&lt;p>&lt;strong>定義（SVP）：&lt;/strong>
給定任意格子基底 $B$，在該格子 $\mathcal{L}(B)$ 所屬的非零向量中，找出歐幾里得範數（長度）最小的向量 $\mathbf{v}$。&lt;/p>
&lt;p>用數學公式表示，就是求出使得 $\min_{\mathbf{v} \in \mathcal{L}(B) \setminus \{\mathbf{0}\}} \| \mathbf{v} \|$ 成立的 $\mathbf{v}$ 的問題。這個最小的長度記為 $\lambda_1(\mathcal{L})$，被稱為「格子的第一連續最小值（First successive minimum）」。&lt;/p>
&lt;p>如果是在二維或三維的低維度空間，只要畫個圖就能用肉眼找到最短的向量。或者，也可以使用高斯（Gauss）的格子基底歸約演算法等來有效率地解決。然而，當維度 $n$ 達到數百至數千這類高維度時，已知嚴格解出 SVP 是 NP 困難的。&lt;/p>
&lt;p>在現實的密碼學中，使用的是尋找「近似較短向量」的近似 SVP（$\gamma$-SVP），而不是嚴格的最短向量。當近似係數 $\gamma$ 為多項式大小時，該問題仍然被認為是非常困難的。&lt;/p>
&lt;h2 id="32-最近點向量問題closest-vector-problem-cvp">3.2 最近點向量問題（Closest Vector Problem: CVP）
&lt;/h2>&lt;p>CVP 也是格子密碼學中極為重要的問題。&lt;/p>
&lt;p>&lt;strong>定義（CVP）：&lt;/strong>
給定任意格子基底 $B$ 以及空間內任意的目標向量 $\mathbf{t} \in \mathbb{R}^m$（不一定是格子點），找出所有格子點中距離 $\mathbf{t}$ 最近的格子點 $\mathbf{v} \in \mathcal{L}(B)$。&lt;/p>
&lt;p>用數學公式表示，就是尋找使得 $\min_{\mathbf{v} \in \mathcal{L}(B)} \| \mathbf{v} - \mathbf{t} \|$ 成立的格子點 $\mathbf{v}$ 的問題。&lt;/p>
&lt;p>與 SVP 一樣，CVP 在高維度中也是 NP 困難的。從密碼學應用的角度來看，稍後將提到的 LWE 問題，與這個 CVP 的特殊變體（Bounded Distance Decoding: BDD，有界距離解碼）有著密切的關係。&lt;/p>
&lt;h2 id="33-為什麼高維度時會解不出來lll-與-bkz-的極限">3.3 為什麼高維度時會解不出來？（LLL 與 BKZ 的極限）
&lt;/h2>&lt;p>作為解決高維度格子問題的著名演算法，有 LLL 演算法（Lenstra-Lenstra-Lovász algorithm）。LLL 演算法可以在多項式時間內運作，並將格子基底在某種程度上歸約（Reduction）為「好的基底」。然而，LLL 演算法所能找到的最短向量，其長度相對於真正的最短向量有一個呈指數級（$2^{\mathcal{O}(n)}$）增長的近似係數，因此並不足以破解密碼的安全性。&lt;/p>
&lt;p>如果使用對 LLL 進行改良的 BKZ（Block Korkine-Zolotarev）演算法等更強大的基底歸約演算法，就能找到更短的向量，但其計算量會相對於區塊大小（Block size）呈指數級增長。在格子密碼學中，正是透過估算這個 BKZ 演算法的執行時間來決定安全的參數（例如維度 $n$ 的大小等）。在目前 PQC 的標準參數中，維度 $n$ 被設定為 500 到 1000 以上的值，據說即使使用超級電腦或未來的量子電腦，破解所需的時間也會超過宇宙的年齡。&lt;/p>
&lt;h1 id="4-lwe-問題learning-with-errors的數學形式化">4. LWE 問題（Learning With Errors）的數學形式化
&lt;/h1>&lt;p>現代大部分的格子密碼學都基於 2005 年由 Oded Regev 所提出的「LWE 問題（Learning With Errors，容錯學習問題）」。LWE 問題的絕妙之處在於其形式化的簡單性，以及擁有「將最壞情況複雜度歸約為平均情況複雜度」這項強大的數學證明。&lt;/p>
&lt;h2 id="41-無雜訊的線性方程組">4.1 無雜訊的線性方程組
&lt;/h2>&lt;p>為了理解 LWE 問題，首先讓我們先考慮一個沒有雜訊的簡單線性方程組。
假設有一個未知的秘密向量 $\mathbf{s} \in \mathbb{Z}_q^n$（各個分量為 $0$ 到 $q-1$ 的整數）。這裡我們假設 $q$ 是質數。&lt;/p>
&lt;p>隨機選取係數向量 $\mathbf{a}_1, \mathbf{a}_2, \dots \in \mathbb{Z}_q^n$，並計算與秘密向量 $\mathbf{s}$ 的內積（對 $q$ 取模）：
$b_1 = \langle \mathbf{a}_1, \mathbf{s} \rangle \pmod q$
$b_2 = \langle \mathbf{a}_2, \mathbf{s} \rangle \pmod q$
$\vdots$&lt;/p>
&lt;p>只要給定足夠數量（$n$ 個以上）的 $(\mathbf{a}_i, b_i)$ 數對，我們就可以利用線性代數中的「高斯消去法（Gaussian elimination）」，輕鬆地還原出秘密向量 $\mathbf{s}$。這是一個在多項式時間內可以輕易解出的問題。&lt;/p>
&lt;h2 id="42-lwe-問題的定義加入雜訊">4.2 LWE 問題的定義：加入雜訊
&lt;/h2>&lt;p>那麼，如果在這個問題中加入微小的「雜訊（誤差）」，會發生什麼事呢？
這就是 LWE 問題的本質。&lt;/p>
&lt;p>對未知的秘密向量 $\mathbf{s} \in \mathbb{Z}_q^n$，在各個方程式的結果中加入微小的誤差 $e_i \in \mathbb{Z}_q$：
$b_i = \langle \mathbf{a}_i, \mathbf{s} \rangle + e_i \pmod q$&lt;/p>
&lt;p>這裡的 $e_i$ 是一個平均值為 0、標準差相對較小（例如從常態分佈那樣的離散高斯分佈中選取）的微小整數值。
給定的資訊是隨機向量 $\mathbf{a}_i$ 與加上誤差後計算出的 $b_i$ 所構成的數對列表：
$( \mathbf{a}_1, b_1 ), ( \mathbf{a}_2, b_2 ), \dots, ( \mathbf{a}_m, b_m )$&lt;/p>
&lt;p>用矩陣來表示會非常簡潔：
使用隨機矩陣 $A \in \mathbb{Z}_q^{m \times n}$、秘密向量 $\mathbf{s} \in \mathbb{Z}_q^n$、誤差向量 $\mathbf{e} \in \mathbb{Z}_q^m$，可以寫成：
&lt;/p>
$$ \mathbf{b} = A \mathbf{s} + \mathbf{e} \pmod q $$
&lt;p>
我們只會被給予 $A$ 和 $\mathbf{b}$。從中求出 $\mathbf{s}$ 的問題就是「搜尋 LWE 問題（Search LWE problem）」。&lt;/p>
&lt;p>因為加入了誤差 $e_i$，如果試圖使用高斯消去法，在方程式加減的過程中誤差會呈指數級放大，最終將無法推導出正確的答案。乍看之下這只是一個簡單的線性方程組，但僅僅因為加入了這個微小的雜訊，問題的難度就躍升至 NP 困難的層級。&lt;/p>
&lt;h2 id="43-判定-lwe-問題decision-lwe">4.3 判定 LWE 問題（Decision LWE）
&lt;/h2>&lt;p>在密碼理論的證明中頻繁使用的，是搜尋 LWE 問題的變體——「判定 LWE 問題（Decision LWE problem）」。&lt;/p>
&lt;p>判定 LWE 問題是指，給定一個從以下兩種分佈中取得樣本的列表時，判定它來自哪一種分佈的問題：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>LWE 分佈&lt;/strong>：刻意計算出的 $(A, \mathbf{b} = A\mathbf{s} + \mathbf{e} \pmod q)$&lt;/li>
&lt;li>&lt;strong>均勻隨機分佈&lt;/strong>：由完全隨機選取的矩陣 $A$ 與向量 $\mathbf{u}$ 所構成的 $(A, \mathbf{u})$&lt;/li>
&lt;/ol>
&lt;p>令人驚訝的是，只要適當地選擇 LWE 問題的參數，從 LWE 分佈取得的數對，將與完全隨機資料的數對「在計算上不可區分（Computationally Indistinguishable）」。這個性質正是基於 LWE 的密碼能夠生成「與隨機數無法區分的密文」的根據。&lt;/p>
&lt;h2 id="44-從最壞情況複雜度到平均情況複雜度的歸約regev-定理">4.4 從最壞情況複雜度到平均情況複雜度的歸約（Regev 定理）
&lt;/h2>&lt;p>Oded Regev 最大的貢獻，就是將這個 LWE 問題的困難度，在數學上與前述的格子問題（SVP 與 CVP）的困難度連結了起來。&lt;/p>
&lt;p>他運用了量子歸約（Quantum reduction），證明了「如果存在能在平均情況下（對於隨機選取的 $A$ 和 $\mathbf{e}$）在多項式時間內解決 LWE 問題的演算法，那麼就存在能在多項式時間內解決任何格子在最壞情況下（最難的情況）的 Gap-SVP 的量子演算法」。（後來，Peikert 等人也提出了古典歸約的證明）。&lt;/p>
&lt;p>這在密碼理論中是一個夢寐以求的性質。因為它消除了「密碼被破解，可能只是因為我們碰巧選到了弱的密鑰（平均情況中的一小部分）」這種疑慮，並提供了「如果能解決平均情況的 LWE，就能解決格子中所有最難的問題（因此 LWE 絕對是困難的）」這樣強大的保證。&lt;/p>
&lt;div class="mermaid">graph TD
A["最壞情況的格子問題 (Gap-SVP, SIVP)"] -->|量子/古典歸約| B["平均情況的 LWE 問題"]
B -->|密碼學構造| C["基於 LWE 的密碼系統 (PKE, KEM, FHE)"]
style A fill:#ffcccc,stroke:#ff0000,stroke-width:2px,color:#000
style B fill:#ccffcc,stroke:#00aa00,stroke-width:2px,color:#000
style C fill:#ccccff,stroke:#0000ff,stroke-width:2px,color:#000&lt;/div>
&lt;h1 id="5-基於-lwe-的公鑰密碼系統regev-密碼的建構">5. 基於 LWE 的公鑰密碼系統（Regev 密碼）的建構
&lt;/h1>&lt;p>了解了 LWE 問題的困難度之後，我們來看看如何使用它進行加密和解密，也就是 Oded Regev 所提出的基本公鑰密碼系統。這裡將解說對 1 位元訊息 $M \in \{0, 1\}$ 進行加密的最基本機制。&lt;/p>
&lt;h2 id="51-金鑰生成key-generation">5.1 金鑰生成（Key Generation）
&lt;/h2>&lt;ol>
&lt;li>作為系統參數，決定模數質數 $q$、維度 $n$、方程式數量 $m$（$m > n \log q$）。&lt;/li>
&lt;li>隨機選取向量 $\mathbf{s} \in \mathbb{Z}_q^n$ 作為私鑰。&lt;/li>
&lt;li>生成隨機矩陣 $A \in \mathbb{Z}_q^{m \times n}$。&lt;/li>
&lt;li>從離散高斯分佈等誤差分佈中選取微小的誤差向量 $\mathbf{e} \in \mathbb{Z}_q^m$。&lt;/li>
&lt;li>計算向量 $\mathbf{b} = A \mathbf{s} + \mathbf{e} \pmod q$。&lt;/li>
&lt;li>公鑰（Public Key）為 $(A, \mathbf{b})$。&lt;/li>
&lt;li>私鑰（Secret Key）為 $\mathbf{s}$。&lt;/li>
&lt;/ol>
&lt;p>公鑰本身簡直就是「LWE 問題的實例」。由於從公鑰 $(A, \mathbf{b})$ 求出私鑰 $\mathbf{s}$ 等同於解決搜尋 LWE 問題，因此保證了其安全性。&lt;/p>
&lt;h2 id="52-加密encryption">5.2 加密（Encryption）
&lt;/h2>&lt;p>愛麗絲使用鮑伯的公鑰 $(A, \mathbf{b})$，對 1 位元訊息 $M \in \{0, 1\}$ 進行加密。&lt;/p>
&lt;ol>
&lt;li>隨機選取一個二進位向量（各分量為 0 或 1）$\mathbf{r} \in \{0, 1\}^m$。&lt;/li>
&lt;li>計算向量 $\mathbf{u} = A^T \mathbf{r} \pmod q$，作為密文的前半部。（$A^T$ 是 $A$ 的轉置矩陣。也就是說，這是在將 $A$ 的列中與 $\mathbf{r}$ 分量為 1 對應的那些列加總起來）。&lt;/li>
&lt;li>計算純量 $v = \mathbf{b}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor \pmod q$，作為密文的後半部。
（如果訊息 $M$ 為 0，則不加任何東西；如果為 1，則加上正好是 $q$ 一半的值 $\lfloor \frac{q}{2} \rfloor$）。&lt;/li>
&lt;li>密文（Ciphertext）為 $(\mathbf{u}, v)$。&lt;/li>
&lt;/ol>
&lt;p>加密直觀上的意義，是針對公鑰的矩陣 $A$ 和向量 $\mathbf{b}$ 取「隨機子集的和」。由於判定 LWE 問題的困難度，這個密文 $(\mathbf{u}, v)$ 看起來將與完全隨機的向量和均勻隨機數無法區分（語意安全性：Semantic Security）。&lt;/p>
&lt;div class="mermaid">flowchart LR
M["訊息 M 屬於 {0,1}"] --> Enc
PK["公鑰 (A, b)"] --> Enc
r["隨機二進位向量 r"] --> Enc
subgraph Enc ["加密過程"]
direction TB
u_calc["u = A^T * r mod q"]
v_calc["v = b^T * r + M * floor(q/2) mod q"]
end
Enc --> CT["密文 (u, v)"]&lt;/div>
&lt;h2 id="53-解密decryption">5.3 解密（Decryption）
&lt;/h2>&lt;p>鮑伯使用私鑰 $\mathbf{s}$ 來解密密文 $(\mathbf{u}, v)$。&lt;/p>
&lt;ol>
&lt;li>計算以下的值： $D = v - \mathbf{s}^T \mathbf{u} \pmod q$&lt;/li>
&lt;li>如果計算結果接近 $0$，則輸出 $M=0$；如果接近 $\lfloor \frac{q}{2} \rfloor$，則輸出 $M=1$。&lt;/li>
&lt;/ol>
&lt;p>為什麼這樣就能解密呢？讓我們在數學上展開來看看。
請回憶一下 $\mathbf{b} = A \mathbf{s} + \mathbf{e}$。&lt;/p>
$$
\begin{aligned}
v - \mathbf{s}^T \mathbf{u} &amp;= (\mathbf{b}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor) - \mathbf{s}^T (A^T \mathbf{r}) \\
&amp;= ((A \mathbf{s} + \mathbf{e})^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor) - \mathbf{s}^T A^T \mathbf{r} \\
&amp;= (\mathbf{s}^T A^T \mathbf{r} + \mathbf{e}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor) - \mathbf{s}^T A^T \mathbf{r} \\
&amp;= \mathbf{e}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor \pmod q
\end{aligned}
$$
&lt;p>在這裡，公式中的 $\mathbf{s}^T A^T \mathbf{r}$ 被完美地抵消掉了！
剩下的部分是 $\mathbf{e}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor$。&lt;/p>
&lt;p>$\mathbf{e}$ 是分量非常小的雜訊向量，而 $\mathbf{r}$ 是分量為 0 或 1 的二進位向量。因此，它們的內積 $\mathbf{e}^T \mathbf{r}$ 也會（只要參數設定得當）保持在一個相對較小的值。&lt;/p>
&lt;ul>
&lt;li>如果 $M=0$，結果會是 $\mathbf{e}^T \mathbf{r}$，這是一個接近 $0$ 的小數值。&lt;/li>
&lt;li>如果 $M=1$，結果會是 $\mathbf{e}^T \mathbf{r} + \lfloor \frac{q}{2} \rfloor$，這會位於 $q$ 的一半即 $\lfloor \frac{q}{2} \rfloor$ 附近。&lt;/li>
&lt;/ul>
&lt;p>只要參數的設計能讓誤差 $\mathbf{e}^T \mathbf{r}$ 的絕對值收斂在 $\frac{q}{4}$ 以內，鮑伯只需要看計算結果是比較接近 $0$ 還是 $\lfloor \frac{q}{2} \rfloor$，就能正確地判定（解密）訊息 $M$。這就是基於 LWE 的密碼能夠運作的美妙機制。&lt;/p>
&lt;div class="mermaid">flowchart LR
CT["密文 (u, v)"] --> Dec
SK["私鑰 s"] --> Dec
subgraph Dec ["解密過程"]
direction TB
calc["計算 D = v - s^T * u mod q"]
check["檢查 D 是接近 0 還是 q/2"]
end
calc --> check
Dec --> M_out["還原出的訊息 M"]&lt;/div>
&lt;h1 id="6-使用具體數值的-lwe-密碼玩具範例">6. 使用具體數值的 LWE 密碼玩具範例
&lt;/h1>&lt;p>只看一堆數學公式可能很難有真實感，所以我們實際設定極小的數值參數，來追蹤一次從加密到解密的計算過程。
（※在現實的密碼系統中，為了確保安全性，$n$ 會設定在 500 以上，$q$ 則是使用數千以上的值）&lt;/p>
&lt;p>&lt;strong>【參數設定】&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>模數 $q = 17$ （質數。因此值會落在 $0$ 到 $16$ 的範圍內）&lt;/li>
&lt;li>維度 $n = 2$&lt;/li>
&lt;li>方程式數量 $m = 4$&lt;/li>
&lt;li>假設要加密的訊息為 $M = 1$。&lt;/li>
&lt;li>訊息的位移量：$\lfloor \frac{q}{2} \rfloor = \lfloor \frac{17}{2} \rfloor = 8$&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>【1. 金鑰生成階段】&lt;/strong>
鮑伯隨機選取私鑰 $\mathbf{s}$、矩陣 $A$ 以及誤差向量 $\mathbf{e}$。
&lt;/p>
$$ \mathbf{s} = \begin{pmatrix} 3 \\ 4 \end{pmatrix} \in \mathbb{Z}_{17}^2 $$
$$ A = \begin{pmatrix} 2 &amp; 15 \\ 1 &amp; 8 \\ 14 &amp; 5 \\ 9 &amp; 10 \end{pmatrix} \in \mathbb{Z}_{17}^{4 \times 2} $$
$$ \mathbf{e} = \begin{pmatrix} 1 \\ -1 \\ 0 \\ 2 \end{pmatrix} \equiv \begin{pmatrix} 1 \\ 16 \\ 0 \\ 2 \end{pmatrix} \pmod{17} $$
&lt;p>接著計算公鑰 $\mathbf{b}$。
&lt;/p>
$$ A \mathbf{s} = \begin{pmatrix} 2 &amp; 15 \\ 1 &amp; 8 \\ 14 &amp; 5 \\ 9 &amp; 10 \end{pmatrix} \begin{pmatrix} 3 \\ 4 \end{pmatrix} = \begin{pmatrix} 2\times 3 + 15\times 4 \\ 1\times 3 + 8\times 4 \\ 14\times 3 + 5\times 4 \\ 9\times 3 + 10\times 4 \end{pmatrix} = \begin{pmatrix} 6 + 60 \\ 3 + 32 \\ 42 + 20 \\ 27 + 40 \end{pmatrix} = \begin{pmatrix} 66 \\ 35 \\ 62 \\ 67 \end{pmatrix} $$
&lt;p>
將其對 17 取模。($66 = 17 \times 3 + 15$ 等)
&lt;/p>
$$ A \mathbf{s} \pmod{17} = \begin{pmatrix} 15 \\ 1 \\ 11 \\ 16 \end{pmatrix} $$
&lt;p>
加上誤差向量 $\mathbf{e}$。
&lt;/p>
$$ \mathbf{b} = A \mathbf{s} + \mathbf{e} = \begin{pmatrix} 15 \\ 1 \\ 11 \\ 16 \end{pmatrix} + \begin{pmatrix} 1 \\ 16 \\ 0 \\ 2 \end{pmatrix} = \begin{pmatrix} 16 \\ 17 \\ 11 \\ 18 \end{pmatrix} \equiv \begin{pmatrix} 16 \\ 0 \\ 11 \\ 1 \end{pmatrix} \pmod{17} $$
&lt;p>公鑰為 $A$ 與 $\mathbf{b} = (16, 0, 11, 1)^T$。&lt;/p>
&lt;p>&lt;strong>【2. 加密階段】&lt;/strong>
愛麗絲加密訊息 $M = 1$。
選取一個隨機向量 $\mathbf{r}$。這裡假設 $\mathbf{r} = (1, 0, 1, 0)^T$。&lt;/p>
&lt;p>計算 $\mathbf{u}$。
&lt;/p>
$$ \mathbf{u} = A^T \mathbf{r} = \begin{pmatrix} 2 &amp; 1 &amp; 14 &amp; 9 \\ 15 &amp; 8 &amp; 5 &amp; 10 \end{pmatrix} \begin{pmatrix} 1 \\ 0 \\ 1 \\ 0 \end{pmatrix} = \begin{pmatrix} 2 \times 1 + 14 \times 1 \\ 15 \times 1 + 5 \times 1 \end{pmatrix} = \begin{pmatrix} 16 \\ 20 \end{pmatrix} \equiv \begin{pmatrix} 16 \\ 3 \end{pmatrix} \pmod{17} $$
&lt;p>計算 $v$。
&lt;/p>
$$ \mathbf{b}^T \mathbf{r} = (16, 0, 11, 1) \begin{pmatrix} 1 \\ 0 \\ 1 \\ 0 \end{pmatrix} = 16 \times 1 + 11 \times 1 = 27 \equiv 10 \pmod{17} $$
&lt;p>
加上對應於訊息 $M=1$ 的值 $\lfloor 17/2 \rfloor = 8$。
&lt;/p>
$$ v = \mathbf{b}^T \mathbf{r} + M \cdot 8 = 10 + 1 \times 8 = 18 \equiv 1 \pmod{17} $$
&lt;p>愛麗絲將密文 $(\mathbf{u}, v) = \left( \begin{pmatrix} 16 \\ 3 \end{pmatrix}, 1 \right)$ 傳送給鮑伯。&lt;/p>
&lt;p>&lt;strong>【3. 解密階段】&lt;/strong>
收到密文的鮑伯，使用私鑰 $\mathbf{s} = (3, 4)^T$ 進行解密。
計算解密處理公式： $D = v - \mathbf{s}^T \mathbf{u} \pmod{17}$。&lt;/p>
$$ \mathbf{s}^T \mathbf{u} = (3, 4) \begin{pmatrix} 16 \\ 3 \end{pmatrix} = 3 \times 16 + 4 \times 3 = 48 + 12 = 60 \equiv 9 \pmod{17} $$
$$ D = v - \mathbf{s}^T \mathbf{u} = 1 - 9 = -8 \pmod{17} $$
&lt;p>在這裡，在模 17 的世界中，$-8$ 等於 $9$（$-8 + 17 = 9$）。
判斷得到的值 $D = 9$ 是比較接近 $0$ 還是 $8$（$\lfloor 17/2 \rfloor$）。
因為 $9$ 明顯比接近 $0$ 更接近 $8$，所以鮑伯正確地還原出了 $M = 1$！&lt;/p>
&lt;p>為什麼會變成 $9$ 呢？讓我們回想一下先前的證明。
誤差部分為 $\mathbf{e}^T \mathbf{r} = (1, -1, 0, 2) (1, 0, 1, 0)^T = 1 \times 1 + 0 \times 1 = 1$。
因此，計算結果會是 $\mathbf{e}^T \mathbf{r} + M \cdot 8 = 1 + 8 = 9$，證實了算出來的值符合理論預期。&lt;/p>
&lt;h1 id="7-邁向實用化的演進ring-lwe-與-module-lwe">7. 邁向實用化的演進：Ring-LWE 與 Module-LWE
&lt;/h1>&lt;p>我們到目前為止所說明的標準 LWE 問題（Standard LWE），雖然擁有非常強大的安全性證明，但在實際應用上卻有一個致命的弱點。那就是「金鑰的容量會變得十分巨大」以及「計算成本過高」。&lt;/p>
&lt;p>在 Standard LWE 中，公鑰包含了一個巨大的矩陣 $A \in \mathbb{Z}_q^{m \times n}$。當參數 $n$ 達到數百至數千時，這個矩陣的容量會達到數百萬位元組（MB）之多，要在網際網路通訊協定（如 TLS）中每次傳送和接收的話，負擔會太重。此外，矩陣與向量的乘法運算會花費 $\mathcal{O}(n^2)$ 的計算量。&lt;/p>
&lt;p>為了解決這個問題而導入的，是將名為多項式環（Polynomial rings）的代數結構結合到格子上的「Ring-LWE（RLWE）」以及「Module-LWE（MLWE）」。&lt;/p>
&lt;h2 id="71-ring-lwe-的直觀">7.1 Ring-LWE 的直觀
&lt;/h2>&lt;p>在 Ring-LWE 中，我們將向量與矩陣替換成多項式環 $\mathcal{R}_q = \mathbb{Z}_q[X]/(X^n + 1)$ 上的元素（多項式）。（這裡的 $n$ 會選擇 2 的次方數）。&lt;/p>
&lt;p>相對於 Standard LWE 的公鑰是矩陣 $A$，Ring-LWE 則是使用單一的多項式 $a(x)$。私鑰 $s(x)$ 與誤差 $e(x)$ 也都會變成多項式。
方程式會變成如下所示：
&lt;/p>
$$ b(x) = a(x) \cdot s(x) + e(x) \pmod q $$
&lt;p>因為這是多項式的乘法，所以可以透過使用類似於快速傅立葉變換（FFT）的「數論轉換（Number Theoretic Transform: NTT）」，將計算量大幅縮減至 $\mathcal{O}(n \log n)$。此外，因為公鑰的容量也從矩陣縮減成了單一多項式，所以資料大小減少到了 $\mathcal{O}(n)$。這在通訊頻寬上帶來了壓倒性的優勢。&lt;/p>
&lt;p>從數學角度來看，Ring-LWE 解決的不再是一般的格子，而是歸約到具有特殊對稱性，被稱為「理想格子（Ideal Lattice）」上的問題。&lt;/p>
&lt;h2 id="72-module-lwe-與-nist-的標準化kyber--ml-kem">7.2 Module-LWE 與 NIST 的標準化（Kyber / ML-KEM）
&lt;/h2>&lt;p>Ring-LWE 雖然效率很高，但卻也令人擔心理想格子特殊的代數結構會不會成為未來攻擊的突破口。因此，擷取 Standard LWE 的保守安全性以及 Ring-LWE 效率的「兩全其美」方案，就是「Module-LWE（MLWE）」。&lt;/p>
&lt;p>在 Module-LWE 中，我們考慮的是以多項式為元素所構成的小型矩陣和向量。也就是說，處理的是環上的模組（Module，加群）。
目前，被 NIST 選定作為 PQC 金鑰交換演算法（KEM）標準的「CRYSTALS-Kyber」（標準化名稱：ML-KEM），正是建構在這個 Module-LWE 問題的困難度之上。&lt;/p>
&lt;h1 id="8-為什麼對量子電腦是安全的">8. 為什麼對量子電腦是安全的？
&lt;/h1>&lt;p>最後，我們來探討一個核心問題：「為什麼格子密碼學被認為即使使用量子電腦也無法破解？」&lt;/p>
&lt;p>量子電腦用來破解 RSA 密碼與橢圓曲線密碼的秀爾演算法，本質上是一個用於解決「隱含子群問題（Hidden Subgroup Problem: HSP）」的演算法。RSA 或 ECC 背後的數學結構（有限阿貝爾群）具有週期性，透過使用名為量子傅立葉變換（QFT）的量子演算法特有操作，可以一次萃取出這個週期（隱含的子群）。&lt;/p>
&lt;p>然而，格子問題卻截然不同。格子雖然也有週期性，但在 SVP 或 CVP 中要求出的是「最短距離」或「消除雜訊」這種幾何學上的非線性性質。即使直接套用像秀爾演算法這種「阿貝爾群上的量子傅立葉變換」，也無法有效率地萃取出對解答格子問題有用的資訊。截至目前為止，尚未發現能在多項式時間內解決 SVP 或 LWE 的量子演算法，學界普遍相信，即使擁有量子電腦的平行計算能力，也只有類似於暴力破解的搜尋方式（透過葛羅夫演算法（Grover&amp;rsquo;s algorithm）達成的平方根加速程度）才是有效的手段。&lt;/p>
&lt;h1 id="9-總結">9. 總結
&lt;/h1>&lt;p>本文中，我們從格子的幾何定義開始，詳細地解說了格子密碼學的數學直觀，包括 LWE 問題的形式化，一直到公鑰密碼系統的建構。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>格子（Lattice）&lt;/strong> 是一個由基底向量以整數係數進行線性組合所表示的離散空間，在高維度下，要找到接近正交的「好基底」（SVP）將會變得困難。&lt;/li>
&lt;li>&lt;strong>LWE 問題（Learning With Errors）&lt;/strong> 是一個求解帶有雜訊的線性方程組的問題，因為這與格子在最壞情況下問題的困難度息息相關，所以能提供強大的安全性基礎。&lt;/li>
&lt;li>透過利用 LWE 問題，藉由刻意加入或消除雜訊的精妙機制，實現了加密與解密（&lt;strong>Regev 密碼&lt;/strong>）。&lt;/li>
&lt;li>在現實的協定中，為了提升通訊效率和計算速度，採用了使用多項式環的 &lt;strong>Ring-LWE&lt;/strong> 與 &lt;strong>Module-LWE&lt;/strong>，並成為了 NIST 標準 &lt;strong>ML-KEM&lt;/strong> 的基礎。&lt;/li>
&lt;/ol>
&lt;p>在量子電腦帶來前所未有的計算典範轉移之際，誕生於古典線性代數與數論深淵之中的「格子密碼學」，將肩負起未來網際網路安全基礎的重任，這是一件非常浪漫的事情。格子密碼學基礎的數學絕非過於艱澀難懂，只要具備線性代數與機率的基礎知識，就能充分理解其優美的結構。希望本文能幫助您理解作為 PQC 核心的格子密碼學。&lt;/p></description></item><item><title>黎曼猜想與質數分佈：與現代密碼學的深層關聯</title><link>http://kenji.blog/zh-tw/p/riemann-hypothesis-prime-distribution-cryptography/</link><pubDate>Fri, 11 Sep 2026 16:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/p/riemann-hypothesis-prime-distribution-cryptography/</guid><description>&lt;img src="http://kenji.blog/p/riemann-hypothesis-prime-distribution-cryptography/img/eyecatch.jpg" alt="Featured image of post 黎曼猜想與質數分佈：與現代密碼學的深層關聯" />&lt;h1 id="1-前言質數這宇宙之謎與黎曼猜想">1. 前言：質數這宇宙之謎與黎曼猜想
&lt;/h1>&lt;p>「質數（Prime Numbers）」是只能被1和自己整除的自然數，在數學世界中也被稱為「原子」。2, 3, 5, 7, 11, 13&amp;hellip; 這般延續的數列，乍看之下似乎毫無秩序、隨機出現。自從古希臘數學家歐幾里得證明了「質數有無窮多個」以來，無數的數學家們便不斷挑戰，試圖解開隱藏在這個質數排列中的規律。&lt;/p>
&lt;p>最逼近這個質數之謎的，是1859年由德國數學家波恩哈德·黎曼（Bernhard Riemann）所提出的**「黎曼猜想（Riemann Hypothesis）」**。黎曼猜想是現代數學中最重要且未解決的難題之一，被克雷數學研究所列為千禧年大獎難題之一，並懸賞了100萬美元的獎金。&lt;/p>
&lt;p>乍看之下，關於質數分佈的純數學難題，似乎與我們的日常生活毫無關聯。然而，支撐現代社會基礎設施的網際網路安全，特別是&lt;strong>RSA加密和橢圓曲線密碼學（ECC）等現代密碼技術&lt;/strong>，都深深依賴於巨大質數的性質。&lt;/p>
&lt;p>本篇文章將帶領讀者踏上一段數學之旅，從質數分佈、質數定理、黎曼ζ函數，一路探討到黎曼猜想的核心，並極為詳細且深入地解說它如何與現代密碼技術相結合，以及如果黎曼猜想被證明，世界將會發生什麼樣的變化。&lt;/p>
&lt;hr>
&lt;h1 id="2-質數定理與質數分佈高斯的發現">2. 質數定理與質數分佈：高斯的發現
&lt;/h1>&lt;p>為了解質數是如何分佈的，數學家們構想出了&lt;strong>質數計數函數（Prime-counting function）&lt;/strong> $\pi(x)$，用來表示「小於等於某個數 $x$ 的質數有多少個」。&lt;/p>
&lt;p>例如：&lt;/p>
&lt;ul>
&lt;li>$\pi(10) = 4$ （2, 3, 5, 7）&lt;/li>
&lt;li>$\pi(100) = 25$&lt;/li>
&lt;li>$\pi(1000) = 168$&lt;/li>
&lt;/ul>
&lt;p>15歲的天才數學家卡爾·弗里德里希·高斯（Carl Friedrich Gauss）在計算了龐大的質數表後，發現質數的出現頻率與自然對數 $\ln x$ 成反比地遞減。也就是說，他猜想在某個數 $x$ 附近找到質數的機率大約是 $\frac{1}{\ln x}$。&lt;/p>
&lt;p>將這個猜想用積分來表現，就是&lt;strong>對數積分（Logarithmic integral）&lt;/strong> $\text{Li}(x)$：&lt;/p>
$$ \text{Li}(x) = \int_{2}^{x} \frac{dt}{\ln t} $$
&lt;p>高斯的猜想後來在1896年由雅克·阿達馬和夏爾-讓·德拉瓦萊·普桑各自獨立證明，並確立為&lt;strong>質數定理（Prime Number Theorem, PNT）&lt;/strong>。&lt;/p>
$$ \lim_{x \to \infty} \frac{\pi(x)}{\text{Li}(x)} = 1 $$
&lt;p>或者近似地表示如下：&lt;/p>
$$ \pi(x) \sim \frac{x}{\ln x} $$
&lt;p>透過這個定理，我們了解到從巨觀來看，質數具有非常平滑且可預測的分佈。然而，從微觀來看，$\pi(x)$ 和 $\text{Li}(x)$ 之間總是存在著「誤差」，也就是「波動」。這個波動的真面目，正是黎曼猜想所試圖解開的最大謎團。&lt;/p>
&lt;hr>
&lt;h1 id="3-黎曼ζ函數與歐拉乘積">3. 黎曼ζ函數與歐拉乘積
&lt;/h1>&lt;p>在解析質數分佈時，最強大的武器就是&lt;strong>黎曼ζ函數（Riemann Zeta Function）&lt;/strong>。這原本是由萊昂哈德·歐拉（Leonhard Euler）針對實數 $s > 1$ 所定義的無窮級數。&lt;/p>
$$ \zeta(s) = \sum_{n=1}^\infty \frac{1}{n^s} = 1 + \frac{1}{2^s} + \frac{1}{3^s} + \frac{1}{4^s} + \dots $$
&lt;p>歐拉最大的貢獻之一，就是證明了這個無窮級數可以表示為所有質數 $p$ 的無窮乘積。這就是&lt;strong>歐拉乘積（Euler Product Formula）&lt;/strong>。&lt;/p>
$$ \zeta(s) = \prod_{p \text{ prime}} \frac{1}{1 - p^{-s}} = \left( \frac{1}{1 - 2^{-s}} \right) \left( \frac{1}{1 - 3^{-s}} \right) \left( \frac{1}{1 - 5^{-s}} \right) \dots $$
&lt;p>這個證明的直觀理解是，將等式右邊的每一項展開為等比級數並將它們相乘，根據算術基本定理（每個自然數都可以唯一地表示為質數的乘積），等式左邊的自然數倒數和將會被完美地重構出來。&lt;/p>
&lt;p>&lt;strong>就這麼一個數學公式，成為了連結分析學（無窮級數・連續函數）與數論（質數・離散數）的橋樑。&lt;/strong> 研究ζ函數，就等同於研究質數的分佈。&lt;/p>
&lt;hr>
&lt;h1 id="4-解析延拓與複數平面的擴展">4. 解析延拓與複數平面的擴展
&lt;/h1>&lt;p>黎曼的天才之處在於，他將歐拉原本只在實數範圍內考慮的 $\zeta(s)$ 的變數 $s$，擴展到了&lt;strong>複數 $s = \sigma + it$（$\sigma$ 為實部，$t$ 為虛部）&lt;/strong>。&lt;/p>
&lt;p>原本的無窮級數只在 $\sigma > 1$ 時收斂，但黎曼使用了「解析延拓（Analytic Continuation）」的手法，將 $\zeta(s)$ 的定義擴展到除了極點 $s = 1$ 之外的整個複數平面上，使其具有意義。&lt;/p>
&lt;p>他更進一步導出了ζ函數所滿足的優美函數方程式（Functional equation）：&lt;/p>
$$ \zeta(s) = 2^s \pi^{s-1} \sin\left(\frac{\pi s}{2}\right) \Gamma(1-s) \zeta(1-s) $$
&lt;p>這裡的 $\Gamma(x)$ 是伽瑪函數。透過這個方程式，我們可以從右半平面的性質得知左半平面的性質。&lt;/p>
&lt;h3 id="零點zeros-of-the-zeta-function">零點（Zeros of the Zeta Function）
&lt;/h3>&lt;p>使ζ函數的值為 0 的複數 $s$ 被稱為「零點」。
由函數方程式可知，當 $s$ 為負偶數（$-2, -4, -6, \dots$）時，$\sin(\pi s / 2)$ 會變成 0，因此 $\zeta(s) = 0$。這些被稱為&lt;strong>平凡零點（Trivial zeros）&lt;/strong>。&lt;/p>
&lt;p>然而，在質數分佈中真正重要的，是除此之外的零點，也就是存在於 $0 \le \sigma \le 1$ 的「臨界帶（Critical strip）」內的&lt;strong>非平凡零點（Non-trivial zeros）&lt;/strong>。&lt;/p>
&lt;hr>
&lt;h1 id="5-黎曼猜想的核心與顯式公式">5. 黎曼猜想的核心與顯式公式
&lt;/h1>&lt;p>黎曼計算了少數幾個零點，並提出了一個令人驚嘆的猜想。這就是&lt;strong>黎曼猜想&lt;/strong>。&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>黎曼猜想 (Riemann Hypothesis)&lt;/strong>
黎曼ζ函數 $\zeta(s)$ 的所有非平凡零點，其實部都位於 $1/2$ 的直線上（$\text{Re}(s) = 1/2$）。&lt;/p>
&lt;/blockquote>
&lt;p>這條實部為1/2的直線被稱為「臨界線（Critical line）」。&lt;/p>
&lt;div class="mermaid">graph TD
A["黎曼ζ函數 ζ(s)"] --> B["透過解析延拓擴展至複數平面"]
B --> C["平凡零點 (s = -2, -4, -6 ...)"]
B --> D["非平凡零點 (0 &lt;= Re(s) &lt;= 1)"]
D --> E["黎曼猜想"]
E --> F["所有非平凡零點皆位於 Re(s) = 1/2 上"]
F --> G["通往質數分佈誤差項極限的證明"]&lt;/div>
&lt;p>為什麼黎曼猜想會如此重要呢？那是因為，ζ函數的零點&lt;strong>完全&lt;/strong>決定了質數的分佈。&lt;/p>
&lt;p>黎曼與後來的數學家馮·曼戈爾特，導出了一個能精確描述質數分佈的「顯式公式（Explicit formula）」。使用切比雪夫函數 $\psi(x)$，可以表示如下：&lt;/p>
$$ \psi(x) = x - \sum_{\rho} \frac{x^\rho}{\rho} - \ln(2\pi) - \frac{1}{2}\ln(1 - x^{-2}) $$
&lt;p>這裡的 $\rho$ 遍歷ζ函數的所有非平凡零點。
主項是 $x$（這對應於質數定理），從中加上或減去依賴於零點 $\rho$ 的波狀項，就能精確還原質數階梯狀的分佈。可以說，非平凡零點代表了質數分佈的「頻率（波）」。&lt;/p>
&lt;p>如果黎曼猜想是正確的，也就是所有非平凡零點 $\rho$ 的實部恰好都是 $1/2$，那麼質數定理的誤差項將會在理論上可預期的最小範圍內。&lt;/p>
$$ |\pi(x) - \text{Li}(x)| \le \frac{1}{8\pi} \sqrt{x} \ln x \quad \text{for} \quad x \ge 2657 $$
&lt;p>也就是說，&lt;strong>如果黎曼猜想為真，這將證明質數是以我們所能想像最「規律、優美」的方式分佈著。&lt;/strong>&lt;/p>
&lt;hr>
&lt;h1 id="6-現代密碼技術與質數不可分割的關係">6. 現代密碼技術與質數不可分割的關係
&lt;/h1>&lt;p>到目前為止，我們探討的是深奧的純數學世界，但這些質數的性質，卻從根本上支撐著現代數位社會。其代表性例子，便是以&lt;strong>RSA加密&lt;/strong>為首的公開金鑰密碼系統。&lt;/p>
&lt;p>網際網路上的信用卡支付、密碼傳輸、區塊鏈的數位簽章等，所有通訊的安全性都依賴於「質數」。&lt;/p>
&lt;h3 id="rsa加密的運作原理">RSA加密的運作原理
&lt;/h3>&lt;p>RSA加密的安全性，建立在「將位數極大的合成數進行質因數分解是非常困難的」這個數學事實（質因數分解問題）之上。&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>金鑰生成&lt;/strong>:
隨機選擇兩個巨大的質數 $p$ 和 $q$（例如各2048位元）。
將它們相乘計算出 $N = p \times q$。這個 $N$ 將成為公開金鑰的一部分。
利用歐拉函數 $\phi(N) = (p-1)(q-1)$，生成私鑰 $d$。&lt;/p>
$$ e \times d \equiv 1 \pmod{\phi(N)} $$
&lt;/li>
&lt;li>
&lt;p>&lt;strong>加密與解密&lt;/strong>:
明文 $M$ 使用公開金鑰 $e, N$ 轉換為密文 $C$。
&lt;/p>
$$ C \equiv M^e \pmod{N} $$
&lt;p>
只有擁有私鑰 $d$ 的人才能解密。
&lt;/p>
$$ M \equiv C^d \pmod{N} $$
&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph LR
A["明文 (Plaintext)"] --> B["使用公開金鑰(e, N)進行加密"]
B --> C["密文 (Ciphertext)"]
C --> D["使用私鑰(d)進行解密"]
D --> E["原始明文"]
F["攻擊者 (Attacker)"] -- "嘗試對N進行質因數分解" --> C
F -.-> G["若不知道p與q，則無法計算出d"]&lt;/div>
&lt;p>要破解RSA加密，就必須從巨大的 $N$ 中找出原本的質數 $p$ 和 $q$（進行質因數分解）。即使使用目前主流的演算法（如普通數域篩法：GNFS），要將數百位數的數字進行質因數分解，即使動用超級電腦，所花費的時間也被認為會遠遠超過宇宙的年齡。&lt;/p>
&lt;hr>
&lt;h1 id="7-黎曼猜想對密碼技術的影響">7. 黎曼猜想對密碼技術的影響
&lt;/h1>&lt;p>那麼，位居純數學頂點的「黎曼猜想」與「密碼技術」是如何產生交集的呢？&lt;/p>
&lt;h3 id="71-質數生成演算法質數判定與廣義黎曼猜想grh">7.1. 質數生成演算法（質數判定）與廣義黎曼猜想（GRH）
&lt;/h3>&lt;p>為了運用RSA加密，首先必須生成巨大的質數 $p$ 和 $q$。然而，要確切且高速地判定「某個數是否為質數」並不容易。&lt;/p>
&lt;p>目前實用上被廣泛使用的是&lt;strong>米勒-拉賓質數判定法（Miller-Rabin primality test）&lt;/strong>，這是一種機率性演算法。這個演算法速度很快，但有極低的機率會將合成數誤判為質數（稱為「偽質數」）。&lt;/p>
&lt;p>但是，如果假設將黎曼猜想擴展到狄利克雷L函數上的**「廣義黎曼猜想（Generalized Riemann Hypothesis, GRH）」&lt;strong>為真，情況就會發生戲劇性的變化。
若GRH為真，米勒-拉賓判定法的測試次數上限就能獲得數學上的保證，從機率性演算法&lt;/strong>昇華為「確定性多項式時間演算法」**（這是在AKS質數測試演算法被發現前就已知的重要事實）。&lt;/p>
&lt;p>也就是說，黎曼猜想（及其推廣）扮演著直接為「能否以絕對的自信且高速地生成巨大質數」這個密碼學基礎生成過程背書的角色。&lt;/p>
&lt;h3 id="72-與質因數分解演算法的關係">7.2. 與質因數分解演算法的關係
&lt;/h3>&lt;p>在評估破解密碼一方的演算法（如普通數域篩法等）的計算複雜度時，關於質數分佈的知識也是不可或缺的。許多質因數分解演算法依賴於「平滑數（Smooth numbers：只包含較小質因數的數字）」的分佈。&lt;/p>
&lt;p>為了嚴密評估平滑數出現的頻率，需要對質數分佈有深刻的理解，這裡也充分運用了直接關聯到ζ函數與黎曼猜想的解析數論技巧。如果黎曼猜想被證明，質數分佈的誤差被完全確定，我們就能更精確地看清質因數分解演算法的效能極限。&lt;/p>
&lt;hr>
&lt;h1 id="8-如果黎曼猜想被證明密碼會被破解嗎">8. 如果黎曼猜想被證明，密碼會被破解嗎？
&lt;/h1>&lt;p>雖然有如都市傳說般流傳著「如果黎曼猜想被解開，RSA加密就會在一瞬間瓦解」，但&lt;strong>這在數學上是不正確的&lt;/strong>。&lt;/p>
&lt;p>黎曼猜想的證明本身，並不會立刻孕育出能讓質因數分解戲劇性加速的魔法演算法。因為黎曼猜想終究是關於質數「巨觀分佈規律性」的定理，並不能直接告訴我們個別數字 $N$ 能被哪個質數整除（局部性質）。&lt;/p>
&lt;p>然而，這並不代表影響為零。
因為在證明黎曼猜想的過程中，&lt;strong>極有可能性會發現「新的數學工具」或「未知的解析手法」&lt;/strong>。回顧歷史，當費馬最後定理或龐加萊猜想被證明時，在此過程中發展出的新理論，都讓整個數學領域有了大幅度的飛躍。&lt;/p>
&lt;p>如果確立了能夠完全操作黎曼ζ函數零點性質的未知代數幾何手法，或是非交換幾何的手法，我們不能否認，這最終可能導致劃時代的質因數分解演算法（例如將計算複雜度降至多項式時間的古典演算法）被發現。就這個意義而言，密碼學家絕不能對黎曼猜想的動向掉以輕心。&lt;/p>
&lt;h3 id="量子電腦與秀爾演算法">量子電腦與秀爾演算法
&lt;/h3>&lt;p>對密碼技術而言，更直接、更具現實威脅的不是黎曼猜想的證明，而是&lt;strong>量子電腦&lt;/strong>。1994年彼得·秀爾（Peter Shor）發表的「秀爾演算法」證明了，只要擁有足夠效能的量子電腦，就能在多項式時間內解決質因數分解問題。這將導致RSA加密和橢圓曲線密碼學從根本上被破解。&lt;/p>
&lt;p>目前，世界各地正積極推進轉移至即使是量子電腦也無法解讀的「後量子密碼學（Post-Quantum Cryptography, PQC）」（如晶格密碼等）。依賴於質數的密碼技術，或許在某種意義上即將結束其黃金時代，但質數本身的數學價值，永遠不會消失。&lt;/p>
&lt;hr>
&lt;h1 id="9-結語數學的抽象性與現實社會的交會點">9. 結語：數學的抽象性與現實社會的交會點
&lt;/h1>&lt;div class="mermaid">graph TD
A["純數學的探索"] --> B["解明黎曼猜想"]
B --> C["完全理解質數分佈"]
C --> D["數論與代數幾何學的飛躍性發展"]
D -.-> E["全新質因數分解演算法的可能性"]
E -.-> F["密碼技術安全性評估的更新"]
A --> G["應用數學與電腦科學"]
G --> H["質數判定與密碼生成的效率化"]
H --> F&lt;/div>
&lt;p>從古希臘延續至今對質數無止盡的探索，被天才黎曼昇華為複數平面上一首優美的交響曲（ζ函數的零點）。而令人驚嘆的是，這純粹無瑕的數學結晶，在經過數個世紀後，竟被應用為確保網際網路社會安全的最強盾牌。&lt;/p>
&lt;p>黎曼猜想同時象徵了數學所具備的「抽象之美」與「對物理世界・現實社會驚人的適用力」。&lt;/p>
&lt;p>當這座至今無人登頂的巨大數學山峰有朝一日被征服時，我們不僅能完全理解質數這宇宙真理，更將對資訊化社會的基礎產生全新的觀點。學習密碼技術，就如同踏上一段追溯人類智慧歷史的旅程。&lt;/p></description></item><item><title>【數學解說】讓高中生也能看懂的RSA加密原理</title><link>http://kenji.blog/zh-tw/p/rsa-encryption-math-explained-for-beginners/</link><pubDate>Fri, 11 Sep 2026 13:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/p/rsa-encryption-math-explained-for-beginners/</guid><description>&lt;img src="http://kenji.blog/p/rsa-encryption-math-explained-for-beginners/img/eyecatch.jpg" alt="Featured image of post 【數學解說】讓高中生也能看懂的RSA加密原理" />&lt;p>互聯網社會安全的底層支柱技術之一就是「RSA加密」。線上購物的信用卡支付、與朋友在社群網路上的交流、公司機密資訊的收發等，我們每天不經意間使用的通訊，很多都是由RSA加密或其後續技術保護的。&lt;/p>
&lt;p>然而，一聽到「加密」，可能會聯想到間諜電影裡那種複雜的密碼機，或是只有少數天才才能理解的超高深數學。雖然現代密碼學確實建立在高等數學的基礎上，但&lt;strong>RSA加密的根本原理，只要具備高中數學（整數性質、質數、同餘等）的知識就足以理解&lt;/strong>。&lt;/p>
&lt;p>這篇文章將以高中數學知識為起點，逐步深入且徹底地解說RSA加密是基於什麼樣的數學原理運作的，以及為什麼它很難被破解。即使是不太擅長數學的人，我也會透過具體例子來淺顯易懂地解釋。&lt;/p>
&lt;hr>
&lt;h2 id="1-對稱密鑰加密與公鑰加密">1. 對稱密鑰加密與公鑰加密
&lt;/h2>&lt;p>在進入RSA加密的數學機制之前，我們先整理一下密碼學的基本概念。加密方式大致可分為「對稱密鑰加密」與「公鑰加密」兩種。&lt;/p>
&lt;h3 id="11-對稱密鑰加密方式的極限">1.1 對稱密鑰加密方式的極限
&lt;/h3>&lt;p>自古以來使用的加密方式，大多稱為「對稱密鑰加密方式」。這是一種&lt;strong>在「加密（將訊息轉換成秘密的密文）」與「解密（將密文還原成原本的訊息）」時使用相同密鑰&lt;/strong>的方式。&lt;/p>
&lt;p>例如，愛麗絲要寄一封秘密信件給鮑勃。愛麗絲用掛鎖（對稱密鑰）將信件鎖在箱子裡。鮑勃要打開那個箱子，就必須擁有與愛麗絲使用的同一把鑰匙。&lt;/p>
&lt;p>這種方式有一個很大的問題，就是「密鑰配送問題」。相隔兩地的愛麗絲與鮑勃在首次通訊時，該如何共享鑰匙而不被竊聽呢？如果在郵寄鑰匙的途中被第三者偷走，之後的加密通訊就會全部洩漏。&lt;/p>
&lt;h3 id="12-劃時代的發明公鑰加密方式">1.2 劃時代的發明「公鑰加密方式」
&lt;/h3>&lt;p>為了解決這個密鑰配送問題而發明出來的，就是「公鑰加密方式」。RSA加密也是其中一種。&lt;/p>
&lt;p>在公鑰加密方式中，會使用**「用來加密的密鑰（公鑰）」與「用來解密的密鑰（私鑰）」這兩把不同的鑰匙**。&lt;/p>
&lt;ol>
&lt;li>接收者鮑勃會建立一對「公鑰」與「私鑰」。&lt;/li>
&lt;li>鮑勃將「公鑰」公開給全世界（任何人都可以取得）。&lt;/li>
&lt;li>發送者愛麗絲使用鮑勃的「公鑰」來加密訊息並發送。&lt;/li>
&lt;li>加密後的訊息，只能用鮑勃獨有的「私鑰」來解密。&lt;/li>
&lt;/ol>
&lt;p>如果用掛鎖來比喻，鮑勃製作了許多「打開狀態的掛鎖（公鑰）」並散佈到全世界。愛麗絲將給鮑勃的訊息放入箱子，撿起鮑勃的掛鎖並將它鎖上。掛鎖一旦鎖上，就只有擁有「萬能鑰匙（私鑰）」的鮑勃才能打開。即使途中有人偷走了箱子，因為沒有萬能鑰匙，所以也打不開。&lt;/p>
&lt;div class="mermaid">graph TD
A["愛麗絲 (發送者)"] --> B["明文 (訊息)"]
B --> C["加密處理"]
D["鮑勃的公鑰 (任何人皆可取得)"] --> C
C --> E["透過網際網路發送: 密文"]
E --> F["解密處理"]
G["鮑勃的私鑰 (僅鮑勃擁有)"] --> F
F --> H["還原後的明文 (訊息)"]
H --> I["鮑勃 (接收者)"]&lt;/div>
&lt;p>要實現這種劃時代的系統，就需要一種**「單向函數（單向的數學謎題）」**，也就是「用公鑰很容易加密，但沒有私鑰就絕對無法解密」。而成為這個謎題零件的，正是我們熟知的「質數」。&lt;/p>
&lt;hr>
&lt;h2 id="2-支撐rsa加密的數學基礎1質數與質因數分解">2. 支撐RSA加密的數學基礎1：質數與質因數分解
&lt;/h2>&lt;p>RSA加密的安全性，建立在**「巨大數字的質因數分解非常困難」**這個數學事實上。&lt;/p>
&lt;h3 id="21-什麼是質數">2.1 什麼是質數
&lt;/h3>&lt;p>質數是指「除了1和自己本身之外，無法被其他數整除，且大於1的自然數」。
例如：$2, 3, 5, 7, 11, 13, 17, 19, 23...$&lt;/p>
&lt;p>質數就像是所有整數的「原子」。任何自然數都可以分解成質數相乘的形式。這稱為&lt;strong>質因數分解&lt;/strong>。例如 $60 = 2^2 \times 3 \times 5$，如果不考慮順序，就只有一種質因數分解的方法，這被稱為「算術基本定理」。&lt;/p>
&lt;h3 id="22-質因數分解的困難度單向函數">2.2 質因數分解的困難度（單向函數）
&lt;/h3>&lt;p>這裡的重點在於**「乘法很簡單，但質因數分解很困難」**這種不對稱性。&lt;/p>
&lt;p>例如，請試著心算以下兩個質數的乘法：
$11 \times 13 = ?$
這很簡單，答案是 $143$。&lt;/p>
&lt;p>那麼，這個數字呢？
請將 $323$ 進行質因數分解。
覺得如何？應該需要花一點時間。（答案是 $17 \times 19$）。&lt;/p>
&lt;p>如果數字很小，人類還能勉強算出來；但當數字變大時，即使使用電腦，計算難度也會呈現爆炸性成長。目前主流的RSA加密，會使用將兩個高達2048位元（十進位約600位數）、極其巨大的質數 $p$ 與 $q$ 相乘後的數字 $N = p \times q$。&lt;/p>
&lt;p>給定兩個巨大的質數 $p$ 和 $q$ 時，電腦瞬間（毫秒以下）就能計算出 $N$。但反過來，如果只給 $N$，要找出原本的 $p$ 和 $q$，即使讓現在最快的超級電腦運算幾兆年也解不出來。&lt;/p>
&lt;p>這種**「計算的不對稱性（去程簡單，回程困難）」**，就是創造出公鑰與私鑰關係的基礎。&lt;/p>
&lt;hr>
&lt;h2 id="3-支撐rsa加密的數學基礎2同餘模運算">3. 支撐RSA加密的數學基礎2：同餘（模運算）
&lt;/h2>&lt;p>RSA加密的計算，並不是我們平常用來讓數字無限變大的加法或乘法，而是在除以某個數的「餘數」世界中進行的。這稱為&lt;strong>同餘（模運算）&lt;/strong>。&lt;/p>
&lt;h3 id="31-時鐘的數學">3.1 時鐘的數學
&lt;/h3>&lt;p>模運算常被比喻為「時鐘的數學」。假設現在是10點，5小時後是幾點？ $10 + 5 = 15$ 點，但在一般的12小時制時鐘裡，我們會回答「3點」。這是因為15除以12的餘數是3。&lt;/p>
&lt;p>在數學的世界裡，我們會這樣表示：
&lt;/p>
$$ 15 \equiv 3 \pmod{12} $$
&lt;p>
讀作「15與3，在模12之下同餘（除以12的餘數相等）」。&lt;/p>
&lt;h3 id="32-同餘的基本性質">3.2 同餘的基本性質
&lt;/h3>&lt;p>同餘擁有與等式（$=$）非常相似且非常方便的性質。假設模（除數）為 $N$。
當 $a \equiv b \pmod N$ 且 $c \equiv d \pmod N$ 時，以下敘述成立：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>加法:&lt;/strong> $a + c \equiv b + d \pmod N$&lt;/li>
&lt;li>&lt;strong>減法:&lt;/strong> $a - c \equiv b - d \pmod N$&lt;/li>
&lt;li>&lt;strong>乘法:&lt;/strong> $a \times c \equiv b \times d \pmod N$&lt;/li>
&lt;li>&lt;strong>冪次方:&lt;/strong> $a^k \equiv b^k \pmod N$ （$k$ 為自然數）&lt;/li>
&lt;/ol>
&lt;p>其中特別重要的是「冪次方」的性質。這意味著**「餘數的次方，等於次方的餘數」**。
例如，我們想求 $7^{100}$ 除以 $5$ 的餘數。如果真的把 $7$ 乘100次再除以 $5$ 會非常辛苦；但如果使用同餘的性質，因為 $7 \equiv 2 \pmod 5$，所以 $7^{100} \equiv 2^{100} \pmod 5$，這能讓計算變得非常簡單。在密碼學的世界中，由於處理的是非常大數字的次方運算，這個性質是不可或缺的。&lt;/p>
&lt;hr>
&lt;h2 id="4-支撐rsa加密的數學基礎3歐拉函數與歐拉定理">4. 支撐RSA加密的數學基礎3：歐拉函數與歐拉定理
&lt;/h2>&lt;p>接下來就是RSA加密核心的數學魔法了。作為「費馬小定理」推廣的「歐拉定理」即將登場。&lt;/p>
&lt;h3 id="41-歐拉的總計函數-phin">4.1 歐拉的總計函數 $\phi(N)$
&lt;/h3>&lt;p>歐拉總計函數（$\phi$ 函數）是針對某個自然數 $N$，回傳**「從1到 $N$ 的自然數中，與 $N$ 互質（最大公因數為1）的數字個數」**的函數。&lt;/p>
&lt;p>我們來看幾個例子：&lt;/p>
&lt;ul>
&lt;li>$\phi(5)$：在1, 2, 3, 4, 5中，與5互質的有1, 2, 3, 4，共4個。因此 $\phi(5) = 4$。&lt;/li>
&lt;li>$\phi(6)$：在1, 2, 3, 4, 5, 6中，與6互質的有1, 5，共2個。因此 $\phi(6) = 2$。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>【質數時的特殊性質】&lt;/strong>
如果 $p$ 是質數，從 1 到 $p-1$ 的所有數字都會與 $p$ 互質。因此：
&lt;/p>
$$ \phi(p) = p - 1 $$
&lt;p>&lt;strong>【質數相乘時的特殊性質】&lt;/strong>
對於兩個不同的質數 $p$ 和 $q$，當 $N = p \times q$ 時，$\phi(N)$ 可以很容易地用以下公式計算：
&lt;/p>
$$ \phi(N) = \phi(p) \times \phi(q) = (p - 1)(q - 1) $$
&lt;p>
這個性質就是RSA加密中的「秘密後門（陷門函數）」。知道 $p$ 和 $q$ 的人（密鑰建立者）可以瞬間計算出 $\phi(N)$，但只知道 $N$ 的第三者，除非對 $N$ 進行質因數分解，否則無法求得 $\phi(N)$。&lt;/p>
&lt;h3 id="42-歐拉定理">4.2 歐拉定理
&lt;/h3>&lt;p>萊昂哈德·歐拉（Leonhard Euler）利用這個 $\phi(N)$，證明了以下優美的定理：&lt;/p>
&lt;p>&lt;strong>歐拉定理：&lt;/strong>
當整數 $a$ 與 $N$ 互質時，以下的同餘式成立：
&lt;/p>
$$ a^{\phi(N)} \equiv 1 \pmod N $$
&lt;p>這是一個驚人的性質：「將某個數字 $a$ 自乘 $\phi(N)$ 次後除以 $N$，餘數必定會是 $1$」。（當 $N$ 是質數 $p$ 時，公式為 $a^{p-1} \equiv 1 \pmod p$，這被稱為費馬小定理）。&lt;/p>
&lt;p>讓我們變形一下這個歐拉定理。兩邊再乘以 $a$：
&lt;/p>
$$ a^{\phi(N) + 1} \equiv a \pmod N $$
&lt;p>此外，對於任意整數 $k$，$a^{k \cdot \phi(N)}$ 也會是 $1^k = 1$，因此以下公式成立：
&lt;/p>
$$ a^{k \cdot \phi(N) + 1} \equiv a \pmod N $$
&lt;p>這個公式正是讓RSA加密中**「加密後再解密就能還原」**這種魔法得以成立的根本原理。&lt;/p>
&lt;hr>
&lt;h2 id="5-rsa加密的演算法密鑰生成加密解密的步驟">5. RSA加密的演算法：密鑰生成、加密、解密的步驟
&lt;/h2>&lt;p>基礎知識準備好後，我們終於要來看看RSA加密的具體步驟了。RSA加密主要分為「1. 密鑰生成」、「2. 加密」、「3. 解密」三個階段。&lt;/p>
&lt;div class="mermaid">flowchart TD
A1["1. 選擇質數 p, q"] --> A2["計算 N = p × q"]
A1 --> A3["計算 φ(N) = (p-1)(q-1)"]
A3 --> A4["選擇與 φ(N) 互質的 e"]
A3 --> A5["計算 d 使得 e × d ≡ 1 (mod φ(N))"]
A2 --> A6["公鑰 (N, e)"]
A4 --> A6
A5 --> A7["私鑰 d"]
B1["2. 明文訊息 M"] --> B2["計算 C ≡ M^e (mod N)"]
A6 -.-> B2
B2 --> B3["發送密文 C"]
B3 --> C1["3. 接收到的密文 C"]
C1 --> C2["計算 M ≡ C^d (mod N)"]
A7 -.-> C2
C2 --> C3["取得原本的明文訊息 M"]&lt;/div>
&lt;h3 id="51-密鑰生成key-generation">5.1 密鑰生成（Key Generation）
&lt;/h3>&lt;p>作為接收者的鮑勃，要為自己生成「公鑰」與「私鑰」。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>選擇質數:&lt;/strong> 隨機選擇兩個大質數 $p$ 和 $q$。&lt;/li>
&lt;li>&lt;strong>計算模 $N$:&lt;/strong> 計算 $N = p \times q$。這個 $N$ 會被公開。&lt;/li>
&lt;li>&lt;strong>計算 $\phi(N)$:&lt;/strong> 計算歐拉函數 $\phi(N) = (p - 1)(q - 1)$。這是只有鮑勃知道的秘密數字。&lt;/li>
&lt;li>&lt;strong>選擇公鑰 $e$:&lt;/strong> 選擇一個整數 $e$，滿足 $1 &lt; e &lt; \phi(N)$，且與 $\phi(N)$ 互質。&lt;/li>
&lt;li>&lt;strong>計算私鑰 $d$:&lt;/strong> 找出滿足以下條件的整數 $d$：
$$ e \times d \equiv 1 \pmod{\phi(N)} $$
也就是說，「找一個數字 $d$，使得 $e \times d$ 除以 $\phi(N)$ 的餘數為 $1$」。&lt;/li>
&lt;/ol>
&lt;p>這樣密鑰就準備完成了。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>公鑰:&lt;/strong> $(N, e)$ 的組合。公開給全世界。&lt;/li>
&lt;li>&lt;strong>私鑰:&lt;/strong> $d$。絕對不能告訴任何人。&lt;/li>
&lt;/ul>
&lt;h3 id="52-加密encryption">5.2 加密（Encryption）
&lt;/h3>&lt;p>假設愛麗絲想發送秘密訊息 $M$ 給鮑勃。（將 $M$ 視為文字數值化後的結果，且 $0 \le M &lt; N$）。愛麗絲會使用鮑勃的公鑰 $(N, e)$ 進行以下計算：&lt;/p>
$$ C \equiv M^e \pmod N $$
&lt;p>計算「將訊息 $M$ 的 $e$ 次方，除以 $N$ 的餘數 $C$」。這個 $C$ 就是密文。&lt;/p>
&lt;h3 id="53-解密decryption">5.3 解密（Decryption）
&lt;/h3>&lt;p>鮑勃接收到密文 $C$。鮑勃使用私鑰 $d$ 進行以下計算：&lt;/p>
$$ M \equiv C^d \pmod N $$
&lt;p>「將密文 $C$ 的 $d$ 次方，除以 $N$ 的餘數」，計算後竟然就能還原出原本的訊息 $M$！&lt;/p>
&lt;hr>
&lt;h2 id="6-為什麼解密後能還原數學證明">6. 為什麼解密後能還原？（數學證明）
&lt;/h2>&lt;p>你可能會覺得疑問：「只是把 $C$ 做了 $d$ 次方，為什麼就能還原成原本的 $M$ 呢？」這時，先前的「歐拉定理」就發揮威力了。&lt;/p>
&lt;p>我們把解密的計算式 $C^d \pmod N$ 中，代入加密的式子 $C = M^e$：
&lt;/p>
$$ C^d \equiv (M^e)^d \equiv M^{ed} \pmod N $$
&lt;p>回想一下密鑰生成的步驟5。鮑勃在製作 $d$ 時，選擇了讓 $e \times d \equiv 1 \pmod{\phi(N)}$ 的數字。這意味著「$ed$ 是 $\phi(N)$ 的倍數加 $1$」。我們可以用整數 $k$ 這樣寫：
&lt;/p>
$$ ed = k \cdot \phi(N) + 1 $$
&lt;p>將它代入指數部分，並利用指數律來分解：
&lt;/p>
$$ M^{ed} = M^{k \cdot \phi(N) + 1} = M^{k \cdot \phi(N)} \times M^1 = (M^{\phi(N)})^k \times M $$
&lt;p>這裡假設訊息 $M$ 與 $N$ 互質，根據&lt;strong>歐拉定理&lt;/strong>，會有 $M^{\phi(N)} \equiv 1 \pmod N$。
&lt;/p>
$$ (M^{\phi(N)})^k \times M \equiv 1^k \times M \equiv M \pmod N $$
&lt;p>因此，完美地成立了以下公式：
&lt;/p>
$$ C^d \equiv M \pmod N $$
&lt;p>愛麗絲不知道 $d$，竊聽者也不知道 $d$，所以能從 $C$ 取出 $M$ 的，只有擁有 $d$ 的鮑勃。&lt;/p>
&lt;hr>
&lt;h2 id="7-具體例子用小質數手動計算體驗rsa">7. 具體例子：用小質數手動計算體驗RSA
&lt;/h2>&lt;p>讓我們實際用小數字（質數）來試試看愛麗絲給鮑勃的加密通訊。&lt;/p>
&lt;p>&lt;strong>【鮑勃的密鑰生成階段】&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>選擇兩個質數 $p=11$, $q=13$。&lt;/li>
&lt;li>計算 $N = 11 \times 13 = 143$。&lt;/li>
&lt;li>計算 $\phi(N) = (11 - 1) \times (13 - 1) = 10 \times 12 = 120$。&lt;/li>
&lt;li>選擇與 $\phi(N)=120$ 互質的公鑰 $e$。這裡我們選擇 $e=7$。&lt;/li>
&lt;li>求私鑰 $d$。尋找能讓 $7 \times d \equiv 1 \pmod{120}$ 的 $d$。
在方程式 $7d = 120k + 1$ 中，當 $k=6$ 時為 $721$，而 $721 \div 7 = 103$。
因此，$d = 103$。&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>公鑰：$(N=143, e=7)$&lt;/li>
&lt;li>私鑰：$d=103$&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>【愛麗絲的加密階段】&lt;/strong>
假設想發送的訊息 $M = 9$。
公式：$C \equiv 9^7 \pmod{143}$
$9^7 = 4,782,969$。把它除以 143，商為 $33447$ 餘數 $48$。
密文 $C = 48$。&lt;/p>
&lt;p>&lt;strong>【鮑勃的解密階段】&lt;/strong>
鮑勃收到密文 $C = 48$，使用私鑰 $d = 103$ 來解密。
公式：$M \equiv 48^{103} \pmod{143}$
在計算機中執行 &lt;code>(48 ** 103) % 143&lt;/code>，結果完美地出現「&lt;strong>9&lt;/strong>」！順利收到了原本的訊息。&lt;/p>
&lt;hr>
&lt;h2 id="8-私鑰-d-的求法擴展歐幾里得演算法">8. 私鑰 $d$ 的求法：擴展歐幾里得演算法
&lt;/h2>&lt;p>在手動計算的例子中，我們是靠直覺找 $k$ 才找出 $d=103$，但當數字高達幾百位數時，這種方法就行不通了。在實際的程式中，會使用**「擴展歐幾里得演算法」**。&lt;/p>
&lt;p>解開 $7d \equiv 1 \pmod{120}$，就等同於尋找滿足 $7d + 120y = 1$ 的整數 $d, y$。透過逆推歐幾里得演算法，就可以機械化地求出這個值。&lt;/p>
&lt;ol>
&lt;li>$120 \div 7 = 17$ 餘 $1$&lt;/li>
&lt;li>將其變形後為 $1 = 120 - 17 \times 7$&lt;/li>
&lt;li>也就是 $-17 \times 7 \equiv 1 \pmod{120}$&lt;/li>
&lt;/ol>
&lt;p>$-17$ 在模 $120$ 的世界裡，與 $120 - 17 = 103$ 意義相同。因此，瞬間就能求得 $d = 103$。無論多麼巨大的數字，用這個方法都能非常快速地計算出來。&lt;/p>
&lt;hr>
&lt;h2 id="9-rsa加密的另一面數位簽章">9. RSA加密的另一面：數位簽章
&lt;/h2>&lt;p>RSA加密最棒的一點在於，如果將公鑰和私鑰的角色反過來，還能當作**「數位簽章」**使用。&lt;/p>
&lt;p>加密時是「用公鑰加密 $\Rightarrow$ 用私鑰解密」，
但在數位簽章中，則會採取「用私鑰加密 $\Rightarrow$ 用公鑰解密」的步驟。&lt;/p>
&lt;div class="mermaid">flowchart TD
A1["1. 愛麗絲用私鑰建立簽章"] --> A2["S ≡ M^d (mod N)"]
A2 --> A3["發送訊息 M 與簽章 S"]
A3 --> B1["2. 鮑勃用公鑰驗證簽章"]
B1 --> B2["計算 M' ≡ S^e (mod N)"]
B2 --> B3["確認 M' 是否與 M 一致"]&lt;/div>
&lt;p>愛麗絲使用自己的私鑰 $d$ 來轉換訊息（這就是簽章 $S$），然後發送給鮑勃。鮑勃使用愛麗絲的公鑰 $e$ 來進行驗證計算。如果計算結果與原本的訊息一致，就能同時證明「這是只有愛麗絲的私鑰才能建立的資料」，以及「訊息在途中沒有被篡改」。&lt;/p>
&lt;hr>
&lt;h2 id="10-透過程式體驗rsa加密">10. 透過程式體驗RSA加密
&lt;/h2>&lt;p>手動計算很辛苦的次方運算，只要用Python就能非常簡單地實作出來。以下是能體驗RSA加密核心邏輯的Python程式碼。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;求最大公因數&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">b&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">a&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">mod_inverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;求私鑰 d（使用 Python 3.8 以後的內建功能）&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. 密鑰生成&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">p&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">q&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">11&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">13&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">N&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">q&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">phi&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">q&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">e&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">7&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">d&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod_inverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;公鑰: (N=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">N&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">, e=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">), 私鑰: d=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">d&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. 加密&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">9&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">ciphertext&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;密文: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">ciphertext&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. 解密&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">decrypted_message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ciphertext&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;解密後的訊息: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">decrypted_message&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Python的 &lt;code>pow(base, exp, mod)&lt;/code> 函數在內部使用了名為「反覆平方法（快速冪）」的高速演算法，因此即使是幾百位數的數字，也能瞬間完成計算。&lt;/p>
&lt;hr>
&lt;h2 id="11-總結與未來的密碼技術">11. 總結與未來的密碼技術
&lt;/h2>&lt;p>我們以高中數學知識為基礎，解開了RSA加密的原理。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>質因數分解的困難度:&lt;/strong> $p \times q = N$ 很簡單，但從 $N$ 找出 $p, q$ 非常困難。&lt;/li>
&lt;li>&lt;strong>同餘與歐拉定理:&lt;/strong> 根據 $a^{\phi(N)} \equiv 1 \pmod N$ 這個法則，完成了「用某個數做次方運算就能還原」的魔法陷門函數。&lt;/li>
&lt;li>&lt;strong>公鑰與私鑰:&lt;/strong> 任何人都能加密，但只有合法的接收者才能解密。&lt;/li>
&lt;/ol>
&lt;p>現在使用的RSA加密的 $N$ 有600位數以上，即使動用全世界的超級電腦，質因數分解所花的時間也會超過宇宙的年齡。然而，近年來研究不斷進展的「量子電腦」若在未來實用化，透過「秀爾演算法（Shor&amp;rsquo;s algorithm）」，這種質因數分解可能瞬間就被解開。因此，現在全世界都在加速開發連量子電腦也無法破解的「後量子密碼學（抗量子計算機密碼）」。&lt;/p>
&lt;p>常被認為「派不上用場」的高等數學，其實在底層保護著我們的日常生活。RSA加密就是能告訴我們數學有多深奧與優美的絕佳教材。希望透過這篇文章，能讓您稍微感受到密碼學與數學的有趣之處。&lt;/p></description></item></channel></rss>