0
SM2性能优化
Sun Yimin edited this page 2023-12-29 08:21:18 +08:00
This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

后续实现和golang SDK同步纯golang实现通过fiat-crypto生成代码,具体请参考SM2性能优化

最近项目/产品有可能要用到国密商密的SM2加解密及签名验签看了标准文档参考了有关实现发现SM2/SM3本身并不复杂主要是SM2用到的椭圆曲线优化实现比较有难度。网上大部分Golang的SM2椭圆曲线优化实现其实大部分都是那个“神兽压阵”的基于Golang NIST P256纯Go语言实现版本并且比较难读。我想要自己实现一遍切实体会一下实现的难度。

通过阅读Golang NIST P256那个generic的源码并且比较NIST P256和SM2 256曲线参数的异同逐步尝试。

  • 首先我要替换掉p256.go中的所有常量这个过程中遇到的最大难点在于p256Zero31的求解。
  • 其次, 开始解决加法p256Sum和减法(p256Diff)的正确性其难点在于解决进位问题p256ReduceCarry
  • 然后就是解决乘法p256Mul的正确性其最大难点在于蒙哥马利约简实现p256ReduceDegree这个花费了很多时间也是和那个“神兽压阵”实现的最大不同。
  • 最后就是求模P的乘法逆元p256Invert基于费马小定理(Fermat's Little Theorem)这个就是用平方和乘法算出a^{p-2} = a^{-1} (mod p)关键是凑出p-2。

我保留了那些如何求取那些常量和预计算的函数在p256.go中而没有删除供后来者参考。期间也和ALI KMS作了集成测试主要是SM2本地加密ALI KMS解密; ALI KMS签名本地验签。

这个实现的性能据我测试在amd64下大概是elliptic.CurveParams默认实现性能的5倍。对于这个性能我还是不甚满意所以开始学习Golang中NIST P256的特定优化实现但是这里面有GO ASM我从来没有接触过。经过一段时间的学习开始跃跃欲试我只有amd64所以从amd64下手还是从替换曲线参数开始

  • 首先替换掉p256_asm.go和p256_asm_amd64.s中的常量这一步还是比较顺利毕竟有一定经验了。
  • 接着就是要修改p256_asm_amd64.s中的实现了主要是蒙哥马利约简模P的和模N的实现原本的实现都是基于NIST P256的参数P和N进行优化的改造起来困难挺大为了验证结果对每个主要的asm实现方法都写了测试保证正确性。本以为有了32位generic实现的改造经验会比较顺利实际情况是在这一步反反复复几度曾想放弃。说老实话到目前为止我也还是不能认清p256_asm_amd64.s中用到的所有Golang ASM的命令。
  • p256_asm.go中p256Inverse的改造因为有经验比较顺利。
  • 然后测试两个多倍点算法ScalarMult/ScalarBaseMult的正确性通过和elliptic.CurveParams默认实现结果比较来鉴定。到此sm2的加解密已经可以验证了
  • 最后,修改实现(curve p256Curve) Inverse(k *big.Int) *big.Int,这个是第一次改造,费了点功夫,通过学习算法算是比较顺利。这个方法以及CombinedMult方法在签名和验签中有用能提高性能。
  • 持续优化蒙哥马利约简主要是根据P这个素数的特性T3=T+(T mod 2^64)*PT = T3 / 2^64,努力减少乘法。

这个实现的性能据我测试在amd64下加解密大概是elliptic.CurveParams默认实现性能的50大概是那个纯golang 32位实现的性能的10倍。签名和验签我没做性能测试不过应该也有很大提高。这个性能已经和SM2基于NIST P256曲线实现的性能相当接近了考虑到SM2 256曲线的参数复杂度这个性能算是不错的了。

最后向Golang中NIST P256的实现者致敬

参考

Elliptic Curve Cryptography: a gentle introduction

Elliptic curves and their implementation (04 Dec 2010)

Fast prime field elliptic-curve cryptography with 256-bit primes

P-256 (secp256r1) Scalar Inversion