2. SM2数学基础与工程实现要点
SM2 的安全性建立在有限域上的椭圆曲线离散对数难题之上,但工程实现中真正决定性能与安全边界的,往往不是数学定义本身,而是有限域运算、群运算、模逆与模幂的实现方式,以及是否满足常量时间要求。本节从“数学对象如何映射到代码”的角度,梳理 SM2 实现中最关键的几个工程要点。
一、有限域运算:SM2 的算术底座
SM2 推荐使用素域 F_p,其中素数 p 为 256 位。所有坐标、标量、中间结果都在 [0, p-1] 范围内。工程上最常用的表示方式是“多字整数”,例如用 4 个 64 位字或 8 个 32 位字表示一个 256 位元素。有限域运算主要包括:
- 模加/模减:先做普通加减,再根据是否越界决定是否加减
p,通常用条件移动避免分支。 - 模乘:先做多字乘法得到 512 位中间结果,再做模约减。SM2 的
p具有特殊形式,可利用快速约减减少除法开销。 - 模平方:可复用模乘逻辑,也可针对平方做优化,减少部分乘法次数。
- 模逆:用于求坐标的仿射表示、签名中的
k^{-1}等,通常用扩展欧几里得或费马小定理实现。
工程实现中,模乘是最热点的运算。以 256 位素域为例,一次普通多字乘法约需 16 次 64×64 乘法,若再叠加通用除法约减,开销会显著上升。因此,SM2 实现通常采用“快速约减”:利用 p 的高位结构,把 512 位结果拆成高低两部分,通过若干次移位、加法和少量乘法完成约减,避免昂贵的除法。
二、椭圆曲线群:点运算与标量乘
SM2 的椭圆曲线方程为 y² = x³ + ax + b,其中 a = -3,这为点倍运算提供了优化空间。群元素是曲线上的点,群运算包括点加、点倍和标量乘。工程实现中,点通常用雅可比坐标 (X, Y, Z) 表示,避免每次点运算都做模逆,只在最后转回仿射坐标时做一次模逆。
标量乘 kP 是 SM2 签名、验签、密钥交换的核心。朴素的双倍-点加算法按位扫描标量,每一位执行一次点倍,若该位为 1 再执行一次点加。这种实现存在明显的分支和时序差异,容易被侧信道攻击利用。工程上更推荐使用固定窗口、滑动窗口或 Montgomery 阶梯,并配合常量时间条件选择。
三、模逆与模幂的高效实现
模逆在 SM2 中出现在多个位置:仿射坐标转换、签名方程 s = (1+d)^{-1}(k - r·d) mod n 中的逆元、以及验签中的若干除法。工程上有两条主流路线:
- 扩展欧几里得算法:迭代次数与输入相关,通常比模幂快,但天然存在数据相关分支,需要改造成常量时间版本,例如固定迭代次数、用条件移动替代分支。
- 费马小定理:
a^{-1} = a^{p-2} mod p,把模逆转化为模幂。模幂本身可以用固定窗口或 Montgomery 阶梯实现,天然更容易做到常量时间,但计算量约为扩展欧几里得的数倍。
模幂在 SM2 中主要用于模逆和部分密钥派生场景。实现时通常采用平方-乘法或固定窗口法,并保证指数扫描过程与指数值无关。对于 256 位指数,固定窗口宽度取 4 或 5 时,预计算表大小与乘法次数之间取得较好平衡。
四、常量时间编程注意事项
侧信道攻击是 SM2 工程实现中必须正视的威胁。攻击者可以通过测量签名耗时、功耗或缓存访问模式,推断标量位、密钥位或中间值。常量时间编程的目标是让执行路径、内存访问模式和运算次数不依赖于秘密数据。具体注意事项包括:
- 避免秘密相关的分支:不要写
if (k_bit == 1) { ... },改用条件移动或掩码选择。 - 避免秘密相关的内存访问:查表时不要用秘密索引直接访问数组,应遍历整个表并用掩码选出目标项。
- 避免秘密相关的循环次数:标量乘的循环次数应固定为标量位长,即使高位为 0 也要执行。
- 注意编译器优化:某些“常量时间”写法可能被编译器重新引入分支,需使用
volatile、内存屏障或编译器内置函数加以约束。 - 统一错误处理路径:验签失败与成功不应在时间上产生明显差异,避免通过错误信息泄露中间状态。
五、工程实现检查清单
下面给出一份可直接对照使用的实现检查清单,覆盖本节涉及的关键点:
| 检查项 | 要求 | 判断依据 |
|---|---|---|
| 模乘约减 | 使用 SM2 专用快速约减,避免通用除法 | 单次模乘耗时应显著低于通用大数除法版本 |
| 点表示 | 中间过程使用雅可比坐标,仅输出时转仿射 | 整个标量乘过程中模逆次数不超过 1 次 |
| 标量乘 | 固定窗口 + 条件移动,循环次数固定 | 不同标量输入下,执行路径与访存模式一致 |
| 模逆 | 优先常量时间扩展欧几里得,或固定窗口模幂 | 逆元计算时间不随输入值明显波动 |
| 查表 | 遍历全表 + 掩码选择,禁止秘密索引直接访存 | 缓存访问模式与秘密索引无关 |
| 错误处理 | 验签失败与成功路径时间一致 | 两种路径的指令数与访存模式基本一致 |
从工程角度看,SM2 的实现质量取决于三个层面的协同:有限域层要快且无分支,群运算层要减少模逆并统一坐标,标量乘层要固定路径并屏蔽秘密相关访存。只有把这三层都纳入常量时间约束,才能在满足性能要求的同时,抵御计时、功耗和缓存等侧信道攻击。