椭圆曲线算法和国密SM2算法介绍

1.基础知识

1.1 群

定义

群是集合G和G上的二元运算 ∘ \circ ,简记为 ( G , ∘ ) (G,\circ) (G,)。集合 G = { x ∣ x ∈ G } G=\{x|x\in G\} G={xxG} G G G上的二元运算 ∘ \circ 满足如下性质:
1.封闭性:对 ∀ a , b ∈ G \forall a,b \in G a,bG,有 a ∘ b ∈ G a\circ b \in G abG
2.结合性:对 ∀ a , b , c ∈ G \forall a,b,c \in G a,b,cG,有 a ∘ b ∘ c = a ∘ ( b ∘ c ) a\circ b\circ c=a\circ (b\circ c) abc=a(bc)
3.单位元:存在单位元 1 1 1,使得 a ∘ 1 = 1 ∘ a = a a\circ 1=1\circ a=a a1=1a=a
4.有逆元:对 ∀ a ∈ G \forall a \in G aG ∃ a − 1 ∈ G \exists a^{-1} \in G a1G,使得 a − 1 ∘ a = a ∘ a − 1 = 1 a^{-1}\circ a=a\circ a^{-1} =1 a1a=aa1=1
若对 ∀ a , b ∈ G \forall a,b \in G a,bG,有 a ∘ b = b ∘ a a\circ b=b\circ a ab=ba,则称群 G G G为阿贝尔群(可交换群)。

例子

1. Z n = { 0 , 1 , 2 , ⋯   , n − 1 } Z_n=\{0,1,2,\cdots,n-1\} Zn={0,1,2,,n1} ∘ = +   m o d   n \circ=+\ mod \ n =+ mod n。单位元为 0 0 0
2. Z n ∗ = { a i ∣ a i ∈ { 0 , 1 , 2 , ⋯   , n − 1 }   a n d   g c d ( a i , n ) = 1 } Z_n^*=\{a_i|a_i \in\{0,1,2,\cdots,n-1\}\ and \ gcd(a_i,n)=1\} Zn={aiai{0,1,2,,n1} and gcd(ai,n)=1} ∘ = ×   m o d   n \circ=\times\ mod \ n =× mod n。单位元为 1 1 1。若n为素数,则 Z n ∗ = { 1 , 2 , ⋯   , n − 1 } Z_n^*=\{1,2,\cdots,n-1\} Zn={1,2,,n1}。证明:根据定义推导,显然。
3. ( R , + ) (R,+) (R,+)是群,单位元是0。
4. ( R 去 除 0 , × ) (R去除0,\times) (R0,×)是群,单位元是1。

1.2 有限群

有限群和群的阶

( G , ∘ ) (G,\circ) (G,)是有限的,若它有有限个元素。我们称群的元素数目为群的阶,记为 ∣ G ∣ |G| G

元素的阶

( G , ∘ ) (G,\circ) (G,)中元素 α \alpha α的阶为满足 α k = 1 , α k = α ∘ α ∘ ⋯ ∘ α ⏟ k \alpha^k=1,\alpha^k=\underbrace{\alpha \circ \alpha \circ \cdots \circ \alpha}_k αk=1αk=k ααα的最小正整数 k k k,记为 o r d ( α ) ord(\alpha) ord(α)

有限循环群和生成元

有限群 ( G , ∘ ) (G,\circ) (G,),若存在一个元素 α \alpha α,其阶为 ∣ G ∣ |G| G,则称此有限群为循环群,其中阶为 ∣ G ∣ |G| G的元素称为生成元。

1.3 有用的结论

Lagrange’s 定理

G G G是有限群,若 H H H G G G的子群,则 ∣ H ∣ 整 除 ∣ G ∣ |H|整除|G| HG

定理1

( G , ∘ ) (G,\circ) (G,)是一个有限群,则对于 ∀ α ∈ G \forall \alpha \in G αG,存在 s ≤ ∣ G ∣ s\le |G| sG,使得 ( α 1 , α 2 , ⋯   , α s ) (\alpha ^1,\alpha^2,\cdots,\alpha^s) (α1,α2,,αs)是一个有限循环群,记为 < α > <\alpha> <α>,其中 α \alpha α为此子群的生成元, o r d ( a ) = s ord(a)=s ord(a)=s

定理2

( G , ∘ ) (G,\circ) (G,)是一个有限群,则1.对 ∀ α ∈ G \forall \alpha \in G αG,有 α ∣ G ∣ = 1 \alpha^{|G|}=1 αG=1;2.对 ∀ α ∈ G \forall \alpha \in G αG o r d ( α ) ord(\alpha) ord(α)整除 ∣ G ∣ |G| G
证明:由Lagrange’s 定理即可得到。

推论1

( G , ∘ ) (G,\circ) (G,)是一个有限群,若其阶为素数,则 ( G , ∘ ) (G,\circ) (G,)是一个有限循环群。
证明:若其阶为素数,则除去单位元的其他元素,其阶都为|G|。

推论2

( G , ∘ ) (G,\circ) (G,)是一个有限循环群群,则1.生成元的数目为 Φ ( ∣ G ∣ ) \Phi(|G|) Φ(G);2.若 ∣ G ∣ |G| G是素数,则除单位元外, G G G中所有元素都是生成元。

结论

若p是素数,则 Z p ∗ = { 1 , 2 , ⋯   , p − 1 } Z_p^*=\{1,2,\cdots,p-1\} Zp={1,2,,p1} ∘ = ×   m o d   p \circ=\times\ mod \ p =× mod p。结论是 Z p ∗ Z_p^* Zp是有限循环群,显然也是可交换群。(此结论如何证明,未知)

2 离散对数问题

2.1 一般性定义

给定一个有限循环群 ( G , ∘ ) (G,\circ) (G,),阶 ∣ G ∣ |G| G= n n n,假设 α \alpha α是G的生成元,则离散对数问题描述为:给定 β ∈ G \beta \in G βG,求 x x x使得 α x = β \alpha ^x = \beta αx=β,其中 1 ≤ x ≤ n 1 \le x \le n 1xn

2.2 Z n Z_n Zn上的定义

