2、SM2 椭圆曲线基础

椭圆曲线密码学 – 先说点直觉

椭圆曲线密码学(ECC),说白了就是在一张特殊的曲线上做加法。不是坐标加法,是点与点之间的合成运算。你能想象两点连一条线,交到曲线上再翻个跟头,得到第三个点吗?就是这样一套几何操作,构成了整个密码体系。

我第一次看这玩意儿也懵。工作几年后回头看,其实核心就一句话:在椭圆曲线上,给你一个点 P,给你一个整数 k,算出 k 个 P 相加的结果 Q 很容易;反过来,给你 P 和 Q,让你反推出 k,几乎不可能。 这就叫椭圆曲线离散对数难题。

我有次给团队新人讲这个,画了满白板的点线交叉,最后用了一个比喻:你站在北京天安门广场,先向东走 3 步,再向北走 5 步,位置明确。但别人只知道你的起点和终点,想猜出你走了几步?嗯,没有地图的话,你只能把整条路枚举一遍——这就是 ECC 之所以安全的原因。

SM2 用的是什么曲线?

SM2 用的是基于素数域 \(F_p\) 的 Weierstrass 曲线,标准方程长这样:

\(y^2 = x^3 + ax + b\)

这里的 \(a\)、\(b\)、\(p\) 都是国家密码管理局定死的常数,不能随便改。下面这张表是 SM2 的官方参数,我建议你直接存成代码常量,别手敲,容易敲错。我就吃过这个亏——当年手动抄参数时少抄了一位十六进制 p,导致运算出来的点根本不在曲线上,排错排了一下午。

参数值(十六进制)说明
pFFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFF素数模数,256 位
aFFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFC曲线方程系数 a
b28E9FA9E 9D9F5E34 4D5A9E4B CF6509A7 F39789F5 152AB8F0 2DD8B311...曲线方程系数 b
G(Gx, Gy)见标准文档基点,同时也是子群的生成元
nFFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF 7203DF6B 21C6052B 53BBF409 39D54123基点 G 的阶(素数)
h1余因子,SM2 曲线 h=1 表示整个椭圆曲线阶等于 n
注意:曲线参数必须使用国密标准(GM/T 0003-2012)中的指定值。我在做某省政务云项目时,发现协作方从网上复制了 SM2 参数,结果公钥验证一直失败——因为网上流传着一份非官方的变体曲线参数。所以务必以《SM2 椭圆曲线公钥密码算法》标准原文为准。

密钥对生成原理

生成一对 SM2 密钥其实就三步:

  1. 产生随机数 k——k 是 1 到 n-1 之间的整数。安全要求高的话,要用硬件随机数发生器,不能用伪随机库。我见过用 Python random 模块生成密钥的线上事故……嗯,后果很严重。
  2. 计算公钥 P = [k]G——这里的 [k]G 代表点乘:把基点 G 和自己相加 k 次。这个过程叫标量乘法。
  3. 输出 (k, P)——私钥 k 必须保密存储,公钥 P 可以公开。

这里面最核心、也最耗时的运算就是标量乘法。我通常用 Montgomery 阶梯法实现,兼顾效率与侧信道防护。你写 SM2 代码时务必注意:标量乘法必须做到常数时间,否则攻击者能通过执行时间推断私钥位数。

我曾经踩过的坑: 在 IoT 设备上用纯软件实现 SM2,芯片不带椭圆曲线加速指令。我天真地用了 double-and-add 算法且没加掩码,结果用示波器看一眼功耗曲线就能区分是 double 还是 add——侧信道攻击直接裸奔。后来加上了随机化点表示和盲化标量,才通过商密检测。

密钥对生成的完整流程

下面这张 SVG 图把整体逻辑画了出来。你可以对照着看,理解每一步的输入输出:

SM2 密钥对生成流程 1. 随机数 k ∈ [1, n-1] 2. 公钥 P = [k]G (标量乘法) 基点 G(曲线参数) 3. 密钥对 (sk = k, pk = P) 私钥 k 保密 → 公钥 P 分发 💡 关键点: • 从私钥 k 求公钥 P 很容易(一次标量乘法) • 从公钥 P 反推私钥 k 等价于解离散对数,目前无多项式算法 • 因此 SM2 的安全性建立在 ECDLP 的难度之上

图里标了三个核心步骤,最后那把锁表示私钥与公钥的单向关系。实际工程中,随机数 k 的生成质量直接决定安全性——如果用同一个 k 签过两次不同消息,攻击者就能把私钥算出来。SM2 标准里已有处理措施,但底层库开发者千万不能自己发明随机数方案。

小试牛刀——自己算笔账

你可以拿小参数试验一下。比如用曲线 y² = x³ + 7(比特币的 secp256k1,但不是 SM2),基点 G 取 (2, 3),私钥 k = 5。手动计算 [5]G = G + G + G + G + G。依次做倍点和点加,最后落到某个整数点 P。理解了这个逻辑,再看 SM2 标量乘法就通了。

我当年入门时最困惑的是“椭圆曲线上加法怎么不像数学加法”。后来我写了不到 50 行 Python 脚本,自己实现点加和倍点,打印每一步的坐标,配合画图才彻底搞明白。建议你也动手实践一下。

一句话总结本章:SM2 的密钥对生成就是「选一个秘密整数 k,算 k 个 G 相加」。后面所有签名、加解密都建立在这对密钥之上。