Skip to main content

code ecdsa keygen proof

P1 P2 函数

P1P2 函数实际上是为了在分布式密钥生成(Distributed Key Generation,简称 DKG)过程中,对生成的密钥片段进行加密传输和验证

alt text

背景

在分布式密钥生成(DKG)过程中,多个参与方共同生成一个公钥和相应的私钥份额。每个参与方持有私钥的一部分(即私钥片段),这些片段可以组合起来生成完整的私钥。为了确保这些片段在传输和存储过程中的安全性,需要对它们进行加密和验证。

P1 函数的作用

P1 函数主要用于生成参与方 1 的私钥片段,并对其进行加密和生成相关证明,以便安全地传输给参与方 2。

具体步骤包括:

  1. 生成私钥片段:计算参与方 1 的私钥片段 x1x1
  2. 加密私钥片段:使用 Paillier 加密系统对私钥片段 x1x1 进行加密。
  3. 生成证明:生成一系列证明(如 Schnorr 证明、零知识证明等)来确保加密和私钥片段的正确性。
  4. 打包数据并发送:将加密后的私钥片段和相关证明打包成消息,发送给参与方 2。

P2 函数的作用

P2 函数主要用于接收并验证参与方 1 发送的加密私钥片段。验证通过后,计算参与方 2 的私钥片段,并确保生成的公钥与预期相符。

具体步骤包括:

  1. 接收并解析消息:接收并解析参与方 1 发送的消息,提取加密的私钥片段和相关证明。
  2. 验证证明:验证参与方 1 提供的各种证明,确保加密私钥片段的正确性。
  3. 计算私钥片段:计算参与方 2 的私钥片段 x2x2
  4. 验证公钥:验证生成的公钥是否与预期相符。
  5. 保存数据:保存验证通过的私钥片段和相关信息。

代码示例

以下是简化版的代码示例,展示了 P1P2 函数的基本流程:

// P1 函数
func P1(share1 *big.Int, paiPriKey *paillier.PrivateKey, from, to int, preParams *PreParams) (*tss.Message, error) {
// 计算私钥片段 x1
x1 := vss.CalLagrangian(curve, big.NewInt(int64(from)), share1, []*big.Int{big.NewInt(int64(from)), big.NewInt(int64(to))})
paiPubKey := &paiPriKey.PublicKey
// Paillier 加密 x1
E_x1, r, err := paiPubKey.Encrypt(x1)
if err != nil {
return nil, err
}
// 生成 Schnorr 证明
X1 := curves.ScalarToPoint(curve, x1)
proof, err := schnorr.Prove(x1, X1)
if err != nil {
return nil, err
}
// 生成零知识证明
nizkProof, err := paillier.NIZKProof(paiPriKey.N, paiPriKey.Phi)
if err != nil {
return nil, err
}
// 生成 DlnProof 和 PDLwSlackProof
dlnProof1 := zkp.NewDlnProve(preParams.H1i, preParams.H2i, preParams.Alpha, preParams.P, preParams.Q, preParams.NTildei)
dlnProof2 := zkp.NewDlnProve(preParams.H2i, preParams.H1i, preParams.Beta, preParams.P, preParams.Q, preParams.NTildei)
pdlWSlackProof, statementParams := zkp.NewPDLwSlackProve(&zkp.PDLwSlackWitness{X: x1, R: r}, &zkp.PDLwSlackStatement{
N: paiPubKey.N, CipherText: E_x1, Q: X1, G: G, H1: preParams.H1i, H2: preParams.H2i, NTilde: preParams.NTildei,
})
if pdlWSlackProof == nil || statementParams == nil {
return nil, fmt.Errorf("PDLwSlack proof fail")
}
// 打包数据并发送
p1Data := P1Data{
E_x1: E_x1, Proof: proof, PaiPubKey: paiPubKey, X1: X1, NIZKProof: nizkProof,
DlnProof1: dlnProof1, DlnProof2: dlnProof2, PDLwSlackProof: pdlWSlackProof, StatementParams: statementParams,
}
bytes, err := json.Marshal(p1Data)
if err != nil {
return nil, err
}
return &tss.Message{From: from, To: to, Data: string(bytes)}, nil
}

