背景: 在之前的加密货币安全基石: MTA协议在Ecdsa门限签名的应用(计算签名中的r) 中,我向大家展示了MTA协议如何拆分Ecdsa门限签名中的r.在这篇文章中,我将在上篇文章基础更进一步, 讲解MTA协议如何计算Ecdsa门限签名中的s. 看完本文章, 你将彻底理解Ecdsa门限签名的秘密。
需要你有一些密码学, 加密货币, 区块链的前置知识:
- 使用 golang 实现一个极简的 区块链
- 加密货币安全基石:直观理解ECC椭圆曲线加密算法
- 加密货币安全基石:从ECC到ECDSA椭圆曲线签名
- 加密货币安全基石: 从拉格朗日插值到shamir共享密钥算法
- 加密货币安全基石: 从Shamir到Feldman VSS算法, 以币安tss-lib库为例
- 加密货币安全基石: 详解 Paillier 同态加密并使用币安tss-lib库
- 加密货币安全基石: 分布式密钥生成协议(GG18, 币安tss-lib keygen部分)
- 加密货币安全基石: MTA协议在Ecdsa门限签名的应用(计算签名中的r)
回顾 ECDSA 签名
ECDSA 的详细原理中我之前的加密货币安全基石:从ECC到ECDSA椭圆曲线签名 中有详细介绍, 这里我们简单回顾一下即可。
定义 G为椭圆曲线 起点, g 为循环群, 私钥 为 d, 公钥Q=dG, n 为 一个大质数, 被签名的原文为 M , 其中 G,Q,M,n 公开, d 为签名方严格保密 签名过程如下:
- 对原文进行取哈希操作, 令 <math xmlns="http://www.w3.org/1998/Math/MathML"> z = h a s h ( M ) z = hash(M) </math>z=hash(M)
- 从 <math xmlns="http://www.w3.org/1998/Math/MathML"> [ 1 , n − 1 ] [1,n-1] </math>[1,n−1] 范围内选一个随机数 k, 计算终点 <math xmlns="http://www.w3.org/1998/Math/MathML"> R = ( k − 1 ) G = g ( k − 1 ) R = (k-1)G = g^{(k^{-1})} </math>R=(k−1)G=g(k−1), R 的 横坐标记为 r
- 计算 <math xmlns="http://www.w3.org/1998/Math/MathML"> s = k − 1 ( z + r d ) m o d n s = k^{-1} (z+rd) mod n </math>s=k−1(z+rd)modn, 其中 <math xmlns="http://www.w3.org/1998/Math/MathML"> k − 1 k^{-1} </math>k−1 为 <math xmlns="http://www.w3.org/1998/Math/MathML"> k m o d n k mod n </math>kmodn 的逆元
- 最终签名由两部分组成 <math xmlns="http://www.w3.org/1998/Math/MathML"> s i g n = ( r , s ) sign = (r, s) </math>sign=(r,s)
明白了如何拆分r和s 也就明白了如何进行ecdsa门店签名, 在上一篇文章中我们着重讲解了如何拆分r, 这篇文章着重讲解如何拆分s。
为了简略,我们将 <math xmlns="http://www.w3.org/1998/Math/MathML"> s = k − 1 ( z + r d ) m o d n s = k^{-1} (z+rd) mod n </math>s=k−1(z+rd)modn 简化成 <math xmlns="http://www.w3.org/1998/Math/MathML"> s = k ( z + r d ) s = k (z+rd) </math>s=k(z+rd), 其中 k为随机数, d为完整私钥。
回顾 MTA 协议
MTA 协议 是一种秘密交换协议. 需要两个参与方, 命名为 Alice 和 Bob。 其中Alice 拥有 Paillier 公私钥对, 拥有 秘密值 a. Bob 拥有 秘密值 b 和随机数 <math xmlns="http://www.w3.org/1998/Math/MathML"> β ′ \beta ' </math>β′ .
MTA协议可以做到在 Alice 不泄露 a 的情况下, 在 Bob 不泄露 b 的情况下, 让 Alice得到一个数 <math xmlns="http://www.w3.org/1998/Math/MathML"> α \alpha </math>α , 让 Bob 得到一个数字 <math xmlns="http://www.w3.org/1998/Math/MathML"> β \beta </math>β 使得下列等式成立:
<math xmlns="http://www.w3.org/1998/Math/MathML"> α + β = ξ = a b ( m o d q ) \alpha + \beta = \xi = ab (mod q) </math>α+β=ξ=ab(modq)
也就是 Alice 与 Bob 在彼此不泄露各自秘密a和b的情况下得到 <math xmlns="http://www.w3.org/1998/Math/MathML"> α \alpha </math>α 和 <math xmlns="http://www.w3.org/1998/Math/MathML"> β \beta </math>β 使得上式成立
回顾 拉格朗日 插值法
给定k个点, 拉格朗日插值法可以拟合一个多项式把这k个点穿起来。 更进一步, 给定k+1个点, 拉格朗日插值法可以唯一确定一个 k 次多项式穿过这k个点。
我们知道两点(不重合)唯一确定一条直线, 3点(不重合)确定一条抛物线,以此类推,k+1个点唯一确定一个 k次多项式。 拉格朗日插值法就是可以唯一确定这 k-1 个多项式。
拉格朗日插值数学表达式
给定二维坐标上 k+1 个点:
<math xmlns="http://www.w3.org/1998/Math/MathML"> ( x 0 , y o ) , ( x 1 , y 1 ) , . . . , ( x k , y k ) (x_0,y_o), (x_1,y_1),...,(x_k, y_k) </math>(x0,yo),(x1,y1),...,(xk,yk)
可以唯一确定的 k 次项表达式为:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> L ( x ) = ∑ j = 0 k y j l j ( x ) L(x)= \sum_{j=0}^{k} y_j l_j(x) \newline </math>L(x)=j=0∑kyjlj(x)
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> l j ( x ) = ∏ i = 0 , i ≠ j k x − x i x j − x i l_j(x)= \prod_{i=0, i\ne j}^{k} \frac{x-x_i}{x_j-xi} </math>lj(x)=i=0,i=j∏kxj−xix−xi
举个例子
令 k =1 , 给定2个点可以唯一确定一次多项式
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> ( x 0 , y o ) = ( 1 , 3 ) ( x 0 , y o ) = ( 2 , 3 ) (x_0,y_o) = (1,3) \newline (x_0,y_o) = (2, 3) \newline </math>(x0,yo)=(1,3)(x0,yo)=(2,3)
此时 有
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> L ( x ) = ∑ j = 0 k y j l j ( x ) = ∑ j = 0 1 y j l j ( x ) L(x)= \sum_{j=0}^{k} y_j l_j(x) = \sum_{j=0}^{1} y_j l_j(x) </math>L(x)=j=0∑kyjlj(x)=j=0∑1yjlj(x)
其中:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> 当 j = 0 , l 1 ( x ) = ∏ i = 0 , i ≠ 0 k x − x i x j − x i = x − x 1 x 0 − x 1 = x − 2 1 − 2 当 j = 1 , l 1 ( x ) = ∏ i = 0 , i ≠ 1 k x − x i x j − x i = x − x 0 x 1 − x 0 = x − 1 2 − 1 当 j = 0, l_1(x) = \prod_{i=0, i\ne 0}^{k} \frac{x-x_i}{x_j-xi} = \frac{x-x_1}{x_0-x1} = \frac{x-2}{1-2} \newline 当 j = 1, l_1(x) = \prod_{i=0, i\ne 1}^{k} \frac{x-x_i}{x_j-xi} = \frac{x-x_0}{x_1-x0} = \frac{x-1}{2-1} \newline </math>当j=0,l1(x)=i=0,i=0∏kxj−xix−xi=x0−x1x−x1=1−2x−2当j=1,l1(x)=i=0,i=1∏kxj−xix−xi=x1−x0x−x0=2−1x−1
我们将上述的 2个式子乘上对应的y相加, 就得到了:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> L ( x ) = y 0 l 0 ( x ) + y 1 l 1 ( x ) = 2 ⋅ x − x 1 x 0 − x 1 + 3 ⋅ x − x 0 x 1 − x 0 = − 2 ( x − 2 ) + 3 ( x − 1 ) = x + 1 L(x) = y_0 l_0(x) + y_1 l_1(x) \newline = 2 \cdot \frac{x-x_1}{x_0-x1} + 3 \cdot \frac{x-x_0}{x_1-x_0} \newline = -2(x-2)+ 3(x-1) = x + 1 </math>L(x)=y0l0(x)+y1l1(x)=2⋅x0−x1x−x1+3⋅x1−x0x−x0=−2(x−2)+3(x−1)=x+1
推导如何计算 s
<math xmlns="http://www.w3.org/1998/Math/MathML"> s = k ( z + r d ) = k z + k r d s = k (z+rd) = kz + krd </math>s=k(z+rd)=kz+krd,
其中z也就是被签名的哈希, 对于每一个party都是已知的,d 为完整私钥。
假设有两个参与方, <math xmlns="http://www.w3.org/1998/Math/MathML"> k = k 0 + k 1 , d = d 0 + d 1 k = k0+ k1, d = d0+ d1 </math>k=k0+k1,d=d0+d1,
<math xmlns="http://www.w3.org/1998/Math/MathML"> s = k 0 z + k 1 z + r k d s = k0z +k1z + rkd </math>s=k0z+k1z+rkd, 其中 k0z, k1z 可以有 party0 和 party1 各自计算, r在上一篇已经讲解如何计算了。剩下的任务就是计算 <math xmlns="http://www.w3.org/1998/Math/MathML"> k d kd </math>kd.
完整私钥 <math xmlns="http://www.w3.org/1998/Math/MathML"> d d </math>d也就是拉格朗日曲线在 x=0时候的y,也就是
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> d = L ( x ) = y 0 l o ( x ) + y 1 l 1 ( x ) = 2 ⋅ x − x 1 x 0 − x 1 + 3 ⋅ x − x 0 x 1 − x 0 d= L(x)=y_0l_o(x)+y_1l_1(x) \newline = 2 \cdot \frac{x-x_1}{x_0-x1} + 3 \cdot \frac{x-x_0}{x_1-x_0} </math>d=L(x)=y0lo(x)+y1l1(x)=2⋅x0−x1x−x1+3⋅x1−x0x−x0
对于所有party来说,彼此的x坐标都是已知的。所以d的计算在于不泄露各自的y。
我们令
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> d = L ( x ) = y 0 l o ( x ) + y 1 l 1 ( x ) = w o + w 1 d= L(x)=y_0l_o(x)+y_1l_1(x) = w_o+w_1 </math>d=L(x)=y0lo(x)+y1l1(x)=wo+w1
则
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> k d = ( k 0 + k 1 ) ∗ ( w o + w 1 ) = k 0 w 0 + k 1 w 0 + k 0 w 1 + k 1 w 1 kd = (k_0+k_1)*(w_o+w_1) \newline = k_0 w_0+k_1 w_0+k_0 w1+k1 w1 </math>kd=(k0+k1)∗(wo+w1)=k0w0+k1w0+k0w1+k1w1
其中 <math xmlns="http://www.w3.org/1998/Math/MathML"> w 0 w 0 w_0 w_0 </math>w0w0可以由party0独自计算, <math xmlns="http://www.w3.org/1998/Math/MathML"> w 1 w 1 w_1 w_1 </math>w1w1可以由party1独自计算
最终计算s的问题只剩下 party0不泄露自己的 <math xmlns="http://www.w3.org/1998/Math/MathML"> k 0 k0 </math>k0, <math xmlns="http://www.w3.org/1998/Math/MathML"> w 0 w_0 </math>w0, party1不泄露自己的 <math xmlns="http://www.w3.org/1998/Math/MathML"> k 1 k1 </math>k1, <math xmlns="http://www.w3.org/1998/Math/MathML"> w 1 w_1 </math>w1 计算出 <math xmlns="http://www.w3.org/1998/Math/MathML"> k 1 w 0 + k 0 w 1 k_1 w_0+k_0 w1 </math>k1w0+k0w1.
眼尖的同学已经看出来了, 可以使用MTA协议进行秘密交换, 将乘法秘密转化成加法秘密从而得到 <math xmlns="http://www.w3.org/1998/Math/MathML"> k 1 w 0 k_1 w_0 </math>k1w0 和 <math xmlns="http://www.w3.org/1998/Math/MathML"> k 0 w 1 k_0 w1 </math>k0w1
总结
自此我们已经完整推导出来了ecdsa门限签名从分布式密钥生成和门限签名的完整过程。从接触这个算法, 到大致梳理完全部流程, 足足花了我半年时间, 可以说是非常的不容易。欢迎大家点赞, 收藏, 关注, 评论。
有了这些知识, 相信你自己去慢慢看 币安的 tsslib 签名部分的源码也能大概看懂了。