原创代码:https://github.com/ZZMarquis/gm
引用时,请导入原创代码库。本文仅以注释方式详解代码逻辑,供学习研究使用。
对原创代码的修改内容
- 修改了部分常量、变量、结构体属性的名称, 以便与GO语言标准包规范相统一
- 加入中文注释,解释代码逻辑
注释者及联系邮箱
Paul Lee
paul_lee0919@163.com
const (
// BitSize 代表曲线基础域的比特长度
BitSize = 256
// KeyBytes 代表秘钥的字节长度,其中加7整除8其实是“向上取整”,用以兼容基础域位数不是8的整数倍的情况。
KeyBytes = (BitSize + 7) / 8
// UnCompress 代表椭圆曲线上的点采用“未压缩”的形式存储,占1个字节,详见国标1-4.1.(b)的定义。
UnCompress = 0x04
)
以上为SM2算法定义的三个常数:
- BitSize 代表曲线基础域的比特长度
- KeyBytes 代表秘钥的字节长度,其中加7整除8其实是“向上取整”,用以兼容基础域位数不是8的整数倍的情况
- UnCompress 代表椭圆曲线上的点采用“未压缩”的形式存储,占1个字节,详见国标1-4.1.(b)的定义
// CipherTextType 是为了区分两个版本SM2国标在密文形式上的区别而创设的枚举类
type CipherTextType int32
const (
//C1C2C3 代表旧标准[GM/T 0009-2012]的密文顺序
C1C2C3 CipherTextType = 1
//C1C3C2 代表新标准[GB/T 32918-2016]的密文顺序
C1C3C2 CipherTextType = 2
)
CipherTextType是为了区分新旧两个版本的国标规范而设置的密文顺序标识枚举类,其中:
- C1C2C3 代表旧标准[GM/T 0009-2012]的密文顺序
- C1C3C2 代表新标准[GB/T 32918-2016]的密文顺序
var (
// sm2H 代表SM2推荐曲线的余因子h=1
// 椭圆曲线方程符合 y^2 = x^3 - 3x + b (mod p)
sm2H = new(big.Int).SetInt64(1)
// sm2SignDefaultUserID 代表sm2算法默认的加密操作用户A的ID编码(详见国标5-A.1)和SM2使用规范(GB/T 35276-2017第10部分)
sm2SignDefaultUserID = []byte{
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}
)
以上为SM2算法定义的两个变量:
- sm2H 代表基域Fp上椭圆曲线E的余因子h
- 由于SM2推荐曲线的余因子h=1, 即#E(Fp) = n
// sm2P256V1 代表国密SM2推荐参数定义的椭圆曲线
var sm2P256V1 P256V1Curve
// P256V1Curve 代表国密SM2推荐参数定义的椭圆曲线:
// (1) 素数域256位椭圆曲线
// (2) 曲线方程为 Y^2 = X^3 + aX + b
// (3) 其他参数: p, a, b, n, Gx, Gy 详见国标SM2推荐曲线参数
// (4) 在GO语言标准库通用椭圆曲线参数类elliptic.CurveParams的基础上增加了参数a的属性
// (5) 由于SM2推荐曲线符合a=p-3, 所以上述曲线可简化为等价曲线 Y^2 = X^3 - 3X + b (mod p),
// 可直接适用GO语言elliptic标准库的一些公共方法。(没有完成严格的数学验证,请大牛指教)
type P256V1Curve struct {
*elliptic.CurveParams
A *big.Int
}
// init() 初始化国密SM2推荐参数计算得出的椭圆曲线。
func init() {
initSm2P256V1()
}
// initSm2P256V1 为初始化国密SM2推荐参数计算得出的椭圆曲线:
// (1) 基域F(p)为素数域
// (2) 一次元x的系数a=p-3, 所以曲线方程等价于 y^2 = x^3 - 3x^2 + b (mod p) (即符合FIPS186-3标准预设函数)
// (3) 余因子h=1
func initSm2P256V1() {
sm2P, _ := new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16)
sm2A, _ := new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16)
sm2B, _ := new(big.Int).SetString("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16)
sm2N, _ := new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16)
sm2Gx, _ := new(big.Int).SetString("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16)
sm2Gy, _ := new(big.Int).SetString("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16)
sm2P256V1.CurveParams = &elliptic.CurveParams{Name: "SM2-P-256-V1"}
sm2P256V1.P = sm2P
sm2P256V1.A = sm2A
sm2P256V1.B = sm2B
sm2P256V1.N = sm2N
sm2P256V1.Gx = sm2Gx
sm2P256V1.Gy = sm2Gy
sm2P256V1.BitSize = BitSize
}
// GetSm2P256V1 为获取国密SM2椭圆曲线定义的函数。
func GetSm2P256V1() P256V1Curve {
return sm2P256V1
}
P256V1Curve 代表国密SM2推荐参数定义的椭圆曲线:
- 素数域256位椭圆曲线
- 曲线方程为 Y2 = X3 + aX + b
- 其他参数: p, a, b, n, Gx, Gy 详见国标SM2推荐曲线参数
- 在GO语言标准库通用椭圆曲线参数类elliptic.CurveParams的基础上增加了参数a的属性
- 由于SM2推荐曲线符合a=p-3, 所以上述曲线可简化为等价曲线 Y^2 = X^3 - 3X + b (mod p)
- 可直接适用GO语言elliptic标准库的公共方法。(没有完成严谨的数学验证,请大牛指教)
(未完待续)