// P2 函数
func P2(share2 *big.Int, publicKey *curves.ECPoint, msg *tss.Message, from, to int) (*P2SaveData, error) {
if msg.From != from || msg.To != to {
return nil, fmt.Errorf("message mismatch")
}
var p1Data P1Data
if err := json.Unmarshal([]byte(msg.Data), &p1Data); err != nil {
return nil, err
}
// 计算私钥片段 x2
x2 := vss.CalLagrangian(curve, big.NewInt(int64(to)), share2, []*big.Int{big.NewInt(int64(from)), big.NewInt(int64(to))})
X2 := curves.ScalarToPoint(curve, x2)
ecPoint, err := X2.Add(p1Data.X1)
if err != nil {
return nil, err
}
if !ecPoint.Equals(publicKey) {
return nil, fmt.Errorf("public keys are not equal")
}
// 验证 Schnorr 证明
if !schnorr.Verify(p1Data.Proof, p1Data.X1) {
return nil, fmt.Errorf("schnorr signature verification error")
}
// 验证 Paillier 公钥和零知识证明
if p1Data.PaiPubKey.N.BitLen() != paillier.PrimeBits && p1Data.PaiPubKey.N.BitLen() != paillier.PrimeBits-1 {
return nil, fmt.Errorf("invalid paillier keys")
}
if !paillier.NIZKVerify(p1Data.PaiPubKey.N, p1Data.NIZKProof) {
return nil, fmt.Errorf("paillier public key error")
}
// 验证 DlnProof 和 PDLwSlackProof
if !zkp.DlnVerify(p1Data.DlnProof1, p1Data.StatementParams.H1, p1Data.StatementParams.H2, p1Data.StatementParams.NTilde) ||
!zkp.DlnVerify(p1Data.DlnProof2, p1Data.StatementParams.H2, p1Data.StatementParams.H1, p1Data.StatementParams.NTilde) ||
!zkp.PDLwSlackVerify(p1Data.PDLwSlackProof, &zkp.PDLwSlackStatement{
N: p1Data.PaiPubKey.N, CipherText: p1Data.E_x1, Q: p1Data.X1, G: G, H1: p1Data.StatementParams.H1, H2: p1Data.StatementParams.H2, NTilde: p1Data.StatementParams.NTilde,
}) {
return nil, fmt.Errorf("proof verification failed")
}
// 保存数据
return &P2SaveData{From: from, To: to, E_x1: p1Data.E_x1, X2: x2, PaiPubKey: p1Data.PaiPubKey}, nil
}

总结

  • P1 函数:负责生成并加密参与方 1 的私钥片段,同时生成一系列证明以确保其正确性,然后将这些数据发送给参与方 2。
  • P2 函数负责 接收并验证 参与方 1 发送的加密私钥片段相关证明,验证通过后计算参与方 2 的私钥片段,并确保生成的公钥与预期相符。

这些步骤共同确保了在分布式密钥生成过程中,各个参与方的私钥片段在传输和存储时的安全性和正确性。

🔥 P2 负责 接收并验证 参与方 1 发送的加密私钥片段和相关证明

P2 函数 接口了参与方 1 发送的加密私钥片段和相关证明,参与方的私钥片段是没有泄漏给参与方 2 的

P2 函数确保了参与方 1 的私钥片段在传输过程中不会泄漏给参与方 2。具体来说,P2 函数接收参与方 1 发送的加密私钥片段和相关证明,并通过验证这些加密片段和证明来确保私钥片段的正确性,而不需要实际解密或获取参与方 1 的私钥片段。

详细解释

加密与验证过程

  1. 加密私钥片段:在 P1 函数中,参与方 1 的私钥片段 x1x1 被使用 Paillier 加密系统加密成 E_x1E\_{x1}。Paillier 加密是一种同态加密方案,允许在加密数据上执行某些数学操作,而无需解密数据。

  2. 生成证明:参与方 1 生成一系列证明(如 Schnorr 证明、零知识证明等),这些证明用于验证加密片段的正确性,而不暴露实际的私钥片段。

  3. 发送数据:参与方 1 将加密后的私钥片段 E_x1E\_{x1} 和相关证明打包成消息,发送给参与方 2。

接收与验证过程

  1. 接收加密片段和证明:在 P2 函数中,参与方 2 接收参与方 1 发送的消息,提取加密的私钥片段 E_x1E\_{x1} 和相关证明。

  2. 验证证明:参与方 2 使用这些证明来验证加密片段的正确性。验证过程包括检查 Schnorr 证明、零知识证明、DlnProof 和 PDLwSlackProof 等。这些验证步骤确保了加密片段确实来自于合法的私钥片段 x1x1,而不需要解密或获取实际的私钥片段。

  3. 计算私钥片段:参与方 2 计算自己的私钥片段 x2x2,并通过验证确保生成的公钥与预期相符。

代码示例

以下是 P2 函数的简化版代码示例,展示了如何验证参与方 1 发送的加密片段和相关证明:

func P2(share2 *big.Int, publicKey *curves.ECPoint, msg *tss.Message, from, to int) (*P2SaveData, error) {
if msg.From != from || msg.To != to {
return nil, fmt.Errorf("message mismatch")
}
var p1Data P1Data
if err := json.Unmarshal([]byte(msg.Data), &p1Data); err != nil {
return nil, err
}
// 计算私钥片段 x2
x2 := vss.CalLagrangian(curve, big.NewInt(int64(to)), share2, []*big.Int{big.NewInt(int64(from)), big.NewInt(int64(to))})
X2 := curves.ScalarToPoint(curve, x2)
ecPoint, err := X2.Add(p1Data.X1)
if err != nil {
return nil, err
}
if !ecPoint.Equals(publicKey) {
return nil, fmt.Errorf("public keys are not equal")
}
// 验证 Schnorr 证明
if !schnorr.Verify(p1Data.Proof, p1Data.X1) {
return nil, fmt.Errorf("schnorr signature verification error")
}
// 验证 Paillier 公钥和零知识证明
if p1Data.PaiPubKey.N.BitLen() != paillier.PrimeBits && p1Data.PaiPubKey.N.BitLen() != paillier.PrimeBits-1 {
return nil, fmt.Errorf("invalid paillier keys")
}
if !paillier.NIZKVerify(p1Data.PaiPubKey.N, p1Data.NIZKProof) {
return nil, fmt.Errorf("paillier public key error")
}
// 验证 DlnProof 和 PDLwSlackProof
if !zkp.DlnVerify(p1Data.DlnProof1, p1Data.StatementParams.H1, p1Data.StatementParams.H2, p1Data.StatementParams.NTilde) ||
!zkp.DlnVerify(p1Data.DlnProof2, p1Data.StatementParams.H2, p1Data.StatementParams.H1, p1Data.StatementParams.NTilde) ||
!zkp.PDLwSlackVerify(p1Data.PDLwSlackProof, &zkp.PDLwSlackStatement{
N: p1Data.PaiPubKey.N, CipherText: p1Data.E_x1, Q: p1Data.X1, G: G, H1: p1Data.StatementParams.H1, H2: p1Data.StatementParams.H2, NTilde: p1Data.StatementParams.NTilde,
}) {
return nil, fmt.Errorf("proof verification failed")
}
// 保存数据
return &P2SaveData{From: from, To: to, E_x1: p1Data.E_x1, X2: x2, PaiPubKey: p1Data.PaiPubKey}, nil
}

总结

  • 加密传输:参与方 1 的私钥片段 x1x1 被加密后发送给参与方 2,确保在传输过程中不会泄漏。
  • 验证证明:参与方 2 通过验证各种证明(如 Schnorr 证明、零知识证明等)来确保加密片段的正确性,而无需解密或获取实际的私钥片段。
  • 安全性:整个过程确保了私钥片段在传输和存储过程中的安全性和正确性,避免了私钥片段的泄漏。

因此,P2 函数在验证参与方 1 发送的加密私钥片段和相关证明的过程中,确实不会泄漏参与方 1 的私钥片段。