Skip to main content

DKG DKGStep3 - 整理

DKG DKGStep3

DKGStep3 中,参与者接收其他参与者的秘密分享和零知识证明,验证这些信息,并计算出最终的密钥份额和公共密钥。下面是详细的计算过程:

1. 接收并验证消息

每个参与者接收其他参与者在 DKGStep2 中发送的消息,这些消息包含了秘密分享、承诺数据和零知识证明。

for _, msg := range msgs {
// 1.
if msg.To != info.DeviceNumber {
return nil, fmt.Errorf("message sending error")
}
var data tss.KeyStep2Data
err := json.Unmarshal([]byte(msg.Data), &data)
if err != nil {
return nil, err
}
// 2. check verifiers commitment
hashCommit := commitment.HashCommitment{}
hashCommit.C = info.commitmentMap[msg.From]
hashCommit.Msg = *data.Witness
ok, D := hashCommit.Open()
if !ok {
return nil, fmt.Errorf("commitment DeCommit fail")
}
// actual chaincode = sum(chaincode)
chaincode = new(big.Int).Add(chaincode, D[0])

// 3.
verifiers[msg.From], err = UnmarshalVerifiers(curve, D[1:], info.Threshold)
if err != nil {
return nil, err
}
// 4.
// feldman verify
if ok, err := feldman.Verify(data.Share, verifiers[msg.From]); !ok {
if err != nil {
return nil, err
} else {
return nil, fmt.Errorf("invalid share for participant")
}
}
// 5.
xi.Y = new(big.Int).Add(xi.Y, data.Share.Y)

ujPoint := verifiers[msg.From][0]
point, err := curves.NewECPoint(curve, ujPoint.X, ujPoint.Y)
if err != nil {
return nil, err
}
// 6.
verify := schnorr.Verify(data.Proof, point)
if !verify {
return nil, fmt.Errorf("schnorr verify fail")
}
}

2. 累加秘密分享

每个参与者将接收到的秘密分享累加到自己的秘密分享中。

xi := info.secretShares[info.DeviceNumber-1]
for _, msg := range msgs {
var data tss.KeyStep2Data
_ = json.Unmarshal([]byte(msg.Data), &data)
xi.Y = new(big.Int).Add(xi.Y, data.Share.Y)
}

3. 计算公共密钥

每个参与者计算公共密钥。公共密钥是所有参与者的验证者的累加结果。

v := make([]*curves.ECPoint, info.Threshold)
for j := 0; j < info.Threshold; j++ {
v[j] = curves.ScalarToPoint(curve, big.NewInt(0))
for _, verifier := range verifiers {
v[j], err = v[j].Add(verifier[j])
if err != nil {
return nil, err
}
}
}

4. 验证计算的公共密钥

每个参与者验证自己计算的公共密钥是否正确。

sharePubKeyMap := make(map[int]*curves.ECPoint, info.Threshold)
for k := 1; k <= info.Total; k++ {
Yi := v[0]
tmp := big.NewInt(1)
for i := 1; i < info.Threshold; i++ {
tmp = tmp.Mul(tmp, big.NewInt(int64(k)))
point := v[i]
point = point.ScalarMult(tmp)
Yi, err = Yi.Add(point)
if err != nil {
return nil, err
}
}
sharePubKeyMap[k] = Yi
}

// check share publicKey
xiG := curves.ScalarToPoint(curve, xi.Y)
if !sharePubKeyMap[info.DeviceNumber].Equals(xiG) {
return nil, fmt.Errorf("public key calculation error")
}

5. 返回结果

最终,每个参与者返回其计算的密钥份额和公共密钥。

info.shareI = xi.Y
info.publicKey = v[0]

content := &tss.KeyStep3Data{
Id: info.DeviceNumber,
ShareI: info.shareI,
PublicKey: info.publicKey,
ChainCode: hex.EncodeToString(chaincode.Bytes()),
SharePubKeyMap: sharePubKeyMap,
}
return content, nil

总结

DKGStep3 中,每个参与者接收其他参与者的秘密分享和零知识证明,验证这些信息的有效性,并将所有的秘密分享累加起来以获得最终的密钥份额。同时,所有参与者的验证者累加起来得到公共密钥。通过这个过程,所有参与者共同生成了一个分布式的密钥对,且每个参与者只掌握密钥份额,而不是完整的私钥。

分析代码

// 公共密钥的计算
v := make([]*curves.ECPoint, info.Threshold)
for j := 0; j < info.Threshold; j++ {
v[j] = curves.ScalarToPoint(curve, big.NewInt(0))

for _, verifier := range verifiers {
v[j], err = v[j].Add(verifier[j])
if err != nil {
return nil, err
}
}
}
/*---------------------------------------------------------------------------------------------------*/
// 计算每个参与者的公共密钥份额
sharePubKeyMap := make(map[int]*curves.ECPoint, info.Threshold)
for k := 1; k <= info.Total; k++ {
Yi := v[0]
tmp := big.NewInt(1)
for i := 1; i < info.Threshold; i++ {
tmp = tmp.Mul(tmp, big.NewInt(int64(k)))
point := v[i]
point = point.ScalarMult(tmp)
Yi, err = Yi.Add(point)
if err != nil {
return nil, err
}
}
sharePubKeyMap[k] = Yi
}
// 验证公共密钥份额
xiG /*新公钥份额*/ := curves.ScalarToPoint(curve, xi.Y /*新私钥份额*/)
if !sharePubKeyMap[info.DeviceNumber].Equals(xiG) {
return nil, fmt.Errorf("public key calculation error")
}

这两个计算对应的公式是什么

在分布式密钥生成(DKG)协议中,计算公共多项式系数和每个参与者的公共密钥份额的公式可以用数学表示如下:

🔥 公共多项式系数计算

设有 nn 个参与者,每个参与者 PiP_i 提供一个验证者点集合 VijV_{ij},其中 jj 表示多项式的第 jj 项。我们需要计算公共多项式的每一项系数 vjv_j

  1. 验证者点累加公式
vj=i=1nVijv_j = \sum_{i=1}^{n} V_{ij}

其中:

  • V_ijV\_{ij} 是第 ii 个参与者提供的第 jj 个验证者点。
  • vjv_j 是公共多项式的第 jj 项系数。
v := make([]*curves.ECPoint, info.Threshold)
for j := 0; j < info.Threshold; j++ {
v[j] = curves.ScalarToPoint(curve, big.NewInt(0))

for _, verifier := range verifiers {
v[j], err = v[j].Add(verifier[j])
if err != nil {
return nil, err
}
}
}

推导公式

alt text

🔥 每个参与者的公共密钥份额计算

对于每个参与者 PkP_k,我们需要计算其公共密钥份额 YkY_k,这可以通过评估公共多项式 f(x)f(x) 在点 kk 处的值来实现。

  1. 公共密钥份额计算公式
Yk=j=0t1vjkjY_k = \sum_{j=0}^{t-1} v_j \cdot k^j

这个公式的左右乘 G 用来验证

Yk=j=0t1vjkjY_k = \sum_{j=0}^{t-1} v_j \cdot k^j

其中:

  • tt 是门限值(阈值)。
  • vjv_j 是公共多项式的第 jj 项系数。
  • kk 是参与者的编号。
  • YkY_k 是参与者 PkP_k 的公共密钥份额。
sharePubKeyMap := make(map[int]*curves.ECPoint, info.Threshold)
for k := 1; k <= info.Total; k++ {
Yi := v[0]
tmp := big.NewInt(1)
for i := 1; i < info.Threshold; i++ {
tmp = tmp.Mul(tmp, big.NewInt(int64(k)))
point := v[i]
point = point.ScalarMult(tmp)
Yi, err = Yi.Add(point)
if err != nil {
return nil, err
}
}
sharePubKeyMap[k] = Yi
}

推导公式

alt text

🔥 DKG 整个过程中参与者不知道公共多项式

alt text