1. 引言
前序博客:
所谓Schnorr签名,是指:
- 签名:将消息
m
m
m 签署为:
σ
=
(
R
,
s
)
\sigma = (R, s)
σ=(R,s),其中:
- r ← § Z p r\xleftarrow{\S} \mathbb{Z}_p r§Zp为随机值
- R = g r R = g^r R=gr
- s = r − H ( R , m ) ⋅ s k s = r - H(R, m) \cdot sk s=r−H(R,m)⋅sk
- 验签:基于公钥 p k = g s k pk = g^{sk} pk=gsk,若 R = g s ⋅ p k H ( R , m ) R = g^s \cdot pk^{H(R, m)} R=gs⋅pkH(R,m)成立,则验签通过。
2. Schnorr签名历史
Schnorr签名方案由德国数学家Claus-Peter Schnorr在 CRYPTO 1989论文Efficient Identification and Signatures for Smart Cards中首次提出,在该论文中:
- Claus-Peter Schnorr提出了一种identification身份证明方案,并通过使用著名的Fiat-Shamir transform转换为签名方案。关于Fiat-Shamir transform,详情见Amos Fiat和Adi Shamir CRYPTO 1986论文How To Prove Yourself: Practical Solutions to Identification and Signature Problems。
- 该签名方案所选择的Abelian group为:
Z
p
∗
\mathbb{Z}_p^*
Zp∗的prime-order
q
q
q子群,其中
p
p
p为素数。
- 后续的研究成果发现可扩展为任意prime-order group——如椭圆曲线群。
Claus-Peter Schnorr在1990为其方案申请了专利。
- 这可能是比特币和其他加密货币领域选择ECDSA而不是Schnorr作为其签名方案的最大原因。
- Schnorr更简单、更高效、更容易做t-of-n门限签名。
- 2010年,专利到期后,Schnorr签名变得更受欢迎。
相比于Schnorr签名,ECDSA签名方案的最大优势在于其public key recovery公钥恢复特性——Bitcoin P2PKH模式下利用了该特性,来让TXN签名更小。实际上,自比特币创立以来,其即使用了P2PKH模式。
3. Schnorr签名方案——prime-order group
预备知识:
- 有prime order p p p 的group G \mathbb{G} G 和有限域 Z p \mathbb{Z}_p Zp
- 令 g g g为 G \mathbb{G} G的generator
- 抗碰撞哈希函数 H : G × { 0 , 1 } ∗ → Z p H : \mathbb{G} \times \{0,1\}^* \rightarrow \mathbb{Z}_p H:G×{0,1}∗→Zp
S c h n o r r \mathsf{Schnorr} Schnorr. K e y G e n ( 1 λ ) → ( s k , p k ) \mathsf{KeyGen}(1^\lambda) \rightarrow (sk, pk) KeyGen(1λ)→(sk,pk):
- s k ← § Z p sk\xleftarrow{\S}\mathbb{Z}_p sk§Zp
- p k ← g s k pk \gets g^{sk} pk←gsk
S c h n o r r \mathsf{Schnorr} Schnorr. S i g n ( m , s k ) → σ \mathsf{Sign}(m, sk) \rightarrow \sigma Sign(m,sk)→σ:
- r ← § Z p r\xleftarrow{\S}\mathbb{Z}_p r§Zp
- R ← g r R \gets g^r R←gr
- s ← ( r − H ( R , m ) ⋅ s k ) m o d p s \gets (r - H(R, m) \cdot sk) \bmod p s←(r−H(R,m)⋅sk)modp 【注意也可用加号来代替其中的减号,验签时做相应调整即可。】
- σ ← ( R , s ) \sigma\gets (R, s) σ←(R,s)
S c h n o r r \mathsf{Schnorr} Schnorr. V e r i f y ( m , p k , σ ) → { 0 , 1 } \mathsf{Verify}(m, pk, \sigma) \rightarrow \{0,1\} Verify(m,pk,σ)→{0,1}:
- ( R , s ) ← σ (R, s) \gets \sigma (R,s)←σ
- assert R = ? g s ⋅ p k H ( R , m ) R \overset{\text{?}}{=} g^s \cdot pk^{H(R, m)} R=?gs⋅pkH(R,m)
3.1 Schnorr签名方案正确性
若由
S
c
h
n
o
r
r
.
S
i
g
n
\mathsf{Schnorr.Sign}
Schnorr.Sign创建的签名,可通过
S
c
h
n
o
r
r
.
V
e
r
i
f
y
\mathsf{Schnorr.Verify}
Schnorr.Verify验证正确,则该签名方案具备correctness正确性:
R
=
?
g
s
⋅
p
k
H
(
R
,
m
)
g
r
=
?
g
r
−
H
(
R
,
m
)
⋅
s
k
⋅
(
g
s
k
)
H
(
R
,
m
)
g
r
=
?
g
r
−
H
(
R
,
m
)
⋅
s
k
⋅
g
H
(
R
,
m
)
⋅
s
k
g
r
=
?
g
r
\begin{align} R &\overset{\text{?}}{=} g^s \cdot pk^{H(R, m)}\\ g^r &\overset{\text{?}}{=} g^{r-H(R, m)\cdot sk} \cdot (g^{sk})^{H(R, m)}\\ g^r &\overset{\text{?}}{=} g^{r-H(R, m)\cdot sk} \cdot g^{H(R, m) \cdot sk}\\ g^r &\overset{\text{?}}{=} g^r \end{align}
Rgrgrgr=?gs⋅pkH(R,m)=?gr−H(R,m)⋅sk⋅(gsk)H(R,m)=?gr−H(R,m)⋅sk⋅gH(R,m)⋅sk=?gr
3.2 Schnorr签名 σ = ( R , s ) \sigma=(R,s) σ=(R,s)批量验证
批量验证Schnorr签名,要比逐个验证,快得多。
如对于
n
n
n个签名
(
σ
i
,
m
i
,
p
k
i
)
i
∈
[
n
]
(\sigma_i, m_i, pk_i)_{i\in [n]}
(σi,mi,pki)i∈[n],其中
σ
i
=
(
R
i
,
s
i
)
\sigma_i = (R_i, s_i)
σi=(Ri,si),可通过将
S
c
h
n
o
r
r
.
V
e
r
i
f
y
(
m
i
,
p
k
i
,
σ
i
)
=
1
,
∀
i
∈
[
n
]
\mathsf{Schnorr.Verify}(m_i, pk_i, \sigma_i) = 1,\forall i\in [n]
Schnorr.Verify(mi,pki,σi)=1,∀i∈[n]的所有验签方程式线性随机组合为一个验签方程式,来一次验证所有签名,即所谓的批量验证算法
S
c
h
n
o
r
r
.
B
a
t
c
h
V
e
r
i
f
y
(
(
m
i
,
p
k
i
,
σ
i
)
i
∈
[
n
]
)
→
{
0
,
1
}
\mathsf{Schnorr.BatchVerify}((m_i, pk_i, \sigma_i)_{i\in[n]}) \rightarrow \{0,1\}
Schnorr.BatchVerify((mi,pki,σi)i∈[n])→{0,1}为:
- z _ i ← § { 0 , 1 } λ , ∀ i ∈ [ n ] z\_i \xleftarrow{\S} \{0,1\}^\lambda,\forall i\in[n] z_i§{0,1}λ,∀i∈[n]
- ( R i , s i ) ← σ i , ∀ i ∈ [ n ] (R_i,s_i)\gets \sigma_i, \forall i \in [n] (Ri,si)←σi,∀i∈[n]
- assert ∏ i ∈ [ n ] R i − z i g s _ i ⋅ z i p k i H ( R i , m i ) ⋅ z i = ? 1 \prod_{i \in [n]} R_i^{-z_i} g^{s\_i \cdot z_i} pk_i^{H(R_i, m_i)\cdot z_i}\overset{\text{?}}{=} 1 ∏i∈[n]Ri−zigs_i⋅zipkiH(Ri,mi)⋅zi=?1
其中assert 方程式中的multi-exponentiation计算,可使用如Bos-Coster或BDL+12算法来加速。BDL+12算法见2012年论文《High-speed high-security signatures》。
当所需批量验证的签名都源自同一公钥时,即
p
k
i
=
p
k
,
∀
i
∈
[
n
]
pk_i = pk, \forall i\in[n]
pki=pk,∀i∈[n],可进一步降低multi-exponentiation size,实现加速:
(
∏
i
∈
[
n
]
R
i
−
z
i
g
s
i
⋅
z
i
)
p
k
∑
i
∈
[
n
]
H
(
R
i
,
m
i
)
⋅
z
i
=
?
1
\begin{align} \left(\prod_{i \in [n]} R_i^{-z_i} g^{s_i \cdot z_i}\right) pk^{\sum_{i\in[n]} H(R_i, m_i)\cdot z_i} \overset{\text{?}}{=} 1 \end{align}
i∈[n]∏Ri−zigsi⋅zi
pk∑i∈[n]H(Ri,mi)⋅zi=?1
基于prime order group实现Schnorr签名批量验证,使其返回与单个验证相同的结果。而若是基于non-prime order group(Edwards 25519)上做签名的批量验证,则要更棘手。
3.3 Schnorr签名的另一种表示—— σ ′ = ( e , s ) \sigma'=(e, s) σ′=(e,s)
将Schnorr签名,由 σ = ( R , s ) \sigma=(R,s) σ=(R,s),转换为另一种表示: σ ′ = ( e , s ) \sigma'=(e, s) σ′=(e,s),其中 e = H ( R , m ) e = H(R, m) e=H(R,m)。
- 这样做的可能优势在于:哈希函数
H
H
H可让
e
e
e比
R
R
R所需的bit数更少。
- Claus-Peter Schnorr在 CRYPTO 1989论文Efficient Identification and Signatures for Smart Cards 中声称:
- λ \lambda λ-bit(而不是 2 λ 2\lambda 2λ)哈希函数,足以实现 λ \lambda λ-bit安全性。
- 劣势在于:不支持更高效的批量验签。
S c h n o r r ′ \mathsf{Schnorr}' Schnorr′. S i g n ( m , s k ) → σ \mathsf{Sign}(m, sk) \rightarrow \sigma Sign(m,sk)→σ:
- r ← § Z p r\xleftarrow{\S}\mathbb{Z}_p r§Zp
- R ← g r R \gets g^r R←gr
- e ← H ( R , m ) e \gets H(R, m) e←H(R,m)
- s ← ( r + e ⋅ s k ) m o d p s \gets (r + e \cdot sk)\bmod p s←(r+e⋅sk)modp
- σ ← ( e , s ) \sigma\gets (e, s) σ←(e,s)
S c h n o r r ′ \mathsf{Schnorr}' Schnorr′. V e r i f y ( m , p k , σ ) → { 0 , 1 } \mathsf{Verify}(m, pk, \sigma) \rightarrow \{0,1\} Verify(m,pk,σ)→{0,1}:
- ( e , s ) ← σ (e, s) \gets \sigma (e,s)←σ
- assert e = ? H ( g s ⋅ p k e , m ) e \overset{\text{?}}{=} H(g^s \cdot pk^e, m) e=?H(gs⋅pke,m)
4. EdDSA 和 Ed25519——non-prime order group
4.1 EdDSA签名方案——针对non-prime order group基于Schnorr的签名方案
EdDSA为:
- 基于Schnorr的签名方案
- 针对non-prime order
p
=
h
⋅
q
p=h\cdot q
p=h⋅q group
G
\mathbb{G}
G而设计,其中
q
≈
2
2
λ
,
h
=
8
q\approx 2^{2\lambda}, h=8
q≈22λ,h=8。
- 但2020年论文The Provable Security of Ed25519: Theory and Practice 说明可扩展为 h = 2 c h=2^c h=2c,其中 c c c为任意值。
相比于上面的Schnorr签名方案,基于安全性考虑,EdDSA做了如下修改:
- 1)nonce r r r为根据 s k sk sk和待签名消息 m m m生成的伪随机数。
- 2)签名中的哈希运算中,额外增加了公钥 p k pk pk,即不再是 H ( R , m ) H(R,m) H(R,m),而是 H ( R , p k , m ) H(R, pk, m) H(R,pk,m)。
- 3)设计为其 s k sk sk可安全地复用于 类似于X25519的Diffie-Hellman(DH)密钥交换协议中。【注意: s k = ( a , ( h b , … , h 2 b − 1 ) ) sk=(a,(h_b,\ldots,h_{2b-1})) sk=(a,(hb,…,h2b−1))中包含了私钥 a a a,以及用于生成nonce r r r的 b b b-bits—— ( h b , … , h 2 b − 1 ) (h_b,\ldots,h_{2b-1}) (hb,…,h2b−1),这样使得相同的[Ed25519] secrets也可安全用于做密钥交换。详情可参看Jake Craige 2020年7月博客An Explainer On Ed25519 Clamping。】
EdDSA需用多个哈希函数:
- H 1 : { 0 , 1 } 2 λ → { 0 , 1 } 4 λ H_1 : \{0,1\}^{2\lambda} \rightarrow \{0,1\}^{4\lambda} H1:{0,1}2λ→{0,1}4λ,
- H 2 : { 0 , 1 } 2 λ × { 0 , 1 } ∗ → { 0 , 1 } 4 λ H_2 : \{0,1\}^{2\lambda} \times \{0,1\}^* \rightarrow \{0,1\}^{4\lambda} H2:{0,1}2λ×{0,1}∗→{0,1}4λ
- H 3 : G × G × { 0 , 1 } ∗ → { 0 , 1 } 4 λ H_3 : \mathbb{G} \times \mathbb{G} \times \{0,1\}^* \rightarrow \{0,1\}^{4\lambda} H3:G×G×{0,1}∗→{0,1}4λ
这些函数函数通常可通过合适的域分隔,自单个哈希函数 H : { 0 , 1 } ∗ → { 0 , 1 } 4 λ H : \{0,1\}^* \rightarrow \{0,1\}^{4\lambda} H:{0,1}∗→{0,1}4λ 实例化而来。
E d D S A \mathsf{EdDSA} EdDSA. K e y G e n ( 1 λ ) → ( s k , p k ) \mathsf{KeyGen}(1^\lambda) \rightarrow (sk, pk) KeyGen(1λ)→(sk,pk):
- b ← 2 λ b \gets 2\lambda b←2λ
- k ⃗ ← § { 0 , 1 } b \vec{k} \xleftarrow{\S} \{0,1\}^{b} k§{0,1}b
- h ⃗ ← H 1 ( k ⃗ ) ∈ { 0 , 1 } 2 b \vec{h} \gets H_1(\vec{k}) \in \{0,1\}^{2b} h←H1(k)∈{0,1}2b
- a ← 2 b − 2 + ∑ 3 ≤ i ≤ b − 3 2 i h i a \gets 2^{b-2} + \sum_{3 \le i \le b - 3} 2^i h_i a←2b−2+∑3≤i≤b−32ihi
- s k ← ( a , ( h b , … h 2 b − 1 ) ) sk \gets (a, (h_b, \ldots h_{2b-1})) sk←(a,(hb,…h2b−1)) 【这样该 s k sk sk可同时用于Ed25519签名和X25519密钥交换协议中。】
- p k ← g a pk \gets g^{a} pk←ga【私钥为 a a a】
E d D S A \mathsf{EdDSA} EdDSA. S i g n ( m , s k ) → σ \mathsf{Sign}(m, sk) \rightarrow \sigma Sign(m,sk)→σ:
- Parse ( a , ( h b , … h 2 b − 1 ) ) ← s k (a, (h_b, \ldots h_{2b-1})) \gets sk (a,(hb,…h2b−1))←sk
- r ← H 2 ( h b , … , h 2 b − 1 , m ) ∈ { 0 , 1 } 2 b r \gets H_2(h_b,\ldots, h_{2b-1}, m) \in \{0,1\}^{2b} r←H2(hb,…,h2b−1,m)∈{0,1}2b
- R ← g r R \gets g^r R←gr
- s ← ( r + H 3 ( R , p k , m ) ⋅ a ) m o d q s \gets (r + H_3(R, pk, m) \cdot a)\bmod q s←(r+H3(R,pk,m)⋅a)modq
- σ ← ( R , s ) \sigma\gets (R, s) σ←(R,s)
在 H 3 H_3 H3中包含公钥 p k pk pk:
- 1)是“一种廉价的方法,可缓解人们对多个公钥可能同时受到攻击的担忧”。
- 2)另一个有待探索的优势是:可防止对手根据目标签名 σ \sigma σ来查找某公钥 p k pk pk所验证的消息 m m m。
- 如在上面的Schnorr签名方案中,已知任意签名 σ = ( R , s ) \sigma=(R,s) σ=(R,s),对手可选择任意消息 m m m并计算出公钥 p k = ( R / g s ) 1 / H ( R , m ) pk = (R / g^s)^{1/H(R, m)} pk=(R/gs)1/H(R,m)。
E d D S A \mathsf{EdDSA} EdDSA. V e r i f y ( m , p k , σ ) → { 0 , 1 } \mathsf{Verify}(m, pk, \sigma) \rightarrow \{0,1\} Verify(m,pk,σ)→{0,1}:
- ( R , s ) ← σ (R, s) \gets \sigma (R,s)←σ
- assert g s = ? R ⋅ p k H ( R , p k , m ) g^s \overset{\text{?}}{=} R \cdot pk^{H(R, pk, m)} gs=?R⋅pkH(R,pk,m)
另一种EdDSA高效验签函数为在指数上都乘以cofactor h h h:
- g h ⋅ s = ? R h ⋅ p k h ⋅ H ( R , p k , m ) g^{h\cdot s} \overset{\text{?}}{=} R^h \cdot pk^{h\cdot H(R, pk, m)} gh⋅s=?Rh⋅pkh⋅H(R,pk,m)
其中的微妙之处见:Henry de Valence 2020年10月博客 It’s 255:19AM. Do you know what your validation criteria are?
4.2 Ed25519
所谓Ed25519,为:
- 基于Edwards 25519曲线的EdDSA签名方案
- 具有的安全性为 λ = 128 \lambda=128 λ=128
- 选择了合理的哈希函数
正如2012年论文《High-speed high-security signatures》中所述:
Our recommended curve for EdDSA is a twisted Edwards curve birationally equivalent to the curve Curve25519 […]
We use the name Ed25519 for EdDSA with this particular choice of curve.
最常用的Ed25519为Ed25519-SHA-512,使用SHA2-512作为其哈希函数。
2020年论文The Provable Security of Ed25519: Theory and Practice中有:
5. Schnorr签名最佳实践及陷阱
在做Schnorr签名实际实现时,通常会有很多微妙之处(即陷阱),详情见:
- Henry de Valence 2020年10月博客 It’s 255:19AM. Do you know what your validation criteria are?
- 2020年论文The Provable Security of Ed25519: Theory and Practice
- 2020年论文Taming the many EdDSAs
本文总结为3大陷阱:【其中Ed25519仅可解决陷阱1问题。】
- 1)陷阱1:安全地生成nonce r r r。
- 2)陷阱2:Non-canonical serialization(非规范序列化)。
- 3)陷阱3:使用non-prime order group。
5.1 陷阱1:安全地生成nonce r r r
在Schnorr签名中,最应该避免的陷阱在于:
- 若同一公钥的2个签名复用了相同的nonce r r r,则可提取出相应的公钥。
因此,最重要的一点就是:
- 基于安全性原因,应对 r r r随机采样获取。
EdDSA中,基于消息和私钥来伪随机确定性的获取 r r r,可解决该问题。
具体的攻击情况为:
- 假设有对消息
m
1
≠
m
2
m_1 \ne m_2
m1=m2 的2个签名
σ
1
=
(
R
,
s
1
)
\sigma_1 = (R, s_1)
σ1=(R,s1) 和
σ
2
=
(
R
,
s
2
)
\sigma_2 = (R, s_2)
σ2=(R,s2),其复用了相同的
r
r
r,即有:
R = g r s 1 = r + H ( R , m 1 ) ⋅ s k s 2 = r + H ( R , m 2 ) ⋅ s k \begin{align} R &= g^r\\ s_1 &= r + H(R, m_1) \cdot sk\\ s_2 &= r + H(R, m_2) \cdot sk \end{align} Rs1s2=gr=r+H(R,m1)⋅sk=r+H(R,m2)⋅sk
则攻击者可按如下方式提取出私钥 s k sk sk:
s 1 − s 2 H ( R , m 1 ) − H ( R , m 2 ) = H ( R , m 1 ) ⋅ s k − H ( R , m 2 ) ⋅ s k H ( R , m 1 ) − H ( R , m 2 ) = s k ⋅ ( H ( R , m 1 ) − H ( R , m 2 ) ) H ( R , m 1 ) − H ( R , m 2 ) = s k \begin{align} \frac{s_1 - s_2}{H(R, m_1) - H(R, m_2)} &= \frac{H(R, m_1)\cdot sk - H(R, m_2)\cdot sk}{H(R, m_1) - H(R, m_2)}\\ &= \frac{sk\cdot(H(R, m_1) - H(R, m_2))}{H(R, m_1) - H(R, m_2)}\\ &= sk \end{align} H(R,m1)−H(R,m2)s1−s2=H(R,m1)−H(R,m2)H(R,m1)⋅sk−H(R,m2)⋅sk=H(R,m1)−H(R,m2)sk⋅(H(R,m1)−H(R,m2))=sk
当 m 1 ≠ m 2 m_1\ne m_2 m1=m2 且 H H H 为抗碰撞哈希函数,则以上公式中分母不为0,该攻击具有压倒性概率可成功。即使采用 σ ′ = ( e , s ) \sigma'=(e,s) σ′=(e,s)格式的Schnorr签名,该攻击也仍成立。
5.2 陷阱2:Non-canonical serialization(非规范序列化)
Non-canonical serialization(非规范序列化)陷阱在于:
- 在大多数学术论文中,并不区分group元素(或域元素)及其序列化为字节数组 二者之间的差别。
- 然而开发者在实现Schnorr签名时,必须理解这些group(或域)元素序列化以及反序列化时的陷阱:
- 以避免签名malleability(延展性)
- 以及,与其它库保持兼容。
如对Schnorr签名中的 s ∈ Z p s\in \mathbb{Z}_p s∈Zp做反序列化:
- 直白的代码将不对字节数组内所编码的正整数做检查,即是否为 < p <p <p。这样使得对于相同的 s s s有2种不同的字节表示。从而使得对 m m m的有效Schnorr签名 σ \sigma σ,可被攻击者攻击为对 m m m的另一有效但不同的Schnorr签名 σ ′ \sigma' σ′。
这样的延展性攻击,对于某些应用——假设对某消息有且仅有一个有效签名,来说,会有很大的问题。在过去,此类攻击可能被用来从(实现不当的)加密货币交易所中抽走资金,详情见2014年论文Bitcoin Transaction Malleability and MtGox。
建议:
- 开发者需确保每个group(或域)元素具有单个唯一的规范序列化表示为字节数组,且其反序列化仅接受该规范表示。
- Ristretto255为对椭圆曲线group提供规范序列化反序列化的库。
5.3 陷阱3:使用non-prime order group
陷阱3:使用non-prime order group:
- 实际上在大多数学术论文中,都作为一个重要假设:
- G \mathbb{G} G为prime-order group。
而Ed25519为最流行的Schnorr签名实现,其并不使用prime-order group。
- 其使用composite order group,其order为 h ⋅ q h\cdot q h⋅q,其中 q q q为prime 且 h = 8 h = 8 h=8 为cofactor。
- 在实际做Schnorr批量验签时,会存在单个签名可验证通过,而批量验证不通过的问题。详情见Henry de Valence 2020年10月博客 It’s 255:19AM. Do you know what your validation criteria are?。
建议:
- 在项目中,应尽量避免基于non-prime order group实现Schnorr签名(即避免Ed25519),并采用像Schnorrkel(https://github.com/w3f/schnorrkel(Rust))那样使用prime-order group的Schnorr签名变种。
6. 小结
本文介绍了Schnorr签名及其实践陷阱:
- nonce复用攻击
- 批量验签
- Schnorr签名替代格式 ( e , s ) (e,s) (e,s)
- 等等
参考资料
[1] Alin Tomescu 2024年5月31日博客 Schnorr signatures: everything you wanted to know, but were afraid to ask!
附录:ECDSA公钥恢复
ECDSA对消息 m m m的签名流程为:【详情见:ECDSA VS Schnorr signature VS BLS signature】
- 1)计算消息
m
m
m的hash值:
e
=
h
a
s
h
(
m
)
e=hash(m)
e=hash(m)。(
hash
函数可为SHA-2,输出转换为数值。) - 2)若group order n n n的bit length为 L n L_n Ln,则取 e e e值最左侧的 L n L_n Ln bits赋值给 z z z。(注意, z z z值可以比 n n n大,但bit length不能比 n n n的长。)
- 3)选择随机数 k ∈ R [ 1 , n − 1 ] k\in_R [1,n-1] k∈R[1,n−1]。(注意,不信任一般的随机数生成器,因为不好的RNG有太多的failures和vulnerabilities,可采用RFC6979 根据 p k pk pk和 m m m来计算deterministic k k k。)(如:2013年8月,安卓Bit0coin钱包因使用了错误的随机数生成器,引起私钥泄露,导致资金损失;2010年12月,索尼PS3游戏机因错误的使用了静态而不是随机的 k k k值,导致其ECDSA私钥泄露。)
- 4)计算curve point ( x 1 , y 1 ) = k × G (x_1,y_1)=k\times G (x1,y1)=k×G。
- 5)计算 r = x 1 m o d n r=x_1\mod n r=x1modn,若 r = 0 r=0 r=0,则跳转继续执行步骤3)。
- 6)计算 s = ( z + r ⋅ s k ) / k m o d n s=(z+r\cdot sk)/k \mod n s=(z+r⋅sk)/kmodn,若 s = 0 s=0 s=0,则跳转继续执行步骤3)。
- 7)最终的签名为
(
r
,
s
)
(r,s)
(r,s)。(注意,
(
r
,
−
s
m
o
d
n
)
(r,-s\mod n)
(r,−smodn)也为有效签名。)
【根据 BIP-62 可知,为了解决ECDSA签名的malleability问题,可对签名中的 s s s值进行约束,限定 s s s值不高于曲线order的一半。】
所谓ECDSA公钥恢复,是指可根据签名
(
r
,
s
)
(r, s)
(r,s)派生出公钥
p
k
pk
pk——DerivedAddress
:
ECDSA verification, P2PKH uncompressed address
- 1)Set r = DecodedSignature[1:33]. If r ≥ n or r == 0, fail verification with an error similar to “Invalid ECDSA signature parameters”.
- 2)Set s = DecodedSignature[33:65]. If s ≥ n or s == 0, fail verification with an error similar to “Invalid ECDSA signature parameters”.
- 3)Set z = SHA256(Message)
- 4)Set recID = Header AND 0x3
- 5)If recID AND 0x2 == 0, set x = r, else set x = r+n
- 6)Set x = (x^3 + 7) mod p
- 7)Set y = x^((p+1)/4) mod p
- 8)Calculate the correct parity of y using the ‘recID’:
- If (is_even(beta) and is_odd(recID)) or (is_odd(beta) and is_even(recID)), set y = p-y.
- 9)Set R = (x,y)
- 10)Set e = (-int(z)) % n
- 11)Set PublicKey = (Rs + Ge) * modinv(r, n)
- 12)Compute EncodedPublicKey = “04” || hex(x) || hex(y)
- 13)Compute AddressHash = RIPEMD160(SHA256(EncodedPublicKey)
- 14)Compute DerivedAddress = Base58Check(hex(00) || AddressHash).
- 15)If DerivedAddress == Address, succeed verification. Else fail verification with an error similar to “Wrong address for signature”.