1.基础知识
1.1 群
定义
群是集合G和G上的二元运算 ∘ \circ ∘,简记为 ( G , ∘ ) (G,\circ) (G,∘)。集合 G = { x ∣ x ∈ G } G=\{x|x\in G\} G={x∣x∈G}和 G G G上的二元运算 ∘ \circ ∘满足如下性质:
1.封闭性:对 ∀ a , b ∈ G \forall a,b \in G ∀a,b∈G,有 a ∘ b ∈ G a\circ b \in G a∘b∈G。
2.结合性:对 ∀ a , b , c ∈ G \forall a,b,c \in G ∀a,b,c∈G,有 a ∘ b ∘ c = a ∘ ( b ∘ c ) a\circ b\circ c=a\circ (b\circ c) a∘b∘c=a∘(b∘c)。
3.单位元:存在单位元 1 1 1,使得 a ∘ 1 = 1 ∘ a = a a\circ 1=1\circ a=a a∘1=1∘a=a。
4.有逆元:对 ∀ a ∈ G \forall a \in G ∀a∈G, ∃ a − 1 ∈ G \exists a^{-1} \in G ∃a−1∈G,使得 a − 1 ∘ a = a ∘ a − 1 = 1 a^{-1}\circ a=a\circ a^{-1} =1 a−1∘a=a∘a−1=1。
若对 ∀ a , b ∈ G \forall a,b \in G ∀a,b∈G,有 a ∘ b = b ∘ a a\circ b=b\circ a a∘b=b∘a,则称群 G G G为阿贝尔群(可交换群)。
例子
1. Z n = { 0 , 1 , 2 , ⋯ , n − 1 } Z_n=\{0,1,2,\cdots,n-1\} Zn={0,1,2,⋯,n−1}, ∘ = + 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∗={ai∣ai∈{0,1,2,⋯,n−1} 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,⋯,n−1}。证明:根据定义推导,显然。
3. ( R , + ) (R,+) (R,+)是群,单位元是0。
4. ( R 去 除 0 , × ) (R去除0,\times) (R去除0,×)是群,单位元是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| ∣H∣整除∣G∣。
定理1
若 ( G , ∘ ) (G,\circ) (G,∘)是一个有限群,则对于 ∀ α ∈ G \forall \alpha \in G ∀α∈G,存在 s ≤ ∣ G ∣ s\le |G| s≤∣G∣,使得 ( α 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,⋯,p−1}, ∘ = × 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 1≤x≤n。
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,⋯,n−1}, ∘ = + 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 1≤x≤n。在这里唯一需要说明的在 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,⋯,p−1}, ∘ = × m o d p \circ=\times\ mod \ p ∘=× mod p,则其阶为 p − 1 p-1 p−1。其离散对数问题描述如下:假设 α \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) 1≤x≤(p−1)。在这里唯一需要说明的在 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,⋯,p−1},其中 α \alpha α为生成元。
发布域参数: p p p和 α \alpha α。2.密钥交换
Alice:随机选择一个 a ∈ { 2 , 3 , ⋯ , p − 1 } a \in \{2,3,\cdots,p-1\} a∈{2,3,⋯,p−1},计算 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,⋯,p−1},计算 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,⋯,n−1}, ∘ = + 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 y2≡x3+a⋅x+b mod p
其中 a , b ∈ Z p a,b \in Z_p a,b∈Zp且 4 ⋅ a 3 + 27 ⋅ b 2 ≠ 0 m o d p 4 \cdot a^3+27 \cdot b^2 \ne 0 \ mod \ p 4⋅a3+27⋅b2=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)∣y2≡x3+a⋅x+b mod p}⋃{ϑ},其中 a , b ∈ Z p a,b \in Z_p a,b∈Zp且 4 ⋅ a 3 + 27 ⋅ b 2 ≠ 0 m o d p 4 \cdot a^3+27 \cdot b^2 \ne 0 \ mod \ p 4⋅a3+27⋅b2=0 mod p。
注意:素数域 Z p = { 0 , 1 , 2 , ⋯ , p − 1 } Z_p=\{0,1,2,\cdots ,p-1\} Zp={0,1,2,⋯,p−1}的意思是:在$+ \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)∣y2≡x3+a⋅x+b mod p}⋃{ϑ},其中 a , b ∈ Z p a,b \in Z_p a,b∈Zp且 4 ⋅ a 3 + 27 ⋅ b 2 ≠ 0 m o d p 4 \cdot a^3+27 \cdot b^2 \ne 0 \ mod \ p 4⋅a3+27⋅b2=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)=P∘Q定义如下:
x 3 = s 2 − x 1 − x 2 m o d p x_3=s^2 -x_1-x_2 \ mod \ p x3=s2−x1−x2 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⋅(x1−x3)−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=x2−x1y2−y1 mod p,如果P=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=2⋅y13⋅x12+a mod p,如果P=Q另外其他一些定义:
1. ϑ \vartheta ϑ为单位元,即对 ∀ P ∈ E l l i p t i c c u r v e \forall P\in Elliptic \ curve ∀P∈Elliptic 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) P−1=(x1,p−y1 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 P∘Q=ϑ。
结论
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)⋃ϑ∣y2≡x3+a⋅x+b mod p},其中 a , b ∈ Z p a,b \in Z_p a,b∈Zp且 4 ⋅ a 3 + 27 ⋅ b 2 ≠ 0 m o d p 4 \cdot a^3+27 \cdot b^2 \ne 0 \ mod \ p 4⋅a3+27⋅b2=0 mod p,以及其上的二元运算 ∘ \circ ∘,构成一个有限群。在某种条件下构成有限循环群。
如何证明请参考专业书籍,这里的某种条件,我们通常会选取满足条件的 a a a、 b b b和 p p p,所以我们以下假定椭圆曲线在以上定义的二元运算上是有限循环群。
一些简称
二元运算 P ∘ Q P\circ Q P∘Q,我们通常称为加法 P + Q P+Q P+Q
二元运算 P ∘ P P\circ P P∘P,我们通常称为倍乘 2 ⋅ P 2\cdot P 2⋅P;则 P d = P ∘ P ∘ ⋯ ∘ P ⏟ d = d ⋅ P P^d=\underbrace{P\circ P \circ \cdots \circ P}_d=d\cdot P Pd=d P∘P∘⋯∘P=d⋅P
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 P∈E,求 d d d使得 G d = P G ^d = P Gd=P即 d ⋅ G = P d\cdot G=P d⋅G=P,其中 1 ≤ d ≤ # E 1 \le d \le \#E 1≤d≤#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 1≤d<n
计算 P = d ⋅ G P=d\cdot G P=d⋅G3.公钥 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 1≤KE<n
2.计算 R = K E ⋅ G = ( x R , y R ) R=K_E\cdot G=(x_R,y_R) R=KE⋅G=(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)+d⋅r)⋅KE−1 mod n,其中 K E − 1 ⋅ K E ≡ 1 m o d n K_E^{-1} \cdot K_E \equiv 1 \ mod \ n KE−1⋅KE≡1 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 ω=s−1 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=μ1⋅G+μ2⋅P。若 x Q ≡ r m o d n x_Q \equiv r \ mod \ n xQ≡r mod n,则签名正确。证明:
因为 G G G是基点,所以 n ⋅ G = ϑ n\cdot G=\vartheta n⋅G=ϑ
又因为 P = d ⋅ G P=d\cdot G P=d⋅G
由 μ 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)+c1⋅n。
由 μ 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+c2⋅n。
所以 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=μ1⋅G+μ2⋅P=(ω⋅h(x)+c1⋅n)⋅G+(ω⋅r+c2⋅n)⋅d⋅G。
所以 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+(ω⋅r⋅d)⋅G=(ω⋅h(x)+ω⋅r⋅d)⋅G。
由 ω = s − 1 m o d n \omega=s^{-1} \ mod \ n ω=s−1 mod n,知存在 c 3 c_3 c3使得 ω = s − 1 + c 3 ⋅ n \omega=s^{-1} + c_3\cdot n ω=s−1+c3⋅n。
所以 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=(s−1⋅h(x)+s−1⋅r⋅d)⋅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)+d⋅r)⋅KE−1 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=s−1⋅h(x)+s−1⋅r⋅d mod n。又 R = K E ⋅ G = ( x R , y R ) R=K_E\cdot G=(x_R,y_R) R=KE⋅G=(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 1≤d<n, n n n为阶 o r d e r order order。
计算 P = d ⋅ G P=d\cdot G P=d⋅G公钥 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)∣∣IDA∣∣a∣∣b∣∣xG∣∣yG∣∣xP∣∣yP),其中用户 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ˉ=ZA∣∣M。
3.计算 e = S M 3 ( M ˉ ) e=SM_3(\bar{M}) e=SM3(Mˉ)。
4.选择 1 ≤ K E < n 1\le K_E < n 1≤KE<n。
5.计算 ( x 1 , y 1 ) = K E ⋅ G (x_1,y_1)=K_E \cdot G (x1,y1)=KE⋅G
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)⋅(KE−r⋅d)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)=s⋅G+t⋅P。
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 R≡r mod n,则签名正确。证明:
因为 G G G是基点,所以 n ⋅ G = ϑ n\cdot G=\vartheta n⋅G=ϑ
又因为 P = d ⋅ G P=d\cdot G P=d⋅G
由 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)+c1⋅n。
所以 ( 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)=s⋅G+t⋅P=s⋅G+(r+s)⋅d⋅G+c1⋅n⋅d⋅G=((1+d)⋅s+r⋅d)⋅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)⋅(KE−r⋅d)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+r⋅d=KE+c2⋅n,所以 ( 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+c2⋅n)⋅G=KE⋅G,证毕。
SM2的DH算法
待写
4.2.2 SM2的公钥加密算法
加密
用公钥P对M进行加密,klen为M的比特长度
1.随机生成 1 ≤ k < n 1\le k < n 1≤k<n。
2.计算 C 1 = k ⋅ G = ( x 1 , y 1 ) C_1=k\cdot G=(x_1,y_1) C1=k⋅G=(x1,y1)。
3.计算 ( x 2 , y 2 ) = k ⋅ P (x_2,y_2)=k\cdot P (x2,y2)=k⋅P。
4.计算 t = K D F ( x 2 ∣ ∣ y 2 , k l e n ) t=KDF(x_2||y_2,klen) t=KDF(x2∣∣y2,klen)
5.计算 C 2 = M ⊕ t C_2=M \oplus t C2=M⊕t。
6.计算 C 3 = S M 3 ( x 2 ∣ ∣ M ∣ y 2 ) C_3=SM_3(x_2||M|y_2) C3=SM3(x2∣∣M∣y2)。
7.输出密文 C = C 1 ∣ ∣ C 2 ∣ ∣ C 3 C=C_1||C_2||C_3 C=C1∣∣C2∣∣C3,其中 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=k⋅G=(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) d⋅C1=k⋅d⋅G=k⋅P=(x2,y2)。利用 t = K D F ( x 2 ∣ ∣ y 2 , k l e n ) t=KDF(x_2||y_2,klen) t=KDF(x2∣∣y2,klen),从而解密 M = C 2 ⊕ t M=C_2 \oplus t M=C2⊕t。
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 月