Z n = { 0 , 1 , 2 , ⋯   , n − 1 } Z_n=\{0,1,2,\cdots,n-1\} Zn={0,1,2,,n1} ∘ = +   m o d   n \circ=+\ mod \ n =+ mod n。则其阶为 n n n,则生成元的数目为 Φ ( n ) \Phi(n) Φ(n),其生成元为与 n n n互质的数。其离散对数问题描述如下:假设 α \alpha α Z n Z_n Zn的生成元,给定 β ∈ G \beta \in G βG,求 x x x使得 α x = β \alpha ^x = \beta αx=β,这里 α x = α + α + ⋯ + α ⏟ x   m o d   n = x ⋅ α   m o d   n \alpha ^x=\underbrace{\alpha + \alpha + \cdots + \alpha }_x \ mod \ n=x \cdot \alpha \ mod \ n αx=x α+α++α mod n=xα mod n,所以 α x = β \alpha ^x = \beta αx=β表达为 x ⋅ α ≡ β   m o d   n x \cdot \alpha \equiv \beta \ mod \ n xαβ mod n,其中 1 ≤ x ≤ n 1 \le x \le n 1xn。在这里唯一需要说明的在 Z n Z_n Zn上计算离散对数问题是简单的:这里 x = α − 1 ⋅ β x=\alpha^{-1}\cdot \beta x=α1β,其中 α − 1 ⋅ α ≡ 1   m o d   n \alpha^{-1} \cdot \alpha \equiv 1 \ mod \ n α1α1 mod n

2.3 Z p ∗ Z_p^* Zp上的定义

p p p是素数, Z p ∗ = { 1 , 2 , ⋯   , p − 1 } Z_p^*=\{1,2,\cdots,p-1\} Zp={1,2,,p1} ∘ = ×   m o d   p \circ=\times\ mod \ p =× mod p,则其阶为 p − 1 p-1 p1。其离散对数问题描述如下:假设 α \alpha α Z p ∗ Z_p^* Zp的生成元,给定 β ∈ G \beta \in G βG,求 x x x使得 α x = β \alpha ^x = \beta αx=β,将 ∘ = ×   m o d   p \circ=\times\ mod \ p =× mod p代入得到 α x ≡ β   m o d   p \alpha ^x \equiv \beta \ mod \ p αxβ mod p,其中 1 ≤ x ≤ ( p − 1 ) 1 \le x \le (p-1) 1x(p1)。在这里唯一需要说明的在 Z p ∗ Z_p^* Zp上计算离散对数问题是困难的。

2.4 基于离散对数问题的密钥交换协议(Diffie-Hellman)

基于有限循环群 Z p ∗ Z_p^* Zp的DH算法

1.初始化: Z p ∗ Z_p^* Zp的参数,通常称为域参数

选择一个大素数 p p p
选择一个整数 α ∈ { 2 , 3 , ⋯   , p − 1 } \alpha \in \{2,3,\cdots,p-1\} α{2,3,,p1},其中 α \alpha α为生成元。
发布域参数: p p p α \alpha α

2.密钥交换

Alice:随机选择一个 a ∈ { 2 , 3 , ⋯   , p − 1 } a \in \{2,3,\cdots,p-1\} a{2,3,,p1},计算 A = α a   m o d   p A = \alpha^a \ mod \ p A=αa mod p,将 A A A通过公共网路传送给Bob。
Bob:随机选择一个 b ∈ { 2 , 3 , ⋯   , p − 1 } b \in \{2,3,\cdots,p-1\} b{2,3,,p1},计算 B = α b   m o d   p B = \alpha^b \ mod \ p B=αb mod p,将 B B B通过公共网路传送给Alice。

3.密钥计算

Alice: K a b = B a = α a b   m o d   p K_{ab}=B^a=\alpha^{ab} \ mod \ p Kab=Ba=αab mod p
Bob: K a b = A b = α a b   m o d   p K_{ab}=A^b=\alpha^{ab} \ mod \ p Kab=Ab=αab mod p

此算法目的用于在不安全的公共网络上双方协商密钥。关键点在于通过 A = α a   m o d   p A = \alpha^a \ mod \ p A=αa mod p,很难计算 a a a;同理通过 B = α b   m o d   p B = \alpha^b \ mod \ p B=αb mod p,很难计算 b b b。这里利用了 Z p ∗ Z_p^* Zp上的离散对数问题在计算上是困难的。

基于有限循环群 ( G , ∘ ) (G,\circ) (G,) 的DH算法的一般定义

1.初始化:

随机选择一个元素 α ∈ G \alpha \in G αG α \alpha α为生成元。
发布 ( G , ∘ ) (G,\circ) (G,)、生成元 α \alpha α和阶 ∣ G ∣ |G| G

2.密钥交换

Alice:随机选择一个 a ∈ { 2 , 3 , ⋯   , ∣ G ∣ } a \in \{2,3,\cdots,|G|\} a{2,3,,G},计算 A = α a A = \alpha^a A=αa,将 A A A通过公共网路传送给Bob。
Bob:随机选择一个 b ∈ { 2 , 3 , ⋯   , ∣ G ∣ } b \in \{2,3,\cdots,|G|\} b{2,3,,G},计算 B = α b B = \alpha^b B=αb,将 B B B通过公共网路传送给Alice。

3.密钥计算

Alice: K a b = B a = α a b K_{ab}=B^a=\alpha^{ab} Kab=Ba=αab
Bob: K a b = A b = α a b K_{ab}=A^b=\alpha^{ab} Kab=Ab=αab

安全性要求: ( G , ∘ ) (G,\circ) (G,)上的离散对数问题要计算困难。比如 Z n = { 0 , 1 , 2 , ⋯   , n − 1 } Z_n=\{0,1,2,\cdots,n-1\} Zn={0,1,2,,n1} ∘ = +   m o d   n \circ=+\ mod \ n =+ mod n就不行。

3 素数域 Z p Z_p Zp上的椭圆曲线上的离散对数问题

3.1 椭圆曲线的定义

椭圆曲线的定义:椭圆曲线是点的集合,哪些点呢?
1.在素数域 Z p Z_p Zp上(p是素数),所有点 ( x , y ) ∈ Z p (x,y) \in Z_p (x,y)Zp
满足:
y 2 ≡ x 3 + a ⋅ x + b   m o d   p y^2 \equiv x^3 + a \cdot x + b \ mod \ p y2x3+ax+b mod p
其中 a , b ∈ Z p a,b \in Z_p a,bZp 4 ⋅ a 3 + 27 ⋅ b 2 ≠ 0   m o d   p 4 \cdot a^3+27 \cdot b^2 \ne 0 \ mod \ p 4a3+27b2=0 mod p
2.另外加上一个无穷远点 ϑ \vartheta ϑ

