1.基础知识
1.1 群
定义
群是集合G和G上的二元运算∘\circ∘,简记为(G,∘)(G,\circ)(G,∘)。集合G={x∣x∈G}G=\{x|x\in G\}G={x∣x∈G}和GGG上的二元运算∘\circ∘满足如下性质:
1.封闭性:对∀a,b∈G\forall a,b \in G∀a,b∈G,有a∘b∈Ga\circ b \in Ga∘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.单位元:存在单位元111,使得a∘1=1∘a=aa\circ 1=1\circ a=aa∘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=1a^{-1}\circ a=a\circ a^{-1} =1a−1∘a=a∘a−1=1。
若对∀a,b∈G\forall a,b \in G∀a,b∈G,有a∘b=b∘aa\circ b=b\circ aa∘b=b∘a,则称群GGG为阿贝尔群(可交换群)。
例子
1.Zn={0,1,2,⋯ ,n−1}Z_n=\{0,1,2,\cdots,n-1\}Zn={0,1,2,⋯,n−1},∘=+ mod n\circ=+\ mod \ n∘=+ mod n。单位元为000。
2.Zn∗={ai∣ai∈{0,1,2,⋯ ,n−1} and gcd(ai,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},∘=× mod n\circ=\times\ mod \ n∘=× mod n。单位元为111。若n为素数,则Zn∗={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α∘α∘⋯∘α的最小正整数kkk,记为ord(α)ord(\alpha)ord(α)。
有限循环群和生成元
有限群(G,∘)(G,\circ)(G,∘),若存在一个元素α\alphaα,其阶为∣G∣|G|∣G∣,则称此有限群为循环群,其中阶为∣G∣|G|∣G∣的元素称为生成元。
1.3 有用的结论
Lagrange’s 定理
GGG是有限群,若HHH是GGG的子群,则∣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α为此子群的生成元,ord(a)=sord(a)=sord(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,ord(α)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∣是素数,则除单位元外,GGG中所有元素都是生成元。
结论
若p是素数,则Zp∗={1,2,⋯ ,p−1}Z_p^*=\{1,2,\cdots,p-1\}Zp∗={1,2,⋯,p−1},∘=× mod p\circ=\times\ mod \ p∘=× mod p。结论是Zp∗Z_p^*Zp∗是有限循环群,显然也是可交换群。(此结论如何证明,未知)
2 离散对数问题
2.1 一般性定义
给定一个有限循环群(G,∘)(G,\circ)(G,∘),阶∣G∣|G|∣G∣=nnn,假设α\alphaα是G的生成元,则离散对数问题描述为:给定β∈G\beta \in Gβ∈G,求xxx使得αx=β\alpha ^x = \betaαx=β,其中1≤x≤n1 \le x \le n1≤x≤n。
2.2 ZnZ_nZn上的定义
Zn={0,1,2,⋯ ,n−1}Z_n=\{0,1,2,\cdots,n-1\}Zn={0,1,2,⋯,n−1},∘=+ mod n\circ=+\ mod \ n∘=+ mod n。则其阶为nnn,则生成元的数目为Φ(n)\Phi(n)Φ(n),其生成元为与nnn互质的数。其离散对数问题描述如下:假设α\alphaα是ZnZ_nZn的生成元,给定β∈G\beta \in Gβ∈G,求xxx使得αx=β\alpha ^x = \betaαx=β,这里αx=α+α+⋯+α⏟x mod n=x⋅α mod 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⋅α≡β mod nx \cdot \alpha \equiv \beta \ mod \ nx⋅α≡β mod n,其中1≤x≤n1 \le x \le n1≤x≤n。在这里唯一需要说明的在ZnZ_nZn上计算离散对数问题是简单的:这里x=α−1⋅βx=\alpha^{-1}\cdot \betax=α−1⋅β,其中α−1⋅α≡1 mod n\alpha^{-1} \cdot \alpha \equiv 1 \ mod \ nα−1⋅α≡1 mod n。
2.3 Zp∗Z_p^*Zp∗上的定义
ppp是素数,Zp∗={1,2,⋯ ,p−1}Z_p^*=\{1,2,\cdots,p-1\}Zp∗={1,2,⋯,p−1},∘=× mod p\circ=\times\ mod \ p∘=× mod p,则其阶为p−1p-1p−1。其离散对数问题描述如下:假设α\alphaα是Zp∗Z_p^*Zp∗的生成元,给定β∈G\beta \in Gβ∈G,求xxx使得αx=β\alpha ^x = \betaαx=β,将∘=× mod p\circ=\times\ mod \ p∘=× mod p代入得到αx≡β mod p\alpha ^x \equiv \beta \ mod \ pαx≡β mod p,其中1≤x≤(p−1)1 \le x \le (p-1)1≤x≤(p−1)。在这里唯一需要说明的在Zp∗Z_p^*Zp∗上计算离散对数问题是困难的。
2.4 基于离散对数问题的密钥交换协议(Diffie-Hellman)
基于有限循环群 Zp∗Z_p^*Zp∗的DH算法
1.初始化:Zp∗Z_p^*Zp∗的参数,通常称为域参数
选择一个大素数ppp
选择一个整数α∈{2,3,⋯ ,p−1}\alpha \in \{2,3,\cdots,p-1\}α∈{2,3,⋯,p−1},其中α\alphaα为生成元。
发布域参数:ppp和α\alphaα。2.密钥交换
Alice:随机选择一个a∈{2,3,⋯ ,p−1}a \in \{2,3,\cdots,p-1\}a∈{2,3,⋯,p−1},计算A=αa mod pA = \alpha^a \ mod \ pA=αa mod p,将AAA通过公共网路传送给Bob。
Bob:随机选择一个b∈{2,3,⋯ ,p−1}b \in \{2,3,\cdots,p-1\}b∈{2,3,⋯,p−1},计算B=αb mod pB = \alpha^b \ mod \ pB=αb mod p,将BBB通过公共网路传送给Alice。3.密钥计算
Alice:Kab=Ba=αab mod pK_{ab}=B^a=\alpha^{ab} \ mod \ pKab=Ba=αab mod p
Bob:Kab=Ab=αab mod pK_{ab}=A^b=\alpha^{ab} \ mod \ pKab=Ab=αab mod p此算法目的用于在不安全的公共网络上双方协商密钥。关键点在于通过A=αa mod pA = \alpha^a \ mod \ pA=αa mod p,很难计算aaa;同理通过B=αb mod pB = \alpha^b \ mod \ pB=αb mod p,很难计算bbb。这里利用了Zp∗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=αaA = \alpha^aA=αa,将AAA通过公共网路传送给Bob。
Bob:随机选择一个b∈{2,3,⋯ ,∣G∣}b \in \{2,3,\cdots,|G|\}b∈{2,3,⋯,∣G∣},计算B=αbB = \alpha^bB=αb,将BBB通过公共网路传送给Alice。3.密钥计算
Alice:Kab=Ba=αabK_{ab}=B^a=\alpha^{ab}Kab=Ba=αab
Bob:Kab=Ab=αabK_{ab}=A^b=\alpha^{ab}Kab=Ab=αab安全性要求:(G,∘)(G,\circ)(G,∘)上的离散对数问题要计算困难。比如Zn={0,1,2,⋯ ,n−1}Z_n=\{0,1,2,\cdots,n-1\}Zn={0,1,2,⋯,n−1},∘=+ mod n\circ=+\ mod \ n∘=+ mod n就不行。
3 素数域ZpZ_pZp上的椭圆曲线上的离散对数问题
3.1 椭圆曲线的定义
椭圆曲线的定义:椭圆曲线是点的集合,哪些点呢?
1.在素数域ZpZ_pZp上(p是素数),所有点(x,y)∈Zp(x,y) \in Z_p(x,y)∈Zp:
满足:
y2≡x3+a⋅x+b mod py^2 \equiv x^3 + a \cdot x + b \ mod \ py2≡x3+a⋅x+b mod p
其中a,b∈Zpa,b \in Z_pa,b∈Zp且4⋅a3+27⋅b2≠0 mod p4 \cdot a^3+27 \cdot b^2 \ne 0 \ mod \ p4⋅a3+27⋅b2=0 mod p。
2.另外加上一个无穷远点ϑ\varthetaϑ。
Elliptic curve={(x,y)∣y2≡x3+a⋅x+b mod 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∈Zpa,b \in Z_pa,b∈Zp且4⋅a3+27⋅b2≠0 mod p4 \cdot a^3+27 \cdot b^2 \ne 0 \ mod \ p4⋅a3+27⋅b2=0 mod p。
注意:素数域Zp={0,1,2,⋯ ,p−1}Z_p=\{0,1,2,\cdots ,p-1\}Zp={0,1,2,⋯,p−1}的意思是:在$+ \mod p $下构成单位元为000的群,去除000元素在× mod p\times \ mod \ p× mod p下构成单位元为111的群。
3.2 椭圆曲线上的二元运算∘\circ∘的定义
二元运算∘\circ∘的定义
Elliptic curve={(x,y)∣y2≡x3+a⋅x+b mod 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∈Zpa,b \in Z_pa,b∈Zp且4⋅a3+27⋅b2≠0 mod p4 \cdot a^3+27 \cdot b^2 \ne 0 \ mod \ p4⋅a3+27⋅b2=0 mod p。
椭圆曲线上的∘\circ∘的定义对∀P=(x1,y1),Q=(x2,y2)∈Elliptic curve\forall P=(x_1,y_1),Q=(x_2,y_2)\in Elliptic \ curve∀P=(x1,y1),Q=(x2,y2)∈Elliptic curve,(x3,y3)=P∘Q(x_3,y_3)=P \circ Q(x3,y3)=P∘Q定义如下:
x3=s2−x1−x2 mod px_3=s^2 -x_1-x_2 \ mod \ px3=s2−x1−x2 mod p
y3=s⋅(x1−x3)−y1mod py_3=s\cdot (x_1-x_3) -y_1 \mod py3=s⋅(x1−x3)−y1modp
其中
s=y2−y1x2−x1 mod p,如果P≠Qs=\frac{y_2- y_1}{x_2 - x_1} \ mod \ p,如果P\ne Qs=x2−x1y2−y1 mod p,如果P=Q
s=3⋅x12+a2⋅y1 mod p,如果P=Qs=\frac{3\cdot x_1^2 +a}{2\cdot y_1} \ mod \ p,如果P=Qs=2⋅y13⋅x12+a mod p,如果P=Q另外其他一些定义:
1.ϑ\varthetaϑ为单位元,即对∀P∈Elliptic curve\forall P\in Elliptic \ curve∀P∈Elliptic curve,P∘ϑ=PP\circ \vartheta=PP∘ϑ=P
2.对∀P=(x1,y1)∈Elliptic curve\forall P=(x_1,y_1) \in Elliptic \ curve∀P=(x1,y1)∈Elliptic curve,P−1=(x1,p−y1 mod p)P^{-1}=(x_1,p-y_1 \ mod \ p)P−1=(x1,p−y1 mod p),所以理论上∀P=(x1,y1),Q=(x2,y2)∈Elliptic curve\forall P=(x_1,y_1),Q=(x_2,y_2)\in Elliptic \ curve∀P=(x1,y1),Q=(x2,y2)∈Elliptic curve,若x1=x2x_1=x_2x1=x2,则P∘Q=ϑP\circ Q=\varthetaP∘Q=ϑ。
结论
Elliptic curve={(x,y)⋃ϑ∣y2≡x3+a⋅x+b mod 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∈Zpa,b \in Z_pa,b∈Zp且4⋅a3+27⋅b2≠0 mod p4 \cdot a^3+27 \cdot b^2 \ne 0 \ mod \ p4⋅a3+27⋅b2=0 mod p,以及其上的二元运算∘\circ∘,构成一个有限群。在某种条件下构成有限循环群。
如何证明请参考专业书籍,这里的某种条件,我们通常会选取满足条件的aaa、bbb和ppp,所以我们以下假定椭圆曲线在以上定义的二元运算上是有限循环群。
一些简称
二元运算P∘QP\circ QP∘Q,我们通常称为加法P+QP+QP+Q
二元运算P∘PP\circ PP∘P,我们通常称为倍乘2⋅P2\cdot P2⋅P;则Pd=P∘P∘⋯∘P⏟d=d⋅PP^d=\underbrace{P\circ P \circ \cdots \circ P}_d=d\cdot PPd=dP∘P∘⋯∘P=d⋅P
3.3 椭圆曲线上的离散对数问题
给定一条基于素数域ZpZ_pZp的椭圆曲线EEE,模为ppp,椭圆曲线的系数为aaa,bbb;若G为生成元,ord(G)=#Eord(G)=\#Eord(G)=#E,则离散问题描述为:给定P∈EP \in EP∈E,求ddd使得Gd=PG ^d = PGd=P即d⋅G=Pd\cdot G=Pd⋅G=P,其中1≤d≤#E1 \le d \le \#E1≤d≤#E。这里唯一要说明的是这在计算上是困难的。
注意:#E\#E#E椭圆曲线点的数目。
3.3 椭圆曲线在密码学上的应用
3.3.1 椭圆曲线的密钥生成
1.域参数选择
选择一条基于素数域ZpZ_pZp椭圆曲线EEE,模为ppp,椭圆曲线的系数为aaa,bbb;
选择椭圆曲线上的一个点GGG,GGG的阶为nnn,阶nnn是素数,G称为基点。
模为ppp,椭圆曲线的系数为aaa,bbb、G=(xG,yG)G=(x_G,y_G)G=(xG,yG)和阶nnn称为域参数。域参数是公开的。2.密钥生成
随机选择一个整数ddd,1≤d<n1\le d < n1≤d<n
计算P=d⋅GP=d\cdot GP=d⋅G3.公钥Kpub=P=(xP,yP)K_{pub}=P=(x_P,y_P)Kpub=P=(xP,yP)和私钥Kpri=dK_{pri}=dKpri=d
3.3.2 椭圆曲线的数字签名算法
签名
用私钥ddd对消息xxx进行签名
1.选择1≤KE<n1\le K_E < n1≤KE<n
2.计算R=KE⋅G=(xR,yR)R=K_E\cdot G=(x_R,y_R)R=KE⋅G=(xR,yR)
3.签名结果为(r,s)(r,s)(r,s),其中r=xRr=x_Rr=xR。
4.计算s,s≡(h(x)+d⋅r)⋅KE−1 mod ns \equiv (h(x)+d\cdot r)\cdot K_E^{-1} \ mod \ ns≡(h(x)+d⋅r)⋅KE−1 mod n,其中KE−1⋅KE≡1 mod nK_E^{-1} \cdot K_E \equiv 1 \ mod \ nKE−1⋅KE≡1 mod n,h为hash算法。
验签
用公钥PPP对结果(x,(r,s))(x,(r,s))(x,(r,s))进行验签
1.计算ω=s−1 mod n\omega=s^{-1} \ mod \ nω=s−1 mod n。
2.计算μ1=ω⋅h(x) mod n\mu_1=\omega \cdot h(x) \ mod \ nμ1=ω⋅h(x) mod n。
3.计算μ2=ω⋅r mod n\mu_2=\omega \cdot r \ mod \ nμ2=ω⋅r mod n。
4.计算Q=μ1⋅G+μ2⋅PQ=\mu_1\cdot G+\mu_2\cdot PQ=μ1⋅G+μ2⋅P。若xQ≡r mod nx_Q \equiv r \ mod \ nxQ≡r mod n,则签名正确。证明:
因为GGG是基点,所以n⋅G=ϑn\cdot G=\varthetan⋅G=ϑ
又因为P=d⋅GP=d\cdot GP=d⋅G
由μ1=ω⋅h(x) mod n\mu_1=\omega \cdot h(x) \ mod \ nμ1=ω⋅h(x) mod n,知存在c1c_1c1使得μ1=ω⋅h(x)+c1⋅n\mu_1=\omega \cdot h(x) + c_1 \cdot nμ1=ω⋅h(x)+c1⋅n。
由μ2=ω⋅r mod n\mu_2=\omega \cdot r \ mod \ nμ2=ω⋅r mod n,知存在c2c_2c2使得μ2=ω⋅r+c2⋅n\mu_2=\omega \cdot r + c_2\cdot nμ2=ω⋅r+c2⋅n。
所以Q=μ1⋅G+μ2⋅P=(ω⋅h(x)+c1⋅n)⋅G+(ω⋅r+c2⋅n)⋅d⋅GQ=\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 GQ=μ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)⋅GQ=(\omega \cdot h(x))\cdot G + (\omega \cdot r \cdot d)\cdot G=(\omega \cdot h(x) + \omega \cdot r \cdot d)\cdot GQ=(ω⋅h(x))⋅G+(ω⋅r⋅d)⋅G=(ω⋅h(x)+ω⋅r⋅d)⋅G。
由ω=s−1 mod n\omega=s^{-1} \ mod \ nω=s−1 mod n,知存在c3c_3c3使得ω=s−1+c3⋅n\omega=s^{-1} + c_3\cdot nω=s−1+c3⋅n。
所以Q=(s−1⋅h(x)+s−1⋅r⋅d)⋅GQ=(s^{-1} \cdot h(x) + s^{-1} \cdot r \cdot d)\cdot GQ=(s−1⋅h(x)+s−1⋅r⋅d)⋅G。
又s≡(h(x)+d⋅r)⋅KE−1 mod ns \equiv (h(x)+d\cdot r)\cdot K_E^{-1} \ mod \ ns≡(h(x)+d⋅r)⋅KE−1 mod n,则KE=s−1⋅h(x)+s−1⋅r⋅d mod nK_E=s^{-1} \cdot h(x) + s^{-1} \cdot r \cdot d \ mod \ nKE=s−1⋅h(x)+s−1⋅r⋅d mod n。又R=KE⋅G=(xR,yR)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. 基于素数域ZpZ_pZp的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)
密钥生成
密钥生成
随机选择一个整数ddd,1≤d<n1\le d < n1≤d<n,nnn为阶orderorderorder。
计算P=d⋅GP=d\cdot GP=d⋅G公钥Kpub=P=(xP,yP)K_{pub}=P=(x_P,y_P)Kpub=P=(xP,yP)和私钥Kpri=dK_{pri}=dKpri=d
4.2 SM2椭圆曲线在密码学上的应用
4.2.1 SM2的数字签名算法
类似于ECDSA。
签名
用私钥ddd对消息MMM进行签名
1.计算用户A的可辨别标识ZA=SM3(ENTLA)∣∣IDA∣∣a∣∣b∣∣xG∣∣yG∣∣xP∣∣yP)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),其中用户AAA具有长度为entlenAentlen_AentlenA比特的可辨别标识IDAID_AIDA,ENTLAENTL_AENTLA是由整数entlenAentlen_AentlenA转换而成的两个字节。
2.计算Mˉ=ZA∣∣M\bar{M}=Z_A||MMˉ=ZA∣∣M。
3.计算e=SM3(Mˉ)e=SM_3(\bar{M})e=SM3(Mˉ)。
4.选择1≤KE<n1\le K_E < n1≤KE<n。
5.计算(x1,y1)=KE⋅G(x_1,y_1)=K_E \cdot G(x1,y1)=KE⋅G
6.计算rrr,r=(e+x1) mod nr=(e+x_1) \ mod \ nr=(e+x1) mod n。
4.计算sss,s=((1+d)−1)⋅(KE−r⋅d)mod ns=((1+d)^{-1})\cdot (K_E-r\cdot d) \mod \ ns=((1+d)−1)⋅(KE−r⋅d)mod n。ddd为私钥。
验签
用公钥PPP对结果(M,(r,s))(M,(r,s))(M,(r,s))进行验签
1.计算e,类似于签名步骤1,2,3
2.计算t=(r+s) mod nt=(r+s) \ mod \ nt=(r+s) mod n。
3.计算计算(x1,y1)=s⋅G+t⋅P(x_1,y_1)=s\cdot G+ t \cdot P(x1,y1)=s⋅G+t⋅P。
4.计算R=(e+x1) mod nR=(e+x_1) \ mod \ nR=(e+x1) mod n。若R≡r mod nR \equiv r \ mod \ nR≡r mod n,则签名正确。证明:
因为GGG是基点,所以n⋅G=ϑn\cdot G=\varthetan⋅G=ϑ
又因为P=d⋅GP=d\cdot GP=d⋅G
由t=(r+s) mod nt=(r+s) \ mod \ nt=(r+s) mod n,知存在c1c_1c1使得t=(r+s)+c1⋅nt=(r+s) + c_1 \cdot nt=(r+s)+c1⋅n。
所以(x1,y1)=s⋅G+t⋅P=s⋅G+(r+s)⋅d⋅G+c1⋅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)⋅(KE−r⋅d)mod ns=((1+d)^{-1})\cdot (K_E-r\cdot d) \mod \ ns=((1+d)−1)⋅(KE−r⋅d)mod n知c2c_2c2使得(1+d)⋅s+r⋅d=KE+c2⋅n(1+d)\cdot s +r\cdot d=K_E+c_2\cdot n(1+d)⋅s+r⋅d=KE+c2⋅n,所以(x1,y1)=(KE+c2⋅n)⋅G=KE⋅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<n1\le k < n1≤k<n。
2.计算C1=k⋅G=(x1,y1)C_1=k\cdot G=(x_1,y_1)C1=k⋅G=(x1,y1)。
3.计算(x2,y2)=k⋅P(x_2,y_2)=k\cdot P(x2,y2)=k⋅P。
4.计算t=KDF(x2∣∣y2,klen)t=KDF(x_2||y_2,klen)t=KDF(x2∣∣y2,klen)
5.计算C2=M⊕tC_2=M \oplus tC2=M⊕t。
6.计算C3=SM3(x2∣∣M∣y2)C_3=SM_3(x_2||M|y_2)C3=SM3(x2∣∣M∣y2)。
7.输出密文C=C1∣∣C2∣∣C3C=C_1||C_2||C_3C=C1∣∣C2∣∣C3,其中C2C_2C2为与明文长度相等的密文。
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=C1=k⋅G=(x1,y1)C_1=k\cdot G=(x_1,y_1)C1=k⋅G=(x1,y1)。从而d⋅C1=k⋅d⋅G=k⋅P=(x2,y2)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=KDF(x2∣∣y2,klen)t=KDF(x_2||y_2,klen)t=KDF(x2∣∣y2,klen),从而解密M=C2⊕tM=C_2 \oplus tM=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 月
本文深入探讨了群论的基本概念,包括群、有限群、循环群及其性质,并详细解析了离散对数问题在不同群上的定义与应用。特别地,文章介绍了在Zp*和椭圆曲线群上的离散对数问题,以及它们在Diffie-Hellman密钥交换、数字签名和加密算法中的应用,如DH算法、ECDSA、SM2算法。

1848

被折叠的 条评论
为什么被折叠?



