1. SM2 算法概述:国密标准背景、椭圆曲线密码基础、SM2 与 ECDSA/E25519 的对比

各位同学,咱们今天正式开讲《SM2 算法性能优化与调优技巧》的第一章。说实话,每次讲国密算法,我都能想起十年前第一次在项目中硬啃 SM2 标准文档的日子——那时候资料少,踩坑多,但回过头看,这些经历反而让我对这套算法有了更深的体感。

这一章,我们不急着写代码,也不急着调优。先把 SM2 的来龙去脉、数学根基,以及它跟 ECDSA、Ed25519 这些主流签名算法的差异理清楚。你想想看,如果连算法为什么长这样都不清楚,后面优化起来很容易走弯路。

1.1 国密标准背景:为什么要有 SM2?

SM2 是国家密码管理局在 2010 年发布的椭圆曲线公钥密码算法标准,编号 GM/T 0003-2012。说白了,它是咱们国家自己的 ECC 算法体系,对标国际上的 ECDSA 和 ECDH。

为什么要搞一套自己的?核心原因就两个:

  • 自主可控:国际算法标准由 NIST 等机构制定,背后涉及复杂的政治和技术博弈。我记得 2013 年斯诺登事件后,很多国内政企项目直接要求「必须用国密」,那时候我们团队连夜改代码,印象太深了。
  • 安全冗余:SM2 使用的椭圆曲线参数是独立生成的,不依赖 NIST 曲线。虽然目前没有证据说 NIST 曲线有后门,但「自己手里有钥匙」总归更踏实。

核心要点:SM2 不是简单的「中国版 ECDSA」。它在签名算法结构、密钥生成方式、哈希使用上都有独立设计。后面我们会详细对比。

目前 SM2 已广泛应用于电子政务、金融 IC 卡、物联网安全芯片等领域。如果你做的是国内合规项目,SM2 基本是必选项。

1.2 椭圆曲线密码基础:SM2 的数学根基

椭圆曲线密码(ECC)的核心,是在一个有限域上的椭圆曲线点群中做离散对数运算。SM2 使用的是 素数域 GF(p) 上的 Weierstrass 方程:

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

SM2 标准推荐了一条 256 位的曲线,参数如下:

参数 值(十六进制) 说明
p FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFF 素数模数,256 位
a FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFC 曲线系数 a
b 28E9FA9E 9D9F5E34 4D5A9E4B CF6509A7 F39789F5 15AB8F92 DDBCBD41 4D940E93 曲线系数 b
Gx 32C4AE2C 1F198119 5F990446 6A39C994 8FE30BBF F2660BE1 715A4589 334C74C7 基点 G 的 x 坐标
Gy BC3736A2 F4F6779C 59BDCEE3 6B692153 D0A9877C C62A4740 02DF32E5 2139F0A0 基点 G 的 y 坐标
n FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF 7203DF6B 21C6052B 53BBF409 39D54123 基点 G 的阶(素数)

个人经验:我在项目中遇到过有人把 p 和 n 搞混,导致密钥生成一直报错。记住:p 是域模数,n 是点群的阶。两者都是 256 位,但数值不同。调试时建议先打印这两个值确认。

SM2 的密钥对生成很简单:

  • 私钥 d:随机选取 [1, n-2] 之间的整数
  • 公钥 P:P = d * G(椭圆曲线标量乘法)

嗯,这里要注意:SM2 的公钥是 未压缩格式,包含 x 和 y 坐标各 32 字节,共 64 字节。相比某些国际标准支持压缩格式,SM2 在存储上会多 32 字节。这个差异在嵌入式场景下影响不小,后面优化章节我们会专门讲。

下面这张图展示了 SM2 椭圆曲线密码体系的核心流程:

SM2 椭圆曲线密码体系核心流程 密钥生成 随机数 d ∈ [1, n-2] P = d * G(标量乘) 输出:私钥 d + 公钥 P 数字签名 ZA = H(ENTLA || IDA || a || b || G || P) e = H(ZA || M) 生成随机数 k,计算 (x1, y1) = k*G r = (e + x1) mod n, s = ((1+d)⁻¹ * (k - r*d)) mod n 输出签名 (r, s) 公钥加密 生成随机数 k,计算 C1 = k*G 点 (x2, y2) = k * P KDF 派生密钥,加密明文 输出密文 C = C1 || C2 || C3 说明:SM2 签名和加密都依赖椭圆曲线标量乘法(k*G 或 k*P),这是性能优化的核心瓶颈点 后续章节将重点围绕标量乘、模运算、KDF 等环节展开优化

1.3 SM2 与 ECDSA / Ed25519 的对比

很多同学会问:SM2 跟 ECDSA 到底有什么区别?跟现在很火的 Ed25519 比又怎么样?

我直接说结论:SM2 在签名算法结构上跟 ECDSA 有本质差异,在曲线选择上跟 Ed25519 走的是完全不同的路线。

先看签名算法的对比:

对比项 SM2 ECDSA Ed25519
曲线形式 Weierstrass y² = x³ + ax + b Weierstrass(NIST P-256 等) Edwards x² + y² = 1 + dx²y²
签名方程 s = (1+d)⁻¹ · (k - r·d) mod n s = k⁻¹ · (e + r·d) mod n 基于 Schnorr 变体
哈希使用 先算 ZA(用户标识+曲线参数),再算 e = H(ZA || M) 直接 e = H(M) H(R || P || M)
签名长度 64 字节(r, s 各 32) 64 字节(r, s 各 32) 64 字节
公钥长度 64 字节(未压缩) 32 或 64 字节 32 字节
抗量子性 弱(同 ECC 体系) 弱 弱

避坑指南:我曾经在对接某银行系统时,对方把 SM2 签名当 ECDSA 处理,直接用 ECDSA 验签流程去验 SM2 签名,结果当然验不过。SM2 的签名方程里有个 (1+d)⁻¹ 的逆元计算,ECDSA 没有。这个差异导致验签算法完全不同,千万别想当然。

再说性能对比。Ed25519 在签名和验签速度上通常比 SM2 快 2-3 倍,原因在于:

  • Edwards 曲线的点加公式更简单,不需要求逆元
  • Ed25519 的标量乘实现可以充分利用固定基点预计算
  • SM2 的 Weierstrass 曲线在通用实现中需要更多的模逆运算

但 SM2 也有自己的优势:

  • 标准成熟:国密标准对密钥生成、签名、加密、密钥交换都有完整定义,生态完善
  • 合规性:国内商用密码应用必须使用国密算法,这是硬性要求
  • 参数可控:曲线参数由国密局指定,不存在「信任第三方曲线」的问题

我的建议:如果你的项目只在国内跑,且涉及合规审查,直接上 SM2 没得选。如果是海外项目或对性能极度敏感(比如高频交易),Ed25519 是更好的选择。但话说回来,SM2 经过优化后,在主流 CPU 上签名速度也能达到每秒数万次,绝大多数场景够用了。

最后提一句,SM2 的密钥交换协议(类似 ECDH)在实现上比 ECDSA 复杂一些,因为它需要双方交互两次,并且要验证对方公钥的合法性。这部分我们在后面「密钥交换优化」章节会详细展开。