<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>ECC on kenji.blog</title><link>http://kenji.blog/zh-tw/tags/ecc/</link><description>Recent content in ECC on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>zh-tw</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 10:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/zh-tw/tags/ecc/index.xml" rel="self" type="application/rss+xml"/><item><title>橢圓曲線密碼學（ECC）的數學基礎與C++實作</title><link>http://kenji.blog/zh-tw/p/elliptic-curve-cryptography-math-cpp/</link><pubDate>Fri, 11 Sep 2026 10:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/p/elliptic-curve-cryptography-math-cpp/</guid><description>&lt;img src="http://kenji.blog/p/elliptic-curve-cryptography-math-cpp/img/eyecatch.jpg" alt="Featured image of post 橢圓曲線密碼學（ECC）的數學基礎與C++實作" />&lt;h1 id="橢圓曲線密碼學ecc的數學基礎與c實作">橢圓曲線密碼學（ECC）的數學基礎與C++實作
&lt;/h1>&lt;p>在現代密碼學中，**橢圓曲線密碼學（Elliptic Curve Cryptography: ECC）**扮演著極其重要的角色。從我們日常的網際網路通訊（HTTPS/TLS），到智慧型手機的安全隔離區（Secure Enclave）、SSH伺服器認證、FIDO等無密碼認證，甚至是比特幣和以太坊等加密資產，可以說現代數位社會的信任基礎都是由ECC所支撐的。&lt;/p>
&lt;p>本文將從橢圓曲線密碼學如何運作出發，深入探討其背後優美卻深奧的數學理論（有限體上的代數幾何），並介紹如何使用C++進行實際實作，甚至涵蓋如何防範旁路攻擊（計時攻擊）的安全程式設計方法，以壓倒性的篇幅為您徹底解析。&lt;/p>
&lt;hr>
&lt;h2 id="1-為什麼選擇橢圓曲線密碼學與rsa的比較">1. 為什麼選擇橢圓曲線密碼學？（與RSA的比較）
&lt;/h2>&lt;p>長期以來，公鑰密碼學的代名詞一直是&lt;strong>RSA密碼&lt;/strong>。RSA密碼的安全性建立在「大整數質因數分解的困難度」之上。然而，隨著電腦運算能力的提升，為了維持安全性，必須不斷增加RSA的金鑰長度（模數的位元數）。如今，建議的最低金鑰長度為2048位元，若要追求更高的安全性，則建議使用3072位元或4096位元。&lt;/p>
&lt;p>相對地，橢圓曲線密碼學（ECC）則以另一種數學難題——**「橢圓曲線上的離散對數問題（ECDLP）」**作為其安全性的基礎。直到現在，尚未發現能有效解決ECDLP的演算法（如次指數時間演算法），即使是目前已知最有效的攻擊方法，也需要指數級的時間。&lt;/p>
&lt;p>這個特性讓ECC擁有了一個決定性的優勢：&lt;strong>能以非常短的金鑰長度實現與RSA同等的安全強度&lt;/strong>。&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:center">安全強度（位元）&lt;/th>
&lt;th style="text-align:center">RSA密碼金鑰長度（位元）&lt;/th>
&lt;th style="text-align:center">橢圓曲線密碼金鑰長度（位元）&lt;/th>
&lt;th style="text-align:center">金鑰長度比例&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:center">80&lt;/td>
&lt;td style="text-align:center">1024&lt;/td>
&lt;td style="text-align:center">160&lt;/td>
&lt;td style="text-align:center">1:6&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">112&lt;/td>
&lt;td style="text-align:center">2048&lt;/td>
&lt;td style="text-align:center">224&lt;/td>
&lt;td style="text-align:center">1:9&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">128&lt;/td>
&lt;td style="text-align:center">3072&lt;/td>
&lt;td style="text-align:center">256&lt;/td>
&lt;td style="text-align:center">1:12&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">192&lt;/td>
&lt;td style="text-align:center">7680&lt;/td>
&lt;td style="text-align:center">384&lt;/td>
&lt;td style="text-align:center">1:20&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">256&lt;/td>
&lt;td style="text-align:center">15360&lt;/td>
&lt;td style="text-align:center">512&lt;/td>
&lt;td style="text-align:center">1:30&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>如上表所示，為了達到128位元的安全強度（目前標準的強度），RSA需要3072位元的金鑰，而ECC只需要短短的256位元。這使得減少計算量、降低記憶體使用量、節省網路頻寬成為可能，特別是在資源受限的物聯網（IoT）設備或智慧卡環境中，展現出壓倒性的優勢。&lt;/p>
&lt;hr>
&lt;h2 id="2-數學準備群論與有限體的世界">2. 數學準備：群論與有限體的世界
&lt;/h2>&lt;p>要真正理解橢圓曲線密碼學，必須掌握抽象代數（群論與體論）的基本概念。在這裡，我們簡明扼要地總結建構ECC所需的預備知識。&lt;/p>
&lt;h3 id="21-群group與阿貝爾群">2.1. 群（Group）與阿貝爾群
&lt;/h3>&lt;p>**群（Group）**是指一個集合 $G$ 及其上的一種二元運算（此處以加法 $+$ 表示）所組成的結構 $(G, +)$，並且滿足以下四個公理：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>封閉性（Closure）&lt;/strong>: 對於任意 $a, b \in G$，$a + b \in G$。&lt;/li>
&lt;li>&lt;strong>結合律（Associativity）&lt;/strong>: 對於任意 $a, b, c \in G$，$(a + b) + c = a + (b + c)$ 成立。&lt;/li>
&lt;li>&lt;strong>單位元素的存在性（Identity element）&lt;/strong>: 存在一個元素 $e \in G$，使得對任意 $a \in G$，$a + e = e + a = a$。在加法群中，這個單位元素通常記為 $0$ 或 $\mathcal{O}$。&lt;/li>
&lt;li>&lt;strong>反元素的存在性（Inverse element）&lt;/strong>: 對於任意 $a \in G$，存在一個元素 $b \in G$ 使得 $a + b = b + a = e$。這個 $b$ 記為 $-a$。&lt;/li>
&lt;/ol>
&lt;p>此外，如果運算的順序對調也不會改變結果，也就是滿足以下條件的群，我們稱之為&lt;strong>阿貝爾群（交換群）&lt;/strong>：&lt;/p>
&lt;ol start="5">
&lt;li>&lt;strong>交換律（Commutativity）&lt;/strong>: 對於任意 $a, b \in G$，$a + b = b + a$ 成立。&lt;/li>
&lt;/ol>
&lt;p>橢圓曲線上的點的集合，透過定義特定的加法規則，便構成了一個&lt;strong>阿貝爾群&lt;/strong>。&lt;/p>
&lt;h3 id="22-有限體finite-field">2.2. 有限體（Finite Field）
&lt;/h3>&lt;p>在密碼學中，我們不使用像實數或複數那樣連續且具有無限元素的體，而是使用元素數量有限的**有限體（Finite Field）**或稱伽羅瓦體（Galois Field）。&lt;/p>
&lt;p>最基本的有限體是使用質數 $p$ 建構的&lt;strong>質數體 $\mathbb{F}_p$&lt;/strong>。這是在整數集合 $\{0, 1, 2, \dots, p-1\}$ 上定義模 $p$（除以 $p$ 的餘數）的四則運算（加、減、乘、除）。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>加法&lt;/strong>: $(a + b) \pmod p$&lt;/li>
&lt;li>&lt;strong>減法&lt;/strong>: $(a - b) \pmod p$&lt;/li>
&lt;li>&lt;strong>乘法&lt;/strong>: $(a \times b) \pmod p$&lt;/li>
&lt;li>&lt;strong>除法&lt;/strong>: $a \times b^{-1} \pmod p$ （這裡 $b^{-1}$ 是 $b$ 在模 $p$ 下的乘法反元素）&lt;/li>
&lt;/ul>
&lt;p>**乘法反元素（Modular Multiplicative Inverse）**的計算在密碼學實作中非常重要。要找到滿足 $b \times b^{-1} \equiv 1 \pmod p$ 的 $b^{-1}$，主要使用以下兩種演算法：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>擴展歐幾里得演算法（Extended Euclidean Algorithm）&lt;/strong>: 速度快，但根據實作方式，處理時間可能會依賴於輸入值，從而存在計時攻擊的風險。&lt;/li>
&lt;li>&lt;strong>費馬小定理（Fermat&amp;rsquo;s Little Theorem）&lt;/strong>: 當 $p$ 為質數且 $b \neq 0$ 時，$b^{p-1} \equiv 1 \pmod p$ 成立。兩邊同除以 $b$，可得 $b^{p-2} \equiv b^{-1} \pmod p$。也就是說，透過計算 $b$ 的 $p-2$ 次方即可求得反元素。因為指數運算較容易以常數時間（Constant-time）實作，密碼學實作中通常偏好此方法。&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="3-橢圓曲線方程式與幾何學">3. 橢圓曲線方程式與幾何學
&lt;/h2>&lt;h3 id="31-魏爾斯特拉斯標準式">3.1. 魏爾斯特拉斯標準式
&lt;/h3>&lt;p>**橢圓曲線（Elliptic Curve）&lt;strong>通常是指由以下被稱為&lt;/strong>魏爾斯特拉斯標準式（Weierstrass normal form）**的方程式所定義的平面曲線：&lt;/p>
$$ y^2 = x^3 + ax + b $$
&lt;p>其中，$a$ 和 $b$ 為常數，為了讓曲線不具有奇異點（自我交叉或尖點），也就是維持曲線的光滑性，必須滿足以下&lt;strong>判別式（Discriminant） $\Delta$&lt;/strong> 不為零的條件：&lt;/p>
$$ \Delta = -16(4a^3 + 27b^2) \neq 0 $$
&lt;p>具有奇異點的曲線會損害密碼學上的安全性，因此務必選擇滿足此條件的係數 $a, b$。&lt;/p>
&lt;h3 id="32-無窮遠點point-at-infinity">3.2. 無窮遠點（Point at Infinity）
&lt;/h3>&lt;p>為了讓橢圓曲線在數學上成為一個完美的群，除了平面上的點之外，還引入了一個虛擬的點，稱為**「無窮遠點（Point at Infinity）」**。我們將其記為 $\mathcal{O}$。&lt;/p>
&lt;p>無窮遠點 $\mathcal{O}$ 被定義為所有垂直線在無限遠處相交的點。在群論中，這個無窮遠點 $\mathcal{O}$ 扮演著&lt;strong>加法單位元素&lt;/strong>（零）的角色。&lt;/p>
&lt;p>也就是說，對於曲線上的任意點 $P$，以下等式成立：
&lt;/p>
$$ P + \mathcal{O} = \mathcal{O} + P = P $$
&lt;p>此外，點 $P = (x, y)$ 的反元素 $-P$ 被定義為與x軸對稱的點 $(x, -y)$。因此：
&lt;/p>
$$ P + (-P) = \mathcal{O} $$
&lt;p>
成立。&lt;/p>
&lt;hr>
&lt;h2 id="4-橢圓曲線上的群運算點的加法與二倍運算">4. 橢圓曲線上的群運算（點的加法與二倍運算）
&lt;/h2>&lt;p>構成橢圓曲線密碼學核心的，是曲線上點與點之間的**「加法（Addition）」**運算。這與一般的整數加法不同，它是基於幾何操作所定義的。&lt;/p>
&lt;h3 id="41-幾何加法tangent-and-chord-method">4.1. 幾何加法（Tangent and Chord Method）
&lt;/h3>&lt;p>將曲線上兩個不同的點 $P$ 和 $Q$ 相加，求得新點 $R$ ($R = P + Q$) 的步驟如下：&lt;/p>
&lt;ol>
&lt;li>畫一條連接點 $P$ 和點 $Q$ 的直線（割線）。&lt;/li>
&lt;li>這條直線必然會與橢圓曲線交於另一個點（我們稱之為 $-R$）。（※根據代數幾何定理）&lt;/li>
&lt;li>將交點 $-R$ 沿x軸對稱翻轉（即改變y座標的符號），得到的點即為所求的 $R$ 點。&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph TD
Step1["畫一條連接 P(x1, y1) 和 Q(x2, y2) 的直線"] --> Step2["找到與曲線的第三個交點 -R"]
Step2 --> Step3["將 -R 沿 x 軸翻轉，得到 R(x3, y3)"]
Step3 -.-> Result["這就是 R = P + Q"]&lt;/div>
&lt;h3 id="42-點的二倍運算point-doubling">4.2. 點的二倍運算（Point Doubling）
&lt;/h3>&lt;p>當我們要將點 $P$ 加上其自身（$P + P = 2P$）時，無法畫出一條穿過兩個相異點的直線。此時，我們改為畫出&lt;strong>曲線在點 $P$ 處的切線（Tangent）&lt;/strong>。&lt;/p>
&lt;ol>
&lt;li>畫出曲線在點 $P$ 處的切線。&lt;/li>
&lt;li>這條切線會與曲線交於另一個點 $-R$。&lt;/li>
&lt;li>將此交點沿x軸對稱翻轉，得到的點即為所求的 $R = 2P$。&lt;/li>
&lt;/ol>
&lt;h3 id="43-代數計算公式">4.3. 代數計算公式
&lt;/h3>&lt;p>我們可以將上述的幾何操作轉換為代數公式，以便讓電腦進行計算。
所有的運算都是在**有限體 $\mathbb{F}_p$ 上（模 $p$）**進行的。&lt;/p>
&lt;p>設點 $P = (x_1, y_1)$，點 $Q = (x_2, y_2)$。
並設計算結果的點為 $R = P + Q = (x_3, y_3)$。&lt;/p>
&lt;p>設直線的斜率為 $\lambda$（Lambda）。&lt;/p>
&lt;p>&lt;strong>【情況1：當 $P \neq Q$ 時（點的加法）】&lt;/strong>
斜率 $\lambda$ 是兩點間的變化率。
&lt;/p>
$$ \lambda \equiv \frac{y_2 - y_1}{x_2 - x_1} \pmod p $$
$$ \lambda \equiv (y_2 - y_1) \cdot (x_2 - x_1)^{-1} \pmod p $$
&lt;p>使用這個 $\lambda$，我們可以如下求出 $x_3, y_3$：
&lt;/p>
$$ x_3 \equiv \lambda^2 - x_1 - x_2 \pmod p $$
$$ y_3 \equiv \lambda(x_1 - x_3) - y_1 \pmod p $$
&lt;p>&lt;strong>【情況2：當 $P = Q$ 時（點的二倍運算）】&lt;/strong>
斜率 $\lambda$ 會變成透過微分求得的切線斜率。（隱函數微分 $y^2 = x^3 + ax + b$）
&lt;/p>
$$ 2y \cdot y' = 3x^2 + a \implies y' = \frac{3x^2 + a}{2y} $$
&lt;p>
因此，
&lt;/p>
$$ \lambda \equiv (3x_1^2 + a) \cdot (2y_1)^{-1} \pmod p $$
&lt;p>$x_3, y_3$ 的公式與加法的形式相同，但因為 $x_2 = x_1$，所以變成如下形式：
&lt;/p>
$$ x_3 \equiv \lambda^2 - 2x_1 \pmod p $$
$$ y_3 \equiv \lambda(x_1 - x_3) - y_1 \pmod p $$
&lt;blockquote>
&lt;p>[!IMPORTANT]
這些公式包含了 $(x_2 - x_1)^{-1}$ 和 $(2y_1)^{-1}$ 等&lt;strong>除法（計算模反元素）&lt;/strong>。因為模反元素的計算成本極高，所以在實際實作中，通常會使用**「雅可比座標系（Jacobian Coordinates）」**等射影座標系來延遲除法的運算。&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h2 id="5-純量乘法與橢圓曲線離散對數問題ecdlp">5. 純量乘法與橢圓曲線離散對數問題（ECDLP）
&lt;/h2>&lt;p>在橢圓曲線密碼學中，計算量最大且構成安全核心的運算是&lt;strong>純量乘法（Scalar Multiplication）&lt;/strong>。&lt;/p>
&lt;h3 id="51-什麼是純量乘法">5.1. 什麼是純量乘法
&lt;/h3>&lt;p>將某個點 $P$ 連續相加 $k$ 次的操作稱為純量乘法，記為 $kP$。
&lt;/p>
$$ kP = \underbrace{P + P + \dots + P}_{k\text{次}} $$
&lt;p>這裡的 $k$ 是一個非常大的整數（例如256位元的整數）。&lt;/p>
&lt;h3 id="52-橢圓曲線離散對數問題ecdlp">5.2. 橢圓曲線離散對數問題（ECDLP）
&lt;/h3>&lt;p>橢圓曲線密碼學的安全性仰賴於以下問題的困難度：&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>橢圓曲線離散對數問題 (Elliptic Curve Discrete Logarithm Problem: ECDLP)&lt;/strong>
給定已知的點 $P$（基點）以及計算結果的點 $Q$，請求出滿足 $Q = kP$ 的純量 $k$。&lt;/p>
&lt;/blockquote>
&lt;p>從 $k$ 和 $P$ 計算出 $Q$（順向）利用後述的演算法非常簡單（多項式時間），但是從 $P$ 和 $Q$ 反推 $k$（逆向），除了暴力破解外，目前沒有高效的解法，實際上是不可能的（單向函數）。
在密碼協定中，&lt;strong>$k$ 對應「私鑰」，而 $Q$ 對應「公鑰」&lt;/strong>。&lt;/p>
&lt;h3 id="53-double-and-add-演算法">5.3. Double-and-Add 演算法
&lt;/h3>&lt;p>當 $k$ 是一個巨大數字（例如：$2^{256}$）時，單純將 $P$ 相加 $k$ 次，就算到了宇宙的盡頭也算不完。因此，為了快速進行純量乘法，我們會使用&lt;strong>Double-and-Add方法（二進位法）&lt;/strong>。&lt;/p>
&lt;p>這是快速計算整數冪的「重複平方法」的橢圓曲線版本。我們將純量 $k$ 表示為二進位數，並從最高位元開始依序處理。&lt;/p>
&lt;ol>
&lt;li>將保存結果的點 $R$ 初始化為 $\mathcal{O}$。&lt;/li>
&lt;li>從 $k$ 的最高位元到最低位元重複以下步驟：
&lt;ul>
&lt;li>將 $R$ 乘以 2（Point Doubling: $R = 2R$）&lt;/li>
&lt;li>如果當前位元為 &lt;code>1&lt;/code>，則將 $R$ 加上 $P$（Point Addition: $R = R + P$）&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>透過這個演算法，計算量從 $O(k)$ 劇烈減少到 $O(\log_2 k)$，使得在現實時間（毫秒級別）內完成計算成為可能。&lt;/p>
&lt;hr>
&lt;h2 id="6-橢圓曲線迪菲-赫爾曼ecdh金鑰交換">6. 橢圓曲線迪菲-赫爾曼（ECDH）金鑰交換
&lt;/h2>&lt;p>在此，我們將解說ECC最具代表性的應用例子——&lt;strong>ECDH（Elliptic Curve Diffie-Hellman）金鑰交換協定&lt;/strong>的運作原理。ECDH 是一種讓 Alice 和 Bob 在可能被竊聽的通訊通道上，安全地產生並共享共通私鑰（會話金鑰）的機制（這是TLS交握的核心）。&lt;/p>
&lt;p>&lt;strong>【前提參數（領域參數）】&lt;/strong>
雙方預先共享要使用的橢圓曲線 $E$、質數 $p$ 以及基點 $G$。（例如 NIST P-256 或 secp256k1 等）&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant Alice as "Alice (愛麗絲)"
participant Bob as "Bob (鮑勃)"
Note over Alice,Bob: "公開參數: 曲線 E, 基點 G, 質數 p"
Alice->>Alice: "產生私鑰 d_A (隨機整數)"
Alice->>Alice: "計算公鑰 Q_A = d_A * G"
Bob->>Bob: "產生私鑰 d_B (隨機整數)"
Bob->>Bob: "計算公鑰 Q_B = d_B * G"
Alice->>Bob: "發送公鑰 Q_A (明文)"
Bob->>Alice: "發送公鑰 Q_B (明文)"
Alice->>Alice: "計算共享秘密 S = d_A * Q_B"
Bob->>Bob: "計算共享秘密 S = d_B * Q_A"
Note over Alice,Bob: "S = d_A * (d_B * G) = d_B * (d_A * G) = (d_A * d_B) * G"
Note over Alice,Bob: "雙方的計算結果 S 完全一致！"&lt;/div>
&lt;p>竊聽者（Eve）雖然能攔截通訊路徑上的 $G$、$Q_A$、$Q_B$，但由於 ECDLP 的困難性，無法從 $Q_A = d_A \cdot G$ 推導出 Alice 的私鑰 $d_A$。此外，即使將 $Q_A$ 和 $Q_B$ 相乘，也不會得到共享金鑰 $S$，因此竊聽者無法計算出 $S$。&lt;/p>
&lt;hr>
&lt;h2 id="7-實作的陷阱旁路攻擊與對策">7. 實作的陷阱：旁路攻擊與對策
&lt;/h2>&lt;p>即使是理論上完美的密碼演算法，在將其編寫為程式的過程中，也可能產生漏洞。這就是**「旁路攻擊（Side-Channel Attack）」**。&lt;/p>
&lt;h3 id="71-計時攻擊timing-attack">7.1. 計時攻擊（Timing Attack）
&lt;/h3>&lt;p>讓我們回顧一下前面提到的 Double-and-Add 演算法。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 脆弱的 Double-and-Add 虛擬碼
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="n">R&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Infinity&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">255&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">--&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">R&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PointDoubling&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// 總是會執行
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">bit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">R&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PointAddition&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// 只有當位元為1時才會執行！
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>這個實作有一個致命的缺陷。因為當位元為 &lt;code>1&lt;/code> 時會執行 Point Addition，所以計算時間會比位元為 &lt;code>0&lt;/code> 時&lt;strong>稍微長一點&lt;/strong>。此外，處理器的分支預測和快取記憶體的行為也會改變。
攻擊者藉由統計觀察這微小的計算時間（或耗電量）差異數千次，就能&lt;strong>將私鑰 $k$ 的位元序列逐位元完全還原&lt;/strong>。這就是計時攻擊。&lt;/p>
&lt;h3 id="72-常數時間constant-time實作montgomery-ladder">7.2. 常數時間（Constant-Time）實作：Montgomery Ladder
&lt;/h3>&lt;p>為了防範計時攻擊，我們必須採用**無論私鑰位元值為何，執行的指令序列和計算時間都始終保持恆定（Constant-Time）**的演算法。&lt;/p>
&lt;p>最具代表性的例子就是&lt;strong>Montgomery Ladder（蒙哥馬利階梯）&lt;/strong>。&lt;/p>
&lt;div class="mermaid">graph TD
Start["初始化: R0 = O, R1 = P"] --> LoopStart["對於每個位元 i (從最高位起)"]
LoopStart --> Cond{"k_i 的值是？"}
Cond -->|0| Branch0["R1 = R0 + R1&lt;br>R0 = 2 * R0"]
Cond -->|1| Branch1["R0 = R0 + R1&lt;br>R1 = 2 * R1"]
Branch0 --> LoopEnd["前往下一個位元"]
Branch1 --> LoopEnd
LoopEnd --> LoopStart
LoopStart -.->|"所有位元處理完畢"| End["結束: R0 即為結果 (kP)"]&lt;/div>
&lt;p>Montgomery Ladder的優美之處在於，無論位元是 &lt;code>0&lt;/code> 還是 &lt;code>1&lt;/code>，都**「始終會執行1次 Point Addition 和1次 Point Doubling」**。這徹底消除了計算時間的資料依賴性。&lt;/p>
&lt;p>然而，只要分支（&lt;code>if (k_i == 0)&lt;/code>）本身存在，編譯器的最佳化或 CPU 的分支預測仍可能帶來執行時間波動的風險。因此，在實際的常數時間實作中，我們會消除條件分支（&lt;code>if&lt;/code> 敘述），並使用&lt;strong>位元運算來進行條件式交換（Conditional Swap）&lt;/strong>。&lt;/p>
&lt;hr>
&lt;h2 id="8-使用c實作橢圓曲線密碼學">8. 使用C++實作橢圓曲線密碼學
&lt;/h2>&lt;p>從這裡開始，我們將把理論轉化為C++程式碼。實用的密碼學函式庫（如 OpenSSL 或 libsodium 等）採用了高度的組合語言最佳化和雅可比座標系，但在這裡，為了加深對數學的理解，我們將展示一個&lt;strong>使用仿射座標系（Affine Coordinates）、容易理解的常數時間實作&lt;/strong>架構。&lt;/p>
&lt;p>我們假設使用 &lt;code>boost::multiprecision::cpp_int&lt;/code> 來處理大整數運算。&lt;/p>
&lt;h3 id="81-模運算與反元素">8.1. 模運算與反元素
&lt;/h3>&lt;p>首先，定義有限體上運算的輔助函式。我們實作利用費馬小定理計算反元素的方法。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;stdexcept&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;boost/multiprecision/cpp_int.hpp&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="k">namespace&lt;/span> &lt;span class="n">boost&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">multiprecision&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 以 secp256k1 的質數 p 與參數為例
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">p&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">7&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 回傳正餘數的模運算
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nl">m&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">r&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 模冪運算 (x^y mod m)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">powerMod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">exp&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">base&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">exp&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">exp&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">res&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">base&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">base&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exp&lt;/span> &lt;span class="o">/=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">res&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 使用費馬小定理計算模反元素
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">modInverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 假設 m 是質數: n^(m-2) ≡ n^(-1) mod m
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">powerMod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="82-點的表示與群運算加法二倍運算">8.2. 點的表示與群運算（加法、二倍運算）
&lt;/h3>&lt;p>我們將無窮遠點以旗標（flag）來管理，建立 &lt;code>Point&lt;/code> 結構體，並實作加法公式。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">struct&lt;/span> &lt;span class="nc">Point&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="n">isInfinity&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 產生無窮遠點
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">isInfinity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">true&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 產生一般的點
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">isInfinity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">false&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 橢圓曲線上的點加法 (R = P + Q)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="nf">pointAdd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isInfinity&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isInfinity&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// P + (-P) = 無窮遠點
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">lambda&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Point Doubling (當 P = Q 時)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// lambda = (3x^2 + a) / 2y
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">den&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">modInverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lambda&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">den&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Point Addition (當 P != Q 時)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// lambda = (y2 - y1) / (x2 - x1)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">den&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">modInverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lambda&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">den&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x3&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">lambda&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">lambda&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">y3&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">lambda&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">x3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y3&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="83-constant-time-conditional-swap-的實作">8.3. Constant-Time Conditional Swap 的實作
&lt;/h3>&lt;p>在根據私鑰位元值來交換變數內容時，我們不使用 &lt;code>if&lt;/code> 敘述，而是僅透過位元運算（遮罩）來進行交換。如此一來，執行路徑將保持絕對一致。&lt;/p>
&lt;blockquote>
&lt;p>[!TIP]
在實際的實作中，像 &lt;code>cpp_int&lt;/code> 這種動態配置記憶體的多倍長整數類別並不適合常數時間處理。因為記憶體配置或陣列大小的變動可能會洩漏時間資訊。在實用的函式庫中，通常會以固定長度（例如 uint64_t × 4個元素的陣列）來表示，並實作位元層級的遮罩處理。以下僅為概念性的範例。&lt;/p>
&lt;/blockquote>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 概念性的常數時間交換 (假設為固定長度整數)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 如果 bit 為 1 則交換 P1 和 P2，若為 0 則不交換
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">void&lt;/span> &lt;span class="nf">cswap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">bit&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// bit 為 0 或 1。遮罩在 bit=1 時全為1 (0xFF..)，在 0 時全為0。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// (這裡為了說明，假設固定長度的 BigInt 類別每個 word 為 w)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="cm">/*
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> uint64_t mask = 0 - (uint64_t)bit;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> for (int i = 0; i &amp;lt; NUM_WORDS; i++) {
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> uint64_t dummy = mask &amp;amp; (P1.x.words[i] ^ P2.x.words[i]);
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> P1.x.words[i] ^= dummy;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> P2.x.words[i] ^= dummy;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> // y座標與 isInfinity 旗標也同樣處理
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ※ 在 boost::multiprecision 中很難實現完美的常數時間交換，
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// 在此僅以分支條件來模擬，幫助理解邏輯。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">bit&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">P1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">P2&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="84-使用-montgomery-ladder-進行純量乘法">8.4. 使用 Montgomery Ladder 進行純量乘法
&lt;/h3>&lt;p>結合前面的 &lt;code>pointAdd&lt;/code> 和 &lt;code>cswap&lt;/code>，我們來實作安全的純量乘法。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 純量乘法 k * P (Montgomery Ladder 方式)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="nf">scalarMultiply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">k&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Point&lt;/span> &lt;span class="n">R0&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// 無窮遠點
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Point&lt;/span> &lt;span class="n">R1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 取得 k 的位元長度 (secp256k1 為 256 位元)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">numBits&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">256&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">numBits&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">--&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 取得第 i 個位元的值 (0 或 1)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">bit&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">static_cast&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">uint8_t&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bit_test&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 如果 bit == 1，則交換 R0 和 R1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cswap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">bit&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 始終執行相同的運算 (Point Addition 和 Point Doubling)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">R1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pointAdd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">R0&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pointAdd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 如果 bit == 1，為了將狀態復原，再次進行交換
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cswap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">bit&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">R0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>透過這樣的實作邏輯，無論純量 $k$ 的各個位元是 &lt;code>0&lt;/code> 還是 &lt;code>1&lt;/code>，在每次迴圈疊代中執行的運算（&lt;code>cswap&lt;/code> $\to$ &lt;code>pointAdd&lt;/code> $\to$ &lt;code>pointAdd&lt;/code> $\to$ &lt;code>cswap&lt;/code>）都會完全相同，從而有效防止攻擊者透過計時或快取存取模式的差異來竊取機密資訊。&lt;/p>
&lt;hr>
&lt;h2 id="9-總結">9. 總結
&lt;/h2>&lt;p>初次接觸橢圓曲線密碼學（ECC）時，可能會對「為什麼畫一條直線並將交點翻轉這種幾何操作能成為密碼？」感到不可思議。然而，這正是將其映射到有限體這個離散世界後，所建構出完美的單向函數（離散對數問題），可說是數學與密碼學奇蹟般融合的產物。&lt;/p>
&lt;p>本文解說了以下幾個重點：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>對 RSA 的優勢&lt;/strong>: 能以極短的金鑰長度提供強大的安全性，是現代行動裝置與物聯網（IoT）時代的最佳選擇。&lt;/li>
&lt;li>&lt;strong>群論與有限體基礎&lt;/strong>: 構成 ECC 基礎的數學結構。&lt;/li>
&lt;li>&lt;strong>加法與二倍運算公式&lt;/strong>: 使用魏爾斯特拉斯方程式的代數群運算實作方法。&lt;/li>
&lt;li>&lt;strong>旁路攻擊的威脅&lt;/strong>: 依賴於私鑰位元的條件分支會造成致命的漏洞。&lt;/li>
&lt;li>&lt;strong>常數時間（Constant-Time）實作&lt;/strong>: 採用 Montgomery Ladder 和 Conditional Swap，使硬體層級的行為均勻化以防止攻擊的 C++ 程式設計技巧。&lt;/li>
&lt;/ol>
&lt;p>一般極不建議自行編寫應用於正式生產環境的密碼學函式庫（&amp;ldquo;Don&amp;rsquo;t roll your own crypto&amp;rdquo;），因為這伴隨著極高的安全風險。然而，對於設計和維護高安全性、高效能系統的工程師來說，深入了解其內部運作的演算法及數學背景，無疑是一項極其寶貴且強大的武器。&lt;/p>
&lt;p>在下一篇文章中，我們將進一步探討利用這條橢圓曲線所建立的數位簽章演算法——&lt;strong>ECDSA (Elliptic Curve Digital Signature Algorithm)&lt;/strong> 的機制，以及比特幣所採用的 &lt;strong>Schnorr 簽章&lt;/strong>。&lt;/p></description></item></channel></rss>