密码学基础回顾:有限域与椭圆曲线

说实话,很多工程师一上来就撸SM2的代码,结果在密钥对生成那一步就卡住了。为什么?因为没搞懂背后的数学结构。我当年也是踩过这个坑的——直接调库当然能跑,但一旦遇到跨平台互调、性能优化或者硬件适配,不懂原理根本没法debug。

这一章,咱们就把SM2依赖的密码学基础捋一遍。不扯太深的理论,够用就行。

2.1 有限域:SM2的“数字沙盘”

有限域,说白了就是一个元素个数有限的集合,里面的数可以做加减乘除,结果还在这个集合里。SM2用的是素域Fp,p是一个大素数。

核心概念:SM2的椭圆曲线定义在Fp上,p = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF

这个p有256位。为什么选这个数?我个人的理解是:它既保证了安全性,又方便硬件实现——你看它的二进制形式,大部分位都是1,做模运算时可以优化。

有限域上的运算规则很简单:

  • 加法:a + b mod p
  • 乘法:a × b mod p
  • 逆元:a × a-1 ≡ 1 mod p

我的经验:在嵌入式设备上实现SM2时,模逆运算最耗性能。我曾经用费马小定理 ap-2 mod p 来计算逆元,虽然慢但通用。后来换成扩展欧几里得算法,速度提升了3倍。

2.2 椭圆曲线:SM2的“几何舞台”

SM2使用的椭圆曲线方程是:

y² = x³ + ax + b  (mod p)

其中参数a和b是固定的:

参数 值(十六进制)
a 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC
b 0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93

嗯,这里要注意:SM2的曲线参数是国标规定的,不能自己随便改。我在项目里见过有人从网上复制了错误的参数,结果签名验证一直失败——折腾了两天才发现是b参数写错了一位。

椭圆曲线上的点,就是满足这个方程的所有(x, y)对,再加上一个特殊的“无穷远点”O。

2.3 点加运算:曲线上的“加法”

椭圆曲线上的点加法,不是普通坐标相加。它有一套几何规则:

  1. 过点P和Q画一条直线
  2. 这条直线与曲线交于第三点R'
  3. R'关于x轴的对称点就是P+Q的结果

公式长这样(别怕,实际代码里都是现成的):

设 P = (x₁, y₁), Q = (x₂, y₂), P ≠ Q
λ = (y₂ - y₁) / (x₂ - x₁) mod p
x₃ = λ² - x₁ - x₂ mod p
y₃ = λ(x₁ - x₃) - y₁ mod p

避坑指南:我曾经在实现点加时,忘记处理P=Q的情况(倍点)和P=-Q的情况(结果为无穷远点)。这两个边界条件不处理,密钥对生成就会随机出错,而且很难复现。

倍点(P=P的情况)公式略有不同:

λ = (3x₁² + a) / (2y₁) mod p
x₃ = λ² - 2x₁ mod p
y₃ = λ(x₁ - x₃) - y₁ mod p

2.4 标量乘法:密钥生成的核心

标量乘法就是:k × P = P + P + ... + P(k次)。

但你不能真的加k次——k是256位的数,加2²⁵⁶次得算到宇宙毁灭。实际用的是“双倍-加”算法:

function scalar_mult(k, P):
    R = O  // 无穷远点
    for i from 255 down to 0:
        R = double(R)      // 倍点
        if bit_i_of_k == 1:
            R = add(R, P)  // 点加
    return R

这个算法只需要256次倍点和平均128次点加,效率高得多。

性能优化:我在做SM2硬件加速时,发现可以用“窗口法”进一步优化——把k分成4位一组,预计算16个点,每次查表。这样点加次数减少到64次,速度提升明显。

2.5 密钥对生成原理

终于到正题了。SM2密钥对生成其实就三步:

  1. 选私钥:在[1, n-1]范围内随机选一个整数d,n是曲线的阶(也是一个固定的大素数)
  2. 算公钥:P = d × G,G是曲线的基点
  3. 输出:私钥d,公钥P

基点的坐标也是国标规定的:

Gx = 0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7
Gy = 0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0

为什么公钥不能从私钥反推?因为标量乘法是“单向”的——知道d和G算P很容易,但知道P和G反推d,就是椭圆曲线离散对数问题,目前没有多项式时间算法。

安全要点:随机数生成器必须真随机。我曾经见过一个项目,用C语言的rand()生成私钥,结果每次启动私钥都一样——这等于没加密。SM2标准推荐使用国家密码管理局认可的随机数发生器。

2.6 本章知识体系

下面这张图把本章的核心逻辑串起来了:

SM2密码学基础结构图 SM2密码学基础:从有限域到密钥对 有限域 Fₚ p = 256位大素数 椭圆曲线 E(Fₚ) y² = x³ + ax + b 基点 G 阶为n的生成元 定义在 选取 点加运算 倍点运算 标量乘法 k×G 私钥 d 随机数 ∈ [1, n-1] 公钥 P P = d × G 生成 标量乘 核心逻辑 1. 有限域Fₚ提供运算环境,椭圆曲线定义点的集合 2. 点加和倍点是标量乘法的基本操作 3. 标量乘法 d×G 从私钥生成公钥,单向不可逆

这张图从下往上看:有限域是地基,椭圆曲线是建筑,基点是入口,标量乘法是电梯,密钥对是顶层房间。每一步都依赖前一步,缺一不可。

2.7 小结

这一章我们走完了从有限域到密钥对的完整路径。说白了,SM2的密码学基础就是三件事:

  • 在有限域上定义椭圆曲线
  • 用点加和倍点实现标量乘法
  • 用标量乘法从私钥算出公钥