国密算法Go语言实现(详解)(十) ——SM2(椭圆曲线公钥密码算法)

国密算法Go语言实现(详解)(十) ——SM2(椭圆曲线公钥密码算法)原创代码:https://github.com/ZZMarquis/gm引用时,请导入原创代码库。本文仅以注释方式详解代码逻辑,供学习研究使用。对原创代码的修改内容修改了部分常量、变量、结构体属性的名称, 以便与GO语言标准包规范相统一加入中文注释,解释代码逻辑注释者及联系邮箱Paul Leepaul_lee0919@163.com国标(GMT 0003.3-2012, 以下简称“国标”) 规定的SM2算法秘钥
摘要由CSDN通过智能技术生成

国密算法Go语言实现(详解)(十) ——SM2(椭圆曲线公钥密码算法)


原创代码:https://github.com/ZZMarquis/gm

引用时,请导入原创代码库。本文仅以注释方式详解代码逻辑,供学习研究使用。

对原创代码的修改内容

  1. 修改了部分常量、变量、结构体属性的名称, 以便与GO语言标准包规范相统一
  2. 加入中文注释,解释代码逻辑

注释者及联系邮箱

Paul Lee
paul_lee0919@163.com

国标(GMT 0003.3-2012, 以下简称“国标”) 规定的SM2算法秘钥交换协议
/*
	国标(GMT 0003.3-2012, 以下简称“国标”) 规定的SM2算法秘钥交换协议
*/

// ExchangeResult 为国标规定的最后推导出的秘钥交换协议的结果:
// Key 为共享秘钥,比如SM4秘钥
// S1 为校验B用户身份的可选中间参数,其哈希函数输入参数的头部为0x02
// S2 为校验A用户身份的可选中间参数,其哈希函数输入参数的头部为0x03
type ExchangeResult struct {
   
	Key []byte
	S1  []byte
	S2  []byte
}

ExchangeResult 为国标规定的最后推导出的秘钥交换协议的结果, 其中:
(1) Key 为共享秘钥,比如SM4秘钥
(2) S1 为校验B用户(应答用户)身份的可选中间参数,其哈希函数输入参数的头部为0x02
(3) S2 为校验A用户(发起用户)身份的可选中间参数,其哈希函数输入参数的头部为0x03

// reduce 为国密算法中获取(x拔)的中间函数, 详见国标6.1的A4/A6和B3/B5,其中:
// 1. Lsh() 为左位移方法,将整数1左移w位,相当于获取2^w
// 2. SetBit(x, i, b) 为设定整数x第i位为b的函数,当b为1时,相当于x | (1<<i)
// 3. x拔在国标中的定义为: 2^w + (x & (2^w - 1)), 其中:
// (1) 2^w二进制表示为w位为1,后续其他位均为0,因此
// (2) 若A = 2^w - 1, 则计算结果A的第w位的值必定为0,因此
// (2) 若B = x & A, 则与运算结果B的第w位也必定为0, 因此
// (3) SetBit (reulst, w, 1) 相当于result + 2^w
// 综上,reduce的计算结果就是 (x拔) =  2^w + (x & (2^w - 1))
func reduce(x *big.Int, w int) *big.Int {
   
	intOne := new(big.Int).SetInt64(1)
	result := util.Lsh(intOne, uint(w))
	result = util.Sub(result, intOne)
	result = util.And(x, result)
	result = util.SetBit(result, w, 1)
	return result
}

reduce 为国密算法中获取(x拔)的中间函数, 详见国标6.1的A4/A6和B3/B5,其中:

  1. Lsh() 为左位移方法,将整数1左移w位,相当于获取2w
  2. SetBit(x, i, b) 为设定整数x第i位为b的函数,当b为1时,相当于x | (1<<i)
  3. x拔在国标中的定义为: 2w+ (x & (2w - 1)), 其中:
    // (1) 2w二进制表示为: w位为1, 后续其他位均为0,因此
    // (2) 若A = 2w - 1, 则计算结果A的第w位的值必定为0,因此
    // (2) 若B = x & A, 则与运算结果B的第w位也必定为0, 因此
    // (3) SetBit (reulst, w, 1) 相当于result + 2w
    // 综上,reduce的计算结果就是 (x拔) = 2w + (x & (2w - 1))
  4. 另外,分析w取值,其实为基点G阶数n二进制比特位数长度的一半,x & (2w - 1) 其实是按照n位数长度一半截取x的值,再加上2w, 相当于在w位加标签“1”
// calculateU 为推导共享秘钥(曲线上关键点U)的函数,其中:
// x1 为己方临时公钥点R1的x值所对应的x拔: x1 =  2^w + (x1 & (2^w - 1))
// x2 为对方临时公钥点R2的x值所对应的x拔: x2 = 2^w + (x2 & (2^w - 1))
// tA 为己方临时私钥r1乘x1加永久私钥d1,之后对基点阶数n取模所得的tA = (d1 + x1.r1) mod n
// sm2H 为SM2曲线余因子h, 应当为曲线点个数#E(Fq)除以基点G阶数n的商,对SM2推荐曲线而言,h=1
// 关键点U = h*tA*(P2 + x2*R2) = h*tA*P2 + h*tA*x2*R2 = k1*P2 + k2*R2
// 值得注意的是,取模计算被从tA计算,挪到了k1和k2步骤,从取模运算的乘法交换律来看,结果并没有影响,
// 但可以尽量让k2模运算后的结果更小,进而降低后续步骤的运算压力。
func calculateU(w int, selfStaticPriv *PrivateKey, selfEphemeralPriv *PrivateKey, selfEphemeralPub *PublicKey,
	otherStaticPub *PublicKey, otherEphemeralPub *PublicKey) (x *big.Int, y *big.Int) {
   
	x1 := reduce(selfEphemeralPub.X, w)
	x2 := reduce(otherEphemeralPub.<
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值