先从gmssl库CryptSM2类里抄一段椭圆曲线点加、点乘的运算函数
class CryptSM2(object):
def __init__(self, private_key, public_key, ecc_table):
self.private_key = private_key
self.public_key = public_key
self.para_len = len(ecc_table['n'])
self.ecc_a3 = (
int(ecc_table['a'], base=16) + 3) % int(ecc_table['p'], base=16)
self.ecc_table = ecc_table
def _kg(self, k, Point): # kP运算
Point = '%s%s' % (Point, '1')
mask_str = '8'
for i in range(self.para_len - 1):
mask_str += '0'
mask = int(mask_str, 16)
Temp = Point
flag = False
for n in range(self.para_len * 4):
if (flag):
Temp = self._double_point(Temp)
if (k & mask) != 0:
if (flag):
Temp = self._add_point(Temp, Point)
else:
flag = True
Temp = Point
k = k << 1
return self._convert_jacb_to_nor(Temp)
def _double_point(self, Point): # 倍点
l = len(Point)
len_2 = 2 * self.para_len
if l < self.para_len * 2:
return None
else:
x1 = int(Point[0:self.para_len], 16)
y1 = int(Point[self.para_len:len_2], 16)
if l == len_2:
z1 = 1
else:
z1 = int(Point[len_2:], 16)
T6 = (z1 * z1) % int(self.ecc_table['p'], base=16)
T2 = (y1 * y1) % int(self.ecc_table['p'], base=16)
T3 = (x1 + T6) % int(self.ecc_table['p'], base=16)
T4 = (x1 - T6) % int(self.ecc_table['p'], base=16)
T1 = (T3 * T4) % int(self.ecc_table['p'], base=16)
T3 = (y1 * z1) % int(self.ecc_table['p'], base=16)
T4 = (T2 * 8) % int(self.ecc_table['p'], base=16)
T5 = (x1 * T4) % int(self.ecc_table['p'], base=16)
T1 = (T1 * 3) % int(self.ecc_table['p'], base=16)
T6 = (T6 * T6) % int(self.ecc_table['p'], base=16)
T6 = (self.ecc_a3 * T6) % int(self.ecc_table['p'], base=16)
T1 = (T1 + T6) % int(self.ecc_table['p'], base=16)
z3 = (T3 + T3) % int(self.ecc_table['p'], base=16)
T3 = (T1 * T1) % int(self.ecc_table['p'], base=16)
T2 = (T2 * T4) % int(self.ecc_table['p'], base=16)
x3 = (T3 - T5) % int(self.ecc_table['p'], base=16)
if (T5 % 2) == 1:
T4 = (T5 + ((T5 + int(self.ecc_table['p'], base=16)) >> 1) - T3) % int(self.ecc_table['p'], base=16)
else:
T4 = (T5 + (T5 >> 1) - T3) % int(self.ecc_table['p'], base=16)
T1 = (T1 * T4) % int(self.ecc_table['p'], base=16)
y3 = (T1 - T2) % int(self.ecc_table['p'], base=16)
form = '%%0%dx' % self.para_len
form = form * 3
return form % (x3, y3, z3)
def _add_point(self, P1, P2): # 点加函数,P2点为仿射坐标即z=1,P1为Jacobian加重射影坐标
len_2 = 2 * self.para_len
l1 = len(P1)
l2 = len(P2)
if (l1 < len_2) or (l2 < len_2):
return None
else:
X1 = int(P1[0:self.para_len], 16)
Y1 = int(P1[self.para_len:len_2], 16)
if (l1 == len_2):
Z1 = 1
else:
Z1 = int(P1[len_2:], 16)
x2 = int(P2[0:self.para_len], 16)
y2 = int(P2[self.para_len:len_2], 16)
T1 = (Z1 * Z1) % int(self.ecc_table['p'], base=16)
T2 = (y2 * Z1) % int(self.ecc_table['p'], base=16)
T3 = (x2 * T1) % int(self.ecc_table['p'], base=16)
T1 = (T1 * T2) % int(self.ecc_table['p'], base=16)
T2 = (T3 - X1) % int(self.ecc_table['p'], base=16)
T3 = (T3 + X1) % int(self.ecc_table['p'], base=16)
T4 = (T2 * T2) % int(self.ecc_table['p'], base=16)
T1 = (T1 - Y1) % int(self.ecc_table['p'], base=16)
Z3 = (Z1 * T2) % int(self.ecc_table['p'], base=16)
T2 = (T2 * T4) % int(self.ecc_table['p'], base=16)
T3 = (T3 * T4) % int(self.ecc_table['p'], base=16)
T5 = (T1 * T1) % int(self.ecc_table['p'], base=16)
T4 = (X1 * T4) % int(self.ecc_table['p'], base=16)
X3 = (T5 - T3) % int(self.ecc_table['p'], base=16)
T2 = (Y1 * T2) % int(self.ecc_table['p'], base=16)
T3 = (T4 - X3) % int(self.ecc_table['p'], base=16)
T1 = (T1 * T3) % int(self.ecc_table['p'], base=16)
Y3 = (T1 - T2) % int(self.ecc_table['p'], base=16)
form = '%%0%dx' % self.para_len
form = form * 3
return form % (X3, Y3, Z3)
def _convert_jacb_to_nor(self, Point): # Jacobian加重射影坐标转换成仿射坐标
len_2 = 2 * self.para_len
x = int(Point[0:self.para_len], 16)
y = int(Point[self.para_len:len_2], 16)
z = int(Point[len_2:], 16)
z_inv = pow(z, int(self.ecc_table['p'], base=16) - 2, int(self.ecc_table['p'], base=16))
z_invSquar = (z_inv * z_inv) % int(self.ecc_table['p'], base=16)
z_invQube = (z_invSquar * z_inv) % int(self.ecc_table['p'], base=16)
x_new = (x * z_invSquar) % int(self.ecc_table['p'], base=16)
y_new = (y * z_invQube) % int(self.ecc_table['p'], base=16)
z_new = (z * z_inv) % int(self.ecc_table['p'], base=16)
if z_new == 1:
form = '%%0%dx' % self.para_len
form = form * 2
return form % (x_new, y_new)
else:
return None
def verify(self, Sign, data):
# 验签函数,sign签名r||s,E消息hash,public_key公钥
r = int(Sign[0:self.para_len], 16)
s = int(Sign[self.para_len:2 * self.para_len], 16)
e = int(data.hex(), 16)
t = (r + s) % int(self.ecc_table['n'], base=16)
if t == 0:
return 0
P1 = self._kg(s, self.ecc_table['g'])
P2 = self._kg(t, self.public_key)
# print(P1)
# print(P2)
if P1 == P2:
P1 = '%s%s' % (P1, 1)
P1 = self._double_point(P1)
else:
P1 = '%s%s' % (P1, 1)
P1 = self._add_point(P1, P2)
P1 = self._convert_jacb_to_nor(P1)
x = int(P1[0:self.para_len], 16)
return (r == ((e + x) % int(self.ecc_table['n'], base=16)))
def sign(self, data, K): # 签名函数, data消息的hash,private_key私钥,K随机数,均为16进制字符串
E = data.hex() # 消息转化为16进制字符串
e = int(E, 16)
d = int(self.private_key, 16)
k = int(K, 16)
P1 = self._kg(k, self.ecc_table['g'])
x = int(P1[0:self.para_len], 16)
R = ((e + x) % int(self.ecc_table['n'], base=16))
if R == 0 or R + k == int(self.ecc_table['n'], base=16):
return None
d_1 = pow(d + 1, int(self.ecc_table['n'], base=16) - 2, int(self.ecc_table['n'], base=16))
S = (d_1 * (k + R) - R) % int(self.ecc_table['n'], base=16)
if S == 0:
return None
else:
return '%064x%064x' % (R, S)
然后直接调用即可,椭圆曲线参数可以改
# -*- coding: utf-8 -*-
import binascii
from gmssl.sm2 import default_ecc_table
import Sm2Calc
def main():
default_ecc_table = {
'n': 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123',
'p': '8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3',
'g': '421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2',
'a': '787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498',
# 'b': '28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93',
}
while 1:
print("======================= SM2倍点试做 ========================")
print("操作:\n==== 1.倍点运算\n==== 2.点加\n 选择:", end='')
calc_Point = Sm2Calc.CryptSM2(private_key=None, public_key=None, ecc_table=default_ecc_table)
chose = input()
if chose == "1":
print("输入初始点:", end='')
point_in = input()
diy_len = point_in
print("输入点的倍数:", end='')
k = int(input())
bei_Point = calc_Point._kg(k, point_in)
print("点乘结果是:", bei_Point)
elif chose == "2":
print("输入点1:", end='')
point_1n = input()
point_1stn = '%s%s' % (point_1n, 1)
print("输入点2:", end='')
point_2n = input()
add_Jacobian = calc_Point._add_point(point_1stn, point_2n)
add_Point = calc_Point._convert_jacb_to_nor(add_Jacobian)
# print("ss:", point_1stn)
print("点加结果是:", add_Point)
if __name__ == '__main__':
main()
椭圆曲线改成下面一组测试参数后,测试成功。
0x421DEBD6 1B62EAB6 746434EB C3CC315E 32220B3B ADD50BDC 4C4E6C14 7FEDD43D // Gx
0x0680512B CBB42C07 D47349D2 153B70C4 E5D7FDFC BFA36EA1 A85841B9 E46E09A2 // Gy
0x8542D69E 4C044F18 E8B92435 BF6FF7DE 45728391 5C45517D 722EDB8B 08F1DFC3 // p
0x787968B4 FA32C3FD 2417842E 73BBFEFF 2F3C848B 6831D7E0 EC65228B 3937E498 // a
测试点用的是G!!!
k = 0x0000000000000000000000000000000000000000000000000000000000000001
Qx = 0x421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D
Qy = 0x0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2
k = 0x0000000000000000000000000000000000000000000000000000000000000002
Qx = 0x5E1E24ACC7FB884895BB954DE21FE26456357D9EE8A32410635F35CDFB0D2846
Qy = 0x8314D639881A8BAF1BDD076BF82B090020D80F7A5ACC3C56BDB61BBD305708F4
k = 0x0000000000000000000000000000000000000000000000000000000000000003
Qx = 0x126FE19E98F4548A976C436D97B8C8A8F14405FF9A6D58B556355D70C2C19E69
Qy = 0x4BD3A18E69CC107212729F6473030132DE0B75BF7482CA5510B532EF7BDDCB93
k = 0x0000000000000000000000000000000000000000000000000000000000000004
Qx = 0x7579488E…45FE9DFD
Qy = 0x53233A1C…E06D6ED4
k = 0x0000000000000000000000000000000000000000000000000000000000000005
Qx = 0x69FB7B95…BFB03FDB
Qy = 0x4B38C759…191BAB3B
k = 0x0000000000000000000000000000000000000000000000000000000000000006
Qx = 0x832CD887…F5BF7A50
Qy = 0x19785C14…1808C891
k = 0x0000000000000000000000000000000000000000000000000000000000000007
Qx = 0x446F914C…284B2D18
Qy = 0x777E0C31…414F65F9
k = 0x0000000000000000000000000000000000000000000000000000000000000008
Qx = 0x2C79ACF6…8155E905
Qy = 0x650F9BB6…B0CE5307
k = 0x000000000000000000000000000000000000000000000000000000000000FFFF
Qx = 0x5FD0FD63…85E1CE60
Qy = 0x82FA4AAD…AC203D1B
k = 0x00000000000000000000000000000000000000000000000000000000FF00FFFF
Qx = 0x45C843E6…E47E234F
Qy = 0x230A83AF…36EC861C