前边我们已经分析过了MPC的私钥生成过程,今天分析一下签名操作的整体流程。因为代码可读性问题,我们改为分析Zen Go的代码库,来学习签名的整体流程,实际上两个代码库的整体思路是一致的,所以不影响我们对整个算法对学习。
挑选参与的Party
工作开始前的第一步就是通过一个随机的操作,挑选出 t+1
个Party,来参与整体的签名操作;然后将Party对应的私钥数据等加载进来,进入真正的签名流程中。
Start
签名操作的过程总过分为了7个round,我们按照这个流程逐步来跟踪计算的过程,这个过程中,源码还涉及了大量的对各自收到消息对证明和验证工作,这里我们对这部分先不做深入探讨,只对正常流程进行分析。
Round0
生成SignKeys对象, 其中比较关键的是,通过拉格朗日公式,计算出wi
wi=ξ∗j=0∑nlagrange_basis(0,j,xj)
其中ξ 就是各方持有的ss分片;
各方的wi相加,就能得到真正的私钥,即
sk=i=0∑nwi
同时,各方分别生成随机数 ki,并通过Paillier算法加密后,生成MessageA,广播给其他各方。
Round1
在收到其他Party发送过来的MessageA之后,我们继续进行计算,因为Party之间相互持有各自的Paillier算法私钥,所以可以进行相应的同态计算。
比如,A收到B发过来的Message之后,因为A持有B的Paillier私钥,同时Message中包含的也是私钥加密之后的ki , 所以A就可以在此基础上进行进一步计算,根据Paillier公式的原理,A进行了如下操作:
mγb=kb∗γa+taga
其中 γa 是A生成的一个随机数,tag也是计算过程中的随机数,这个随机数很重要,保证了各方都无法单独还原出私钥等敏感信息。
同理
mwb=kb∗wa+taga
各方均进行此计算,并将结果通过P2P返回给发送方;
Round2
在收到其他各方返回的消息之后,各个Party对消息进行进一步的处理
δi=j=0∑nmγj−i=0∑ntagij=j=0∑nki∗γj−i=0∑ntagij=ki∗γ−rand
其中
γ=i=0∑nγi
同理可得
σi=ki∗w−i=0∑ntagij=ki∗sk−rand
这里的随机数很重要,如果没有此随机数,则sk可以被直接破解。同时,σi 相加,又可以把这里的随机数消除掉,具体的实现需要看一下代码,比较绕。
将δi 广播给其他各方。
Round3
δ_inv=∑i=0nδi1=δ1
Round4
R=i=0∑n(γi∗G)∗δ_inv=δγ∗G=k∗γγ∗G=k1∗G
其中γi∗G 是通过各方消息广播收到的,因为是*G之后的值,所以并未泄露任何信息。
这里的R,也就是ECDSA签名中用到的r的完整形态。
Round5/Round6
这两个轮次里,主要是在做一些参数证明和验证,我们暂不深入探讨;到这里之后,我们就已经具备了进行签名计算的所有要素,然后我们进入最后一个Round
Round7
这里拿到用户的输入message,进行局部签名计算,得到
si=Hash(message)∗ki+R.x∗σi
相互交换彼此的si后,
s=i=0∑nsi=H(m)∗k+R.x∗σ=H(m)∗k+R.x∗k∗sk=k∗(H(m)+R.x∗sk)
最后(s, R.x) 即为签名信息。