E l l i p t i c   c u r v e = { ( x , y ) ∣ y 2 ≡ x 3 + a ⋅ x + b   m o d   p } ⋃ { ϑ } Elliptic \ curve=\{(x,y)|y^2 \equiv x^3 + a \cdot x + b \ mod \ p\} \bigcup \{\vartheta\} Elliptic curve={(x,y)y2x3+ax+b mod p}{ϑ},其中 a , b ∈ Z p a,b \in Z_p a,bZp 4 ⋅ a 3 + 27 ⋅ b 2 ≠ 0   m o d   p 4 \cdot a^3+27 \cdot b^2 \ne 0 \ mod \ p 4a3+27b2=0 mod p

注意:素数域 Z p = { 0 , 1 , 2 , ⋯   , p − 1 } Z_p=\{0,1,2,\cdots ,p-1\} Zp={0,1,2,,p1}的意思是:在$+ \mod p $下构成单位元为 0 0 0的群,去除 0 0 0元素在 ×   m o d   p \times \ mod \ p × mod p下构成单位元为 1 1 1的群。

3.2 椭圆曲线上的二元运算 ∘ \circ 的定义

二元运算 ∘ \circ 的定义

E l l i p t i c   c u r v e = { ( x , y ) ∣ y 2 ≡ x 3 + a ⋅ x + b   m o d   p } ⋃ { ϑ } Elliptic \ curve=\{(x,y)|y^2 \equiv x^3 + a \cdot x + b \ mod \ p\} \bigcup \{\vartheta\} Elliptic curve={(x,y)y2x3+ax+b mod p}{ϑ},其中 a , b ∈ Z p a,b \in Z_p a,bZp 4 ⋅ a 3 + 27 ⋅ b 2 ≠ 0   m o d   p 4 \cdot a^3+27 \cdot b^2 \ne 0 \ mod \ p 4a3+27b2=0 mod p

椭圆曲线上的 ∘ \circ 的定义

∀ P = ( x 1 , y 1 ) , Q = ( x 2 , y 2 ) ∈ E l l i p t i c   c u r v e \forall P=(x_1,y_1),Q=(x_2,y_2)\in Elliptic \ curve P=(x1,y1),Q=(x2,y2)Elliptic curve ( x 3 , y 3 ) = P ∘ Q (x_3,y_3)=P \circ Q (x3,y3)=PQ定义如下:
x 3 = s 2 − x 1 − x 2   m o d   p x_3=s^2 -x_1-x_2 \ mod \ p x3=s2x1x2 mod p
y 3 = s ⋅ ( x 1 − x 3 ) − y 1 m o d    p y_3=s\cdot (x_1-x_3) -y_1 \mod p y3=s(x1x3)y1modp
其中
s = y 2 − y 1 x 2 − x 1   m o d   p , 如 果 P ≠ Q s=\frac{y_2- y_1}{x_2 - x_1} \ mod \ p,如果P\ne Q s=x2x1y2y1 mod pP=Q
s = 3 ⋅ x 1 2 + a 2 ⋅ y 1   m o d   p , 如 果 P = Q s=\frac{3\cdot x_1^2 +a}{2\cdot y_1} \ mod \ p,如果P=Q s=2y13x12+a mod pP=Q

另外其他一些定义:
1. ϑ \vartheta ϑ为单位元,即对 ∀ P ∈ E l l i p t i c   c u r v e \forall P\in Elliptic \ curve PElliptic curve P ∘ ϑ = P P\circ \vartheta=P Pϑ=P
2.对 ∀ P = ( x 1 , y 1 ) ∈ E l l i p t i c   c u r v e \forall P=(x_1,y_1) \in Elliptic \ curve P=(x1,y1)Elliptic curve P − 1 = ( x 1 , p − y 1   m o d   p ) P^{-1}=(x_1,p-y_1 \ mod \ p) P1=(x1,py1 mod p),所以理论上 ∀ P = ( x 1 , y 1 ) , Q = ( x 2 , y 2 ) ∈ E l l i p t i c   c u r v e \forall P=(x_1,y_1),Q=(x_2,y_2)\in Elliptic \ curve P=(x1,y1),Q=(x2,y2)Elliptic curve,若 x 1 = x 2 x_1=x_2 x1=x2,则 P ∘ Q = ϑ P\circ Q=\vartheta PQ=ϑ

结论

E l l i p t i c   c u r v e = { ( x , y ) ⋃ ϑ ∣ y 2 ≡ x 3 + a ⋅ x + b   m o d   p } Elliptic \ curve=\{(x,y) \bigcup \vartheta|y^2 \equiv x^3 + a \cdot x + b \ mod \ p\} Elliptic curve={(x,y)ϑy2x3+ax+b mod p},其中 a , b ∈ Z p a,b \in Z_p a,bZp 4 ⋅ a 3 + 27 ⋅ b 2 ≠ 0   m o d   p 4 \cdot a^3+27 \cdot b^2 \ne 0 \ mod \ p 4a3+27b2=0 mod p,以及其上的二元运算 ∘ \circ ,构成一个有限群。在某种条件下构成有限循环群。

如何证明请参考专业书籍,这里的某种条件,我们通常会选取满足条件的 a a a b b b p p p,所以我们以下假定椭圆曲线在以上定义的二元运算上是有限循环群。

一些简称

二元运算 P ∘ Q P\circ Q PQ,我们通常称为加法 P + Q P+Q P+Q
二元运算 P ∘ P P\circ P PP,我们通常称为倍乘 2 ⋅ P 2\cdot P 2P;则 P d = P ∘ P ∘ ⋯ ∘ P ⏟ d = d ⋅ P P^d=\underbrace{P\circ P \circ \cdots \circ P}_d=d\cdot P Pd=d PPP=dP

3.3 椭圆曲线上的离散对数问题

给定一条基于素数域 Z p Z_p Zp的椭圆曲线 E E E,模为 p p p,椭圆曲线的系数为 a a a b b b;若G为生成元, o r d ( G ) = # E ord(G)=\#E ord(G)=#E,则离散问题描述为:给定 P ∈ E P \in E PE,求 d d d使得 G d = P G ^d = P Gd=P d ⋅ G = P d\cdot G=P dG=P,其中 1 ≤ d ≤ # E 1 \le d \le \#E 1d#E。这里唯一要说明的是这在计算上是困难的。

注意: # E \#E #E椭圆曲线点的数目。

3.3 椭圆曲线在密码学上的应用

3.3.1 椭圆曲线的密钥生成

1.域参数选择

选择一条基于素数域 Z p Z_p Zp椭圆曲线 E E E,模为 p p p,椭圆曲线的系数为 a a a b b b
选择椭圆曲线上的一个点 G G G G G G的阶为 n n n,阶 n n n是素数,G称为基点。
模为 p p p,椭圆曲线的系数为 a a a b b b G = ( x G , y G ) G=(x_G,y_G) G=(xG,yG)和阶 n n n称为域参数。域参数是公开的。

2.密钥生成

随机选择一个整数 d d d 1 ≤ d < n 1\le d < n 1d<n
计算 P = d ⋅ G P=d\cdot G P=dG

3.公钥 K p u b = P = ( x P , y P ) K_{pub}=P=(x_P,y_P) Kpub=P=(xP,yP)和私钥 K p r i = d K_{pri}=d Kpri=d

3.3.2 椭圆曲线的数字签名算法

签名

用私钥 d d d对消息 x x x进行签名

1.选择 1 ≤ K E < n 1\le K_E < n 1KE<n
2.计算 R = K E ⋅ G = ( x R , y R ) R=K_E\cdot G=(x_R,y_R) R=KEG=(xR,yR)
3.签名结果为 ( r , s ) (r,s) (r,s),其中 r = x R r=x_R r=xR
4.计算s, s ≡ ( h ( x ) + d ⋅ r ) ⋅ K E − 1   m o d   n s \equiv (h(x)+d\cdot r)\cdot K_E^{-1} \ mod \ n s(h(x)+dr)KE1 mod n,其中 K E − 1 ⋅ K E ≡ 1   m o d   n K_E^{-1} \cdot K_E \equiv 1 \ mod \ n KE1KE1 mod n,h为hash算法。

验签

用公钥 P P P对结果 ( x , ( r , s ) ) (x,(r,s)) (x,(r,s))进行验签

1.计算 ω = s − 1   m o d   n \omega=s^{-1} \ mod \ n ω=s1 mod n
2.计算 μ 1 = ω ⋅ h ( x )   m o d   n \mu_1=\omega \cdot h(x) \ mod \ n μ1=ωh(x) mod n
3.计算 μ 2 = ω ⋅ r   m o d   n \mu_2=\omega \cdot r \ mod \ n μ2=ωr mod n
4.计算 Q = μ 1 ⋅ G + μ 2 ⋅ P Q=\mu_1\cdot G+\mu_2\cdot P Q=μ1G+μ2P。若 x Q ≡ r   m o d   n x_Q \equiv r \ mod \ n xQr mod n,则签名正确。

证明:

因为 G G G是基点,所以 n ⋅ G = ϑ n\cdot G=\vartheta nG=ϑ
又因为 P = d ⋅ G P=d\cdot G P=dG
μ 1 = ω ⋅ h ( x )   m o d   n \mu_1=\omega \cdot h(x) \ mod \ n μ1=ωh(x) mod n,知存在 c 1 c_1 c1使得 μ 1 = ω ⋅ h ( x ) + c 1 ⋅ n \mu_1=\omega \cdot h(x) + c_1 \cdot n μ1=ωh(x)+c1n
μ 2 = ω ⋅ r   m o d   n \mu_2=\omega \cdot r \ mod \ n μ2=ωr mod n,知存在 c 2 c_2 c2使得 μ 2 = ω ⋅ r + c 2 ⋅ n \mu_2=\omega \cdot r + c_2\cdot n μ2=ωr+c2n
所以 Q = μ 1 ⋅ G + μ 2 ⋅ P = ( ω ⋅ h ( x ) + c 1 ⋅ n ) ⋅ G + ( ω ⋅ r + c 2 ⋅ n ) ⋅ d ⋅ G Q=\mu_1\cdot G+\mu_2\cdot P=(\omega \cdot h(x) + c_1 \cdot n)\cdot G+(\omega \cdot r + c_2\cdot n)\cdot d \cdot G Q=μ1G+μ2P=(ωh(x)+c1n)G+(ωr+c2n)dG
所以 Q = ( ω ⋅ h ( x ) ) ⋅ G + ( ω ⋅ r ⋅ d ) ⋅ G = ( ω ⋅ h ( x ) + ω ⋅ r ⋅ d ) ⋅ G Q=(\omega \cdot h(x))\cdot G + (\omega \cdot r \cdot d)\cdot G=(\omega \cdot h(x) + \omega \cdot r \cdot d)\cdot G Q=(ωh(x))G+(ωrd)G=(ωh(x)+ωrd)G
ω = s − 1   m o d   n \omega=s^{-1} \ mod \ n ω=s1 mod n,知存在 c 3 c_3 c3使得 ω = s − 1 + c 3 ⋅ n \omega=s^{-1} + c_3\cdot n ω=s1+c3n
所以 Q = ( s − 1 ⋅ h ( x ) + s − 1 ⋅ r ⋅ d ) ⋅ G Q=(s^{-1} \cdot h(x) + s^{-1} \cdot r \cdot d)\cdot G Q=(s1h(x)+s1rd)G
s ≡ ( h ( x ) + d ⋅ r ) ⋅ K E − 1   m o d   n s \equiv (h(x)+d\cdot r)\cdot K_E^{-1} \ mod \ n s(h(x)+dr)KE1 mod n,则 K E = s − 1 ⋅ h ( x ) + s − 1 ⋅ r ⋅ d   m o d   n K_E=s^{-1} \cdot h(x) + s^{-1} \cdot r \cdot d \ mod \ n KE=s1h(x)+s1rd mod n。又 R = K E ⋅ G = ( x R , y R ) R=K_E\cdot G=(x_R,y_R) R=KEG=(xR,yR)。证毕。

3.3.3 椭圆曲线的DH算法

参考前面

3.3.5 Python测试代码

import hashlib
import math

#求逆 mod p
def inverseP(p,r1): #p为正整数,r0为整数
#修正r0为0=<r0<p
    if r1<0 or r1>p:
        r1=r1-math.floor(r1/p)*p

    r0=p
    r1=r1

    #满足r0=s0*r0+t0*r1
    s0=1
    t0=0 
    #满足r1=s1*r0+t1*r1
    s1=0
    t1=1 
    while r1 !=0:
        r2= r0 % r1
        q= r0//r1 
        r0=r1
        r1=r2
        s0_temp=s0
        t0_temp=t0
        #r0=r1=s1*r0+t1*r1 所以s0=s1 t0=t1
        s0=s1
        t0=t1  
        #r1=r2=r0-q*r1=(s0*r0+t0*r1)-q*(s1*r0+t1*r1)=(s0-q*s1)*r0+(t0-q*t1)*r1
        s1=s0_temp-q*s1
        t1=t0_temp-q*t1
    if r0!=1:
        print("No inverseP")
        return 0
    else:
        if t0<0 or t0>p:
            t0=t0-math.floor(t0/p)*p #修正到0和p-1之间
        return t0

#自定义椭圆曲线
class EcSelfDefine():
  def __init__(self,a,b,p,xG,yG,order,d,xPub,yPub):
    self.a=a
    self.b=b
    self.p=p
    self.xG=xG
    self.yG=yG
    self.order=order
    self.d=d
    self.xPub=xPub
    self.yPub=yPub

  def _point_addition(self,xP,yP,xQ,yQ):
    if xP == None:
      return xQ,yQ
    elif xQ == None:
      return xP,yP
    elif yP == -1*yQ:
      return None,None
    elif xP==xQ and yP==yQ:
      s=((3 * xP**2 + self.a ) * inverseP(self.p,(2 * yP)))%self.p
      newx = -2 * xP  + s*s
      newy = -yP + s*(xP-newx)
      return newx % self.p , newy % self.p
    else:
      s=((yQ-yP)*inverseP(self.p,(xQ-xP)))%self.p
      newx = - xP-xQ  + s*s
      newy = -yP + s*(xP-newx)
      return newx % self.p , newy % self.p

  def _mul(self,scalar,xP,yP):
    xResult = None
    yResult = None
    xN=xP
    yN=yP
    if scalar > 0:
      for bit in range(scalar.bit_length()):
        if (scalar & (1 << bit)):
          (xResult,yResult)=self._point_addition(xResult,yResult,xN,yN)
        (xN,yN)=self._point_addition(xN,yN,xN,yN)
    return xResult,yResult

  def verifySign(self,data,r,s,hash):
      mHash=hashlib.sha256(data)
      ismp=inverseP(self.order,s)
      u1=ismp*int(mHash.hexdigest(),16) % self.order
      u2=ismp*r % self.order
      xP1,yP1=self._mul(u1,self.xG,self.yG)
      xP2,yP2=self._mul(u2,self.xPub,self.yPub)
      x,y=self._point_addition(xP1,yP1,xP2,yP2)
      if r % self.order == x % self.order:
        print("verify suc")
      else:
        print("verify fail")



#椭圆曲线SECP256K1()的域参数
p=115792089237316195423570985008687907853269984665640564039457584007908834671663 
a=0#椭圆曲线系数 a
b=7#椭圆曲线系数 b
xG=55066263022277343669578718895168534326250603453777594175500187360389116729240#基点G 
yG=32670510020758816978083085130507043184471273380659243275938904335757337482424
order=115792089237316195423570985008687907852837564279074904382605163141518161494337#基点G的阶

#私钥
d="77090417795357418597142879162416172615250850989980925874163023305273313532855"
d=int(d,16) 

#公钥Pub=(xPub,yPub)
xPub=int("d00d4ae6f998fa1d1c2f7b9f45dfba6021cd678b80cce46c39a268b1dbac1274",16) 
yPub=int("3e409cf6d4894b21e21b0ef30b1b108b15ceaa24677c5c4418cec371c97fd96f",16) 

#数据
data = b"this is some data I'd like to sign"

EcCure=EcSelfDefine(a,b,p,xG,yG,order,d,xPub,yPub)

#签名结果(r,s)
r="1b68fe1f67f371e23be270bb6a1cefba406da2fab0e227c4e9f83ac8b067e7da"
s="71b079be6001e53b421f736024791f8fd28d55db50fef16f86a06115c7043b45"
r=int(r,16)
s=int(s,16)

#验签
EcCure.verifySign(data,r,s,0)

4. 基于素数域 Z p Z_p Zp的SM2国密算法

4.1 SM2椭圆曲线的定义

SM2的椭圆曲线的域参数如下

a=int('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC',16)
b=int('28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93',16)
p=int('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF', 16)
xG=int('32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7',16)
yG=int('bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0',16)
order=int('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123',16)
密钥生成

密钥生成

随机选择一个整数 d d d 1 ≤ d < n 1\le d < n 1d<n n n n为阶 o r d e r order order
计算 P = d ⋅ G P=d\cdot G P=dG

公钥 K p u b = P = ( x P , y P ) K_{pub}=P=(x_P,y_P) Kpub=P=(xP,yP)和私钥 K p r i = d K_{pri}=d Kpri=d

4.2 SM2椭圆曲线在密码学上的应用

4.2.1 SM2的数字签名算法

类似于ECDSA。

签名

用私钥 d d d对消息 M M M进行签名

1.计算用户A的可辨别标识 Z A = S M 3 ( E N T L A ) ∣ ∣ I D A ∣ ∣ a ∣ ∣ b ∣ ∣ x G ∣ ∣ y G ∣ ∣ x P ∣ ∣ y P ) Z_A=SM_3(ENTL_A)||ID_A||a||b||x_G||y_G||x_P||y_P) ZA=SM3(ENTLA)IDAabxGyGxPyP),其中用户 A A A具有长度为 e n t l e n A entlen_A entlenA比特的可辨别标识 I D A ID_A IDA E N T L A ENTL_A ENTLA是由整数 e n t l e n A entlen_A entlenA转换而成的两个字节。
2.计算 M ˉ = Z A ∣ ∣ M \bar{M}=Z_A||M Mˉ=ZAM
3.计算 e = S M 3 ( M ˉ ) e=SM_3(\bar{M}) e=SM3(Mˉ)
4.选择 1 ≤ K E < n 1\le K_E < n 1KE<n
5.计算 ( x 1 , y 1 ) = K E ⋅ G (x_1,y_1)=K_E \cdot G (x1,y1)=KEG
6.计算 r r r r = ( e + x 1 )   m o d   n r=(e+x_1) \ mod \ n r=(e+x1) mod n
4.计算 s s s s = ( ( 1 + d ) − 1 ) ⋅ ( K E − r ⋅ d ) m o d      n s=((1+d)^{-1})\cdot (K_E-r\cdot d) \mod \ n s=((1+d)1)(KErd)mod n d d d为私钥。

验签

用公钥 P P P对结果 ( M , ( r , s ) ) (M,(r,s)) (M,(r,s))进行验签

1.计算e,类似于签名步骤1,2,3
2.计算 t = ( r + s )   m o d   n t=(r+s) \ mod \ n t=(r+s) mod n
3.计算计算 ( x 1 , y 1 ) = s ⋅ G + t ⋅ P (x_1,y_1)=s\cdot G+ t \cdot P (x1,y1)=sG+tP
4.计算 R = ( e + x 1 )   m o d   n R=(e+x_1) \ mod \ n R=(e+x1) mod n。若 R ≡ r   m o d   n R \equiv r \ mod \ n Rr mod n,则签名正确。

证明:

因为 G G G是基点,所以 n ⋅ G = ϑ n\cdot G=\vartheta nG=ϑ
又因为 P = d ⋅ G P=d\cdot G P=dG
t = ( r + s )   m o d   n t=(r+s) \ mod \ n t=(r+s) mod n,知存在 c 1 c_1 c1使得 t = ( r + s ) + c 1 ⋅ n t=(r+s) + c_1 \cdot n t=(r+s)+c1n
所以 ( x 1 , y 1 ) = s ⋅ G + t ⋅ P = s ⋅ G + ( r + s ) ⋅ d ⋅ G + c 1 ⋅ n ⋅ d ⋅ G = ( ( 1 + d ) ⋅ s + r ⋅ d ) ⋅ G (x_1,y_1)=s\cdot G + t \cdot P=s\cdot G + (r+s)\cdot d \cdot G +c_1\cdot n \cdot d \cdot G=((1+d)\cdot s + r\cdot d )\cdot G (x1,y1)=sG+tP=sG+(r+s)dG+c1ndG=((1+d)s+rd)G
又由 s = ( ( 1 + d ) − 1 ) ⋅ ( K E − r ⋅ d ) m o d      n s=((1+d)^{-1})\cdot (K_E-r\cdot d) \mod \ n s=((1+d)1)(KErd)mod n c 2 c_2 c2使得 ( 1 + d ) ⋅ s + r ⋅ d = K E + c 2 ⋅ n (1+d)\cdot s +r\cdot d=K_E+c_2\cdot n (1+d)s+rd=KE+c2n,所以 ( x 1 , y 1 ) = ( K E + c 2 ⋅ n ) ⋅ G = K E ⋅ G (x_1,y_1)=(K_E+c_2\cdot n)\cdot G=K_E \cdot G (x1,y1)=(KE+c2n)G=KEG,证毕。

SM2的DH算法

待写

4.2.2 SM2的公钥加密算法

加密

用公钥P对M进行加密,klen为M的比特长度

1.随机生成 1 ≤ k < n 1\le k < n 1k<n
2.计算 C 1 = k ⋅ G = ( x 1 , y 1 ) C_1=k\cdot G=(x_1,y_1) C1=kG=(x1,y1)
3.计算 ( x 2 , y 2 ) = k ⋅ P (x_2,y_2)=k\cdot P (x2,y2)=kP
4.计算 t = K D F ( x 2 ∣ ∣ y 2 , k l e n ) t=KDF(x_2||y_2,klen) t=KDF(x2y2,klen)
5.计算 C 2 = M ⊕ t C_2=M \oplus t C2=Mt
6.计算 C 3 = S M 3 ( x 2 ∣ ∣ M ∣ y 2 ) C_3=SM_3(x_2||M|y_2) C3=SM3(x2My2)
7.输出密文 C = C 1 ∣ ∣ C 2 ∣ ∣ C 3 C=C_1||C_2||C_3 C=C1C2C3,其中 C 2 C_2 C2为与明文长度相等的密文。

KDF

参考 [4] SM2 椭圆曲线公钥密码算法第2 部分:公钥加密算,国家密码管理
局,2010 年12 月

	def kdf(self,Z,klen,v=256): #SM3:256bit,32 bytes。  #klen是8的倍数。  #Z:bytes
   		if klen>(2**32-1)*256:
   			print("error")
   			return None
   		count=0x01
   		k=math.ceil(klen/v)
   		Z=Z.hex()
   		H=""
   		for i in range(k):
   			H=H+SM3.Hash_sm3(Z+"%08x" % count,1)
   			count=count+1
   		return bytes.fromhex(H[:klen//4])
解密

利用私钥d对(C=C=C_1||C_2||C_3)进行解密

利用C_1= C 1 = k ⋅ G = ( x 1 , y 1 ) C_1=k\cdot G=(x_1,y_1) C1=kG=(x1,y1)。从而 d ⋅ C 1 = k ⋅ d ⋅ G = k ⋅ P = ( x 2 , y 2 ) d\cdot C_1=k\cdot d\cdot G=k\cdot P=(x_2,y_2) dC1=kdG=kP=(x2,y2)。利用 t = K D F ( x 2 ∣ ∣ y 2 , k l e n ) t=KDF(x_2||y_2,klen) t=KDF(x2y2,klen),从而解密 M = C 2 ⊕ t M=C_2 \oplus t M=C2t

Python测试代码

SM3.py

from  math import ceil

IV="7380166f 4914b2b9 172442d7 da8a0600 a96f30bc 163138aa e38dee4d b0fb0e4e"
IV = int(IV.replace(" ", ""), 16)
a = []
for i in range(0, 8):
    a.append(0)
    a[i] = (IV >> ((7 - i) * 32)) & 0xFFFFFFFF
IV = a

def out_hex(list1):
    for i in list1:
        print("%08x" % i)
    print("\n")

def rotate_left(a, k):
    k = k % 32
    return ((a << k) & 0xFFFFFFFF) | ((a & 0xFFFFFFFF) >> (32 - k))

T_j = []
for i in range(0, 16):
    T_j.append(0)
    T_j[i] = 0x79cc4519
for i in range(16, 64):
    T_j.append(0)
    T_j[i] = 0x7a879d8a

def FF_j(X, Y, Z, j):
    if 0 <= j and j < 16:
        ret = X ^ Y ^ Z
    elif 16 <= j and j < 64:
        ret = (X & Y) | (X & Z) | (Y & Z)
    return ret

def GG_j(X, Y, Z, j):
    if 0 <= j and j < 16:
        ret = X ^ Y ^ Z
    elif 16 <= j and j < 64:
        #ret = (X | Y) & ((2 ** 32 - 1 - X) | Z)
        ret = (X & Y) | ((~ X) & Z)
    return ret

def P_0(X):
    return X ^ (rotate_left(X, 9)) ^ (rotate_left(X, 17))

def P_1(X):
    return X ^ (rotate_left(X, 15)) ^ (rotate_left(X, 23))

def CF(V_i, B_i):
    W = []
    for i in range(16):
        weight = 0x1000000
        data = 0
        for k in range(i*4,(i+1)*4):
            data = data + B_i[k]*weight
            weight = int(weight/0x100)
        W.append(data)

    for j in range(16, 68):
        W.append(0)
        W[j] = P_1(W[j-16] ^ W[j-9] ^ (rotate_left(W[j-3], 15))) ^ (rotate_left(W[j-13], 7)) ^ W[j-6]
        str1 = "%08x" % W[j]
    W_1 = []
    for j in range(0, 64):
        W_1.append(0)
        W_1[j] = W[j] ^ W[j+4]
        str1 = "%08x" % W_1[j]

    A, B, C, D, E, F, G, H = V_i
    """
    print "00",
    out_hex([A, B, C, D, E, F, G, H])
    """
    for j in range(0, 64):
        SS1 = rotate_left(((rotate_left(A, 12)) + E + (rotate_left(T_j[j], j))) & 0xFFFFFFFF, 7)
        SS2 = SS1 ^ (rotate_left(A, 12))
        TT1 = (FF_j(A, B, C, j) + D + SS2 + W_1[j]) & 0xFFFFFFFF
        TT2 = (GG_j(E, F, G, j) + H + SS1 + W[j]) & 0xFFFFFFFF
        D = C
        C = rotate_left(B, 9)
        B = A
        A = TT1
        H = G
        G = rotate_left(F, 19)
        F = E
        E = P_0(TT2)

        A = A & 0xFFFFFFFF
        B = B & 0xFFFFFFFF
        C = C & 0xFFFFFFFF
        D = D & 0xFFFFFFFF
        E = E & 0xFFFFFFFF
        F = F & 0xFFFFFFFF
        G = G & 0xFFFFFFFF
        H = H & 0xFFFFFFFF
        """
        str1 = "%02d" % j
        if str1[0] == "0":
            str1 = ' ' + str1[1:]
        print str1,
        out_hex([A, B, C, D, E, F, G, H])
        """

    V_i_1 = []
    V_i_1.append(A ^ V_i[0])
    V_i_1.append(B ^ V_i[1])
    V_i_1.append(C ^ V_i[2])
    V_i_1.append(D ^ V_i[3])
    V_i_1.append(E ^ V_i[4])
    V_i_1.append(F ^ V_i[5])
    V_i_1.append(G ^ V_i[6])
    V_i_1.append(H ^ V_i[7])
    return V_i_1

def hash_msg(msg):
    # print(msg)
    len1 = len(msg)
    reserve1 = len1 % 64
    msg.append(0x80)
    reserve1 = reserve1 + 1
    # 56-64, add 64 byte
    range_end = 56
    if reserve1 > range_end:
        range_end = range_end + 64

    for i in range(reserve1, range_end):
        msg.append(0x00)

    bit_length = (len1) * 8
    bit_length_str = [bit_length % 0x100]
    for i in range(7):
        bit_length = int(bit_length / 0x100)
        bit_length_str.append(bit_length % 0x100)
    for i in range(8):
        msg.append(bit_length_str[7-i])

    # print(msg)

    group_count = round(len(msg) / 64)

    B = []
    for i in range(0, group_count):
        B.append(msg[i*64:(i+1)*64])

    V = []
    V.append(IV)
    for i in range(0, group_count):
        V.append(CF(V[i], B[i]))

    y = V[i+1]
    result = ""
    for i in y:
        result = '%s%08x' % (result, i)
    return result

def str2byte(msg): # 字符串转换成byte数组
    ml = len(msg)
    msg_byte = []
    msg_bytearray = msg.encode('utf-8')
    for i in range(ml):
        msg_byte.append(msg_bytearray[i])
    return msg_byte

def byte2str(msg): # byte数组转字符串
    ml = len(msg)
    str1 = b""
    for i in range(ml):
        str1 += b'%c' % msg[i]
    return str1.decode('utf-8')

def hex2byte(msg): # 16进制字符串转换成byte数组
    ml = len(msg)
    if ml % 2 != 0:
        msg = '0'+ msg
    ml = int(len(msg)/2)
    msg_byte = []
    for i in range(ml):
        msg_byte.append(int(msg[i*2:i*2+2],16))
    return msg_byte

def byte2hex(msg): # byte数组转换成16进制字符串
    ml = len(msg)
    hexstr = ""
    for i in range(ml):
        hexstr = hexstr + ('%02x'% msg[i])
    return hexstr

def Hash_sm3(msg,Hexstr = 0):
    if(Hexstr):
        msg_byte = hex2byte(msg)
    else:
        msg_byte = str2byte(msg)
    return hash_msg(msg_byte)


def KDF(Z,klen): # Z为16进制表示的比特串(str),klen为密钥长度(单位byte)
    klen = int(klen)
    ct = 0x00000001
    rcnt = ceil(klen/32)
    Zin = hex2byte(Z)
    Ha = ""
    for i in range(rcnt):
        msg = Zin  + hex2byte('%08x'% ct)
        # print(msg)
        Ha = Ha + hash_msg(msg)
        # print(Ha)
        ct += 1
    return Ha[0: klen * 2]

if __name__ == '__main__':
    y = Hash_sm3("abc")
    print(y)

    # klen = 19
    # print(KDF("57E7B63623FAE5F08CDA468E872A20AFA03DED41BF1403770E040

SM2验签和加密

import SM3
import math
import os

#求逆 mod p
def inverseP(p,r1): #p为正整数,r0为整数
#修正r0为0=<r0<p
    if r1<0 or r1>p:
        r1=r1-math.floor(r1/p)*p

    r0=p
    r1=r1

    #满足r0=s0*r0+t0*r1
    s0=1
    t0=0 
    #满足r1=s1*r0+t1*r1
    s1=0
    t1=1 
    while r1 !=0:
        r2= r0 % r1
        q= r0//r1 
        r0=r1
        r1=r2
        s0_temp=s0
        t0_temp=t0
        #r0=r1=s1*r0+t1*r1 所以s0=s1 t0=t1
        s0=s1
        t0=t1  
        #r1=r2=r0-q*r1=(s0*r0+t0*r1)-q*(s1*r0+t1*r1)=(s0-q*s1)*r0+(t0-q*t1)*r1
        s1=s0_temp-q*s1
        t1=t0_temp-q*t1
    if r0!=1:
        print("No inverseP")
        return 0
    else:
        if t0<0 or t0>p:
            t0=t0-math.floor(t0/p)*p #修正到0和p-1之间
        return t0
class SM2():
	def __init__(self,d,xPub,yPub,
		a=int('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC',16),
		b=int('28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93',16),
		p=int('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF', 16),
		xG=int('32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7',16),
		yG=int('bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0',16),
		order=int('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123',16),
		key_size=32
		):
		self.a=a
		self.b=b
		self.p=p
		self.xG=xG
		self.yG=yG
		self.order=order
		self.d=d
		self.xPub=xPub
		self.yPub=yPub
		self.key_size=key_size

	def _point_addition(self,xP,yP,xQ,yQ):
		if xP == None:
			return xQ,yQ
		elif xQ == None:
			return xP,yP
		elif yP == -1*yQ:
			return None,None
		elif xP==xQ and yP==yQ:
			s=((3 * xP**2 + self.a ) * inverseP(self.p,(2 * yP)))%self.p
			newx = -2 * xP  + s*s
			newy = -yP + s*(xP-newx)
			return newx % self.p , newy % self.p
		else:
			s=((yQ-yP)*inverseP(self.p,(xQ-xP)))%self.p
			newx = - xP-xQ  + s*s
			newy = -yP + s*(xP-newx)
			return newx % self.p , newy % self.p

	def _mul(self,scalar,xP,yP):
		xResult = None
		yResult = None
		xN=xP
		yN=yP
		if scalar > 0:
			for bit in range(scalar.bit_length()):
				if (scalar & (1 << bit)):
					(xResult,yResult)=self._point_addition(xResult,yResult,xN,yN)
				(xN,yN)=self._point_addition(xN,yN,xN,yN)
		return xResult,yResult

	def verifySign(self,data,IDA,r,s,hash):#IDA hexstr r int s int hash 0   
		#02杂凑值ZA=H256(ENTLA ∥ IDA ∥ a ∥ b ∥ xG ∥ yG ∥ xA ∥ yA)
		#IDA="11248139509653376079" #hexstr

		#1.计算e
		ENTLA="".join(["%02x" % x for x in [(len(IDA)*4)//256,(len(IDA)*4)%256]])
		a='FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC'
		b='28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93'
		xG='32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7'
		yG='bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0'
		#xG="5fcf1e2d45db51f4e0145b0a86f9d6b8eaadde214041cd7ae3c77fcdfb4cba2c"
		xPub="0"*(self.key_size-len("%x" % self.xG))+"%x" % self.xPub
		yPub="0"*(self.key_size-len("%x" % self.xG))+"%x" % self.yPub
		ZA=ENTLA+IDA+a+b+xG+yG+xPub+yPub
		ZA=SM3.Hash_sm3(ZA,1)
		e=ZA+data.hex()
		e=SM3.Hash_sm3(e,1)

		#2.计算t=r+s
		t=(r+s) % self.order

		#3.计算(x1,y1)
		xP1,yP1=self._mul(s,self.xG,self.yG)
		xP2,yP2=self._mul(t,self.xPub,self.yPub)
		x_1,y_1=self._point_addition(xP1,yP1,xP2,yP2)

		#4.计算R
		R=int(e,16)+x_1
		if r % self.order == R % self.order:
   			print("verify suc")
		else:
   			print("verify fail")

	def sign():
   		pass

	def kdf(self,Z,klen,v=256): #SM3:256bit,32 bytes。  #klen是8的倍数。  #Z:bytes
   		if klen>(2**32-1)*256:
   			print("error")
   			return None
   		count=0x01
   		k=math.ceil(klen/v)
   		Z=Z.hex()
   		H=""
   		for i in range(k):
   			H=H+SM3.Hash_sm3(Z+"%08x" % count,1)
   			count=count+1
   		return bytes.fromhex(H[:klen//4])

	def encrypt(self,message):#返回bytes
		#1.随机选择k
		key=os.urandom(32)
		key=key.hex()

		#2.计算C_1=(x_1,y_1)
		C1_x,C1_y=self._mul(int(key,16),self.xG,self.yG)

		#3.计算(x_2,y_2)
		x_2,y_2=self._mul(int(key,16),self.xPub,self.yPub)

		#4.计算t
		t=self.kdf(bytes.fromhex("%064x" % x_2 + "%064x" % y_2),len(message)*8)

		#5.计算C_2
		C2="".join([ "%02x" % (message[i]^t[i]) for i in range(len(message))])

		#6.计算C_3
		C3=SM3.Hash_sm3("%064x" % x_2 + message.hex()+"%064x" % y_2,1)


		C1="04"+"%064x" % C1_x + "%064x" % C1_y #"04"代表C_1是未压缩模式
		C=C1+C2+C3

		return bytes.fromhex(C)

	def dencrypt(self,e_message):#返回bytes

		if e_message[0] != 0x04:
			print(error)
			return

		#1.提取C_1
		C1_x=e_message[1:1+32]
		C1_y=e_message[1+32:1+32+32]

		#2.提取C_2
		C2=e_message[1+32+32:-32]

		#3.提取C_3
		C3=e_message[-32:]

		#4.计算(x_2,y_2)
		x_2,y_2=self._mul(self.d,int(C1_x.hex(),16),int(C1_y.hex(),16))

		#5.计算t
		t=self.kdf(bytes.fromhex("%064x" % x_2 + "%064x" % y_2),len(C2)*8)

		#6.计算明文M
		M="".join([ "%02x" % (C2[i]^t[i]) for i in range(len(C2))])

		C3_=SM3.Hash_sm3("%064x" % x_2 + M+"%064x" % y_2,1)
		if C3.hex()==C3_:
			return bytes.fromhex(M)
		else:
			print("fail")
			return b"fail"


if __name__=="__main__":


	#私钥
	d=int("552E8CA9F023F8AFAAFA6FF35B8B936E3940EFA94BEB6FD2D066C5BA99D8B7B9",16)

	#公钥
	xPub=int("5fcf1e2d45db51f4e0145b0a86f9d6b8eaadde214041cd7ae3c77fcdfb4cba2c",16)
	yPub=int("ec3ae9e628850d73b43f1012e96c6193184dca08c607e3ff27772746e3029890",16)

	#用户ID
	IDA="3131323438313339353039363533333736303739"

	#1.验签
	#数据M
	data=bytes.fromhex("6D65737361676520646967657374")

	#签名结构(r,s)
	r="FBF686FD1DAA6B635E1377112CF7B0BC1FD170A90D3120F9722D5C36DE8CD566"
	s="4DFAB9FA7F92759829EF170F48D7E9BF0A8723B13861A7F4FE7111AAE15B7AC2"
	sm=SM2(d,xPub,yPub)
	sm.verifySign(data,IDA,int(r,16),int(s,16),0)


	#2.加密
	yResult=sm.encrypt(b'I love you')
	print(yResult.hex())

	#3.解密
	yResult_plain=sm.dencrypt(yResult)
	print(yResult_plain)

参考

[1] Understanding Cryptography: A Textbook for Students and Practitioners,
Paar, Christof, Pelzl, Jan
[2] SM2 椭圆曲线公钥密码算法第1 部分:总则,国家密码管理局,2010 年
12 月
[3] SM2 椭圆曲线公钥密码算法第2 部分:数字签名算法,国家密码管理
局,2010 年12 月
[4] SM2 椭圆曲线公钥密码算法第2 部分:公钥加密算,国家密码管理
局,2010 年12 月

结束

  • 3
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值