<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Mathematics on kenji.blog</title><link>http://kenji.blog/zh-cn/tags/mathematics/</link><description>Recent content in Mathematics on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 10:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/zh-cn/tags/mathematics/index.xml" rel="self" type="application/rss+xml"/><item><title>椭圆曲线密码学（ECC）的数学基础与C++实现</title><link>http://kenji.blog/zh-cn/p/elliptic-curve-cryptography-math-cpp/</link><pubDate>Fri, 11 Sep 2026 10:00:00 +0900</pubDate><guid>http://kenji.blog/zh-cn/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位。这使得减少计算量、降低内存使用量和节约网络带宽成为可能，特别是在资源有限的物联网设备和智能卡环境中，ECC拥有压倒性的优势。&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}$ 是模 $p$ 下 $b$ 的乘法逆元）&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$ 次方即可求得逆元。因为幂运算容易实现为常数时间操作，所以密码学实现中通常更倾向于使用这种方法。&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}$（字母 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 + 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$ 翻倍（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 是爱丽丝和鲍勃在可能被窃听的通信信道上，安全地生成并共享共同私钥（会话密钥）的机制（这也是 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>窃听者（伊芙）可以截获通信路径上流动的 $G$、$Q_A$、$Q_B$，但由于 ECDLP 的困难性，无法从 $Q_A = d_A \cdot G$ 推导得出爱丽丝的私钥 $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>1&lt;/code> 时所需的&lt;strong>计算时间会比位为 &lt;code>0&lt;/code> 时稍微长一些&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>，都会**“始终执行一次 Point Addition 和一次 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>使用仿射坐标系且易于理解的 Constant-Time 实现&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>通过标志位管理无穷远点的 &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> 这样动态分配的多精度整数类并不适合 Constant-Time 处理。因为内存分配和数组大小的变化会泄露计时信息。在实用库中，使用固定长度（例如 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">// 概念性的 Constant-Time Swap (假设使用定长整数)
&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 类的每个字为 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>: 能在非常短的密钥长度下提供强大的安全性，是现代移动互联网和物联网时代的最佳选择。&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>