第2章:SM2算法原理:椭圆曲线基础归纳总结

聊SM2之前,得先搞明白它背后的数学基石——椭圆曲线。说实话,我刚接触密码学时也觉得这东西很抽象,后来在项目中踩过坑才真正体会到:你如果不理解椭圆曲线,SM2的密钥对、签名验签就是黑盒调试,出了问题根本无从下手。

2.1 什么是椭圆曲线?

椭圆曲线不是椭圆函数,也不是椭圆形状的曲线。它是一条在二维平面上满足特定方程的曲线。密码学中常用的形式是Weierstrass方程:

y² = x³ + ax + b   (其中4a³ + 27b² ≠ 0)

那个不等于零的条件是为了保证曲线没有“奇点”(尖点或自交),否则加法运算就不良定义。我在项目中遇到过把a、b参数抄错导致曲线校验不通过的情况,排查了好久才发现是文档拷贝时多了一个空格。

椭圆曲线长什么样子?举个例子,a = -1, b = 0 时的曲线在实数域上是左右对称的图形,有点像两个驼峰。但密码学里我们不在实数域上做运算——浮点数误差没法控制,所以要用有限域。

2.2 有限域上的椭圆曲线

SM2使用的是素域Fp,p是一个大素数。曲线上的点坐标都是0到p-1之间的整数,所有运算对p取模。这样一来,曲线上的点集就变成了一个有限的离散点集合,这是密码学能用的前提。

域类型 典型p长度 SM2标准 运算特点
素域 Fp 256位 SM2推荐p = 2^256 - 2^224 - 2^96 + 2^64 - 1 整数模p运算,硬件友好
二进制定域 F2^m 同上 SM2不采用 适合特定硬件,但安全性分析复杂

我个人习惯上只记素域Fp,因为SM2、SM3、SM4这条链路里的国密标准全部基于它。你想想看,整个SM2的密钥交换、签名验算都跑在Fp上,所以理解好模运算很重要。

2.3 椭圆曲线上的点加法

这是椭圆曲线最精彩的部分。两个在曲线上的点P和Q相加,可以得到第三个点R。几何解释很简单:

  • 过P和Q作直线,与曲线相交于第三点R'
  • 将R'关于x轴对称得到R,就是P+Q的结果

注意几个边界情况:

  • 如果P=Q,则做切线(倍点运算)
  • 如果P是Q关于x轴的对称点,则P+Q = 无穷远点(零元)
  • 无穷远点记作O,任何点加O等于它本身

我一直记得刚学倍点公式时,总是把斜率计算搞反。后来写了一个小demo验证:先算一个点,再算两倍,再算三倍,看看能不能拼回原值。我建议你也这样做一次——亲手验算几个点,比你背十遍公式都牢。

2.4 群的阶与基点

所有曲线上点的个数加上无穷远点,称为曲线的阶,记作#E(Fp)。阶是一个很难计算的大数,SM2标准直接给出了SM2曲线的阶n。

基点是曲线上一个特定的点G,它的阶是一个大素数(通常是n)。为什么需要基点?因为所有参与者的运算都从G开始:

  • 私钥 d: 一个随机大整数,范围 [1, n-1]
  • 公钥 Q: Q = d × G (标量乘法)

标量乘法就是连续的点加和倍点运算,比如 d×G = G+G+...+G(d次)。这就是椭圆曲线密码学的核心——从私钥算公钥很容易,但反过来从公钥算私钥非常困难(椭圆曲线离散对数问题,ECDLP)。

2.5 SM2椭圆曲线参数一览

SM2标准里给出了一套固定的曲线参数(SM2P256V1)。你不用自己选,直接用标准里的即可。我见过一些团队试图“增强安全性”修改参数,结果导致互操作性问题,最后不得不回退。

重要的几个:

参数名 含义 SM2标准值(十六进制截取)
p 素域模数 FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFF
a Weierstrass系数a FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFC
b Weierstrass系数b 28E9FA9E 9D9F5E34 4D5A9E4B CF6509A7 F39789F5 15AB8F92 DDBCBD41 4D940E93
Gx 基点G的x坐标 32C4AE2C 1F198119 5F990446 6A39C994 8FE30BBF F2660BE1 715A4589 334C74C7
Gy 基点G的y坐标 BC3736A2 F4F6779C 59BDCEE3 6B692153 D0A9877C C62A4740 02DF32E5 2139F0A0
n 基点G的阶 FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF 7203DF6B 21C6052B 53BBF409 39D54123
⚠️ 我曾经犯过的错: 在移植SM2代码时,我把p和n搞混了,导致签名验证一直失败。这两个值很像,但一个是域模数,一个是群阶。千万别复制粘贴错了。

2.6 密钥对生成流程

有了基点G和阶n,密钥生成就是一个标量乘法。流程很简单:

  1. 生成随机数 d ∈ [1, n-1](作为私钥)
  2. 计算 Q = d × G(点乘)
  3. 输出 (d, Q)

点乘的实现有很多种:二进制展开、滑动窗口、Montgomery ladder(防侧信道攻击)。SM2推荐用二进制展开,但如果你做安全芯片,我建议用Montgomery ladder——它在时间上恒定,不容易被时序攻击。

关键点: 私钥d必须用安全的随机数生成器。在嵌入式项目中我曾用系统rand()生成密钥,结果被同事用采样法猜出了部分私钥熵。后来全部换成了SM3驱动的DRBG(伪随机数生成器)。

2.7 核心概念关系图

为了帮你把这几节内容串起来,我画了一张结构图。它展示了SM2椭圆曲线密码体系的骨架:

SM2椭圆曲线核心概念关系 SM2椭圆曲线密码体系核心结构 椭圆曲线基础 方程 y² = x³ + ax + b 参数 a, b, p 非奇条件: 4a³+27b²≠0 素域 Fp 模 p 运算 点加法 & 标量乘法 几何几何:弦 + 对称 倍点:切线法 Q = d × G 无穷远点 O 作为零元 参数 & 基点 G SM2P256V1 标准参数 基点 G (Gx, Gy) 阶 n(大素数) 曲线阶 #E(Fp) 密钥对生成 私钥 d ∈ [1, n-1] 公钥 Q = d × G ECDLP 安全性基础 SM2 所有密码运算(签名、验签、密钥交换、加密解密)都建立在这套椭圆曲线结构上。 核心安全假设:已知公钥 Q 求私钥 d 在计算上不可行(ECDLP 困难性)。
💡 我的一个经验: 当你需要调试SM2签名验签时,不要一头扎进算法细节。先确认曲线参数p、a、b、G、n是否正确——这五个值错了任何一个,后续全白干。我常用的做法是在初始化时打印一组校验和,跟标准文档逐字节核对。

2.8 本章小结

椭圆曲线密码学本质上是一套在有限域上封闭的加法群操作。你只要记住三件事:

  • 曲线方程和域参数决定群结构
  • 点加/倍点定义运算规则
  • 私钥→公钥是单向的标量乘法