code ecdsa sign TestEcdsaSign
流程图
好的,以下是描述你提供的代码逻辑的流程图。这个流程图使用 Mermaid 语法绘制,展示了密钥生成、BIP32 派生密钥生成和签名过程的各个步骤。
流程图解释
-
密钥生成阶段
- P1 和 P2 各自生成自己的私钥片段。
- P1 生成 Paillier 密钥对,并加载预计算参数。
- P1 生成 P1 DTO,P2 生成 P2 保存数据。
-
BIP32 派生密钥生成
- P2 使用 P2 保存数据生成 BIP32 派生密钥。
- P2 获取派生的私钥片段和公钥。
-
签名阶段
- P1 计算消息哈希值并初始化上下文。
- P2 初始化上下文。
- P1 生成并发送承诺,P2 生成并返回 Schnorr 证明和点。
- P1 验证证明并生成新的证明和承诺,P2 验证并计算加密值。
- P1 解密并计算最终签名。
通过这个流程图,可以更直观地理解两方 ECDSA 签名的具体步骤和交互过程。
为什么有 BIP32 派生密钥部分?
BIP32(Bitcoin Improvement Proposal 32)定义了一种层级确定性(Hierarchical Deterministic,HD)钱包的标准,允许从一个主密钥派生出一系列的子密钥。这种机制在多种场景下非常有用,比如生成多个地址、管理多个账户等。
在你的代码中,BIP32 派生密钥部分的存在可能有以下几个原因:
-
层级密钥管理:通过使用 BIP32,可以从一个主密钥派生出多个子密钥,从而实现层级密钥管理。这对于管理多个账户或地址非常有用。
-
增加安全性:BIP32 允许生成新的子密钥,而不需要直接使用主密钥进行签名操作,这样可以增加安全性。即使某个子密钥泄漏,也不会影响其他子密钥或主密钥的安全性。
-
灵活性和扩展性:通过 BIP32,可以方便地生成新的子密钥,适应不同的应用场景和需求。比如在多重签名方案中,可以为每个参与方生成不同的子密钥。
-
兼容性:许多加密货币钱包和协议都支持 BIP32 标准,因此使用 BIP32 可以提高兼容性和互操作性。
代码中的 BIP32 派生密钥部分
在你的代码中,BIP32 派生密钥部分的具体步骤如下:
fmt.Println("=========bip32==========")
tssKey, err := bip32.NewTssKey(p2SaveData.X2, p2Data.PublicKey, p2Data.ChainCode)
tssKey, err = tssKey.NewChildKey(996)
x2 := tssKey.ShareI()
pubKey := &ecdsa.PublicKey{Curve: curve, X: tssKey.PublicKey().X, Y: tssKey.PublicKey().Y}
流程图更新
如果我们想更新流程图以解释 BIP32 派生密钥部分的存在,可以添加一些注释来说明其目的。以下是更新后的流程图:
通过这个流程图,可以更直观地理解 BIP32 派生密钥部分的存在及其在整个签名过程中的作用。
code
func TestEcdsaSign(t *testing.T) {
p1Data, p2Data, _ := KeyGen()
fmt.Println("=========2/2 keygen==========")
preParams := &keygen.PreParams{}
err := json.Unmarshal([]byte(preParamsStr), preParams)
if err != nil {
fmt.Println("preParams Unmarshal error, ", err)
return
}
// 1.3 Paillier 密钥对生成
paiPrivate, _, _ := paillier.NewKeyPair(8)
// 1.4 P1 和 P2 初始化
p1Dto, _ := keygen.P1(p1Data.ShareI, paiPrivate, p1Data.Id, p2Data.Id, preParams)
publicKey, _ := curves.NewECPoint(curve, p2Data.PublicKey.X, p2Data.PublicKey.Y)
p2SaveData, err := keygen.P2(p2Data.ShareI, publicKey, p1Dto, p1Data.Id, p2Data.Id)
fmt.Println(p2SaveData, err)
// 2. BIP32 派生密钥生成
fmt.Println("=========bip32==========")
// 2.1 BIP32 密钥派生
// 使用 BIP32 协议生成一个新的派生密钥 tssKey。BIP32 是一种层级确定性钱包标准,允许从主密钥派生出子密钥。
tssKey, err := bip32.NewTssKey(p2SaveData.X2, p2Data.PublicKey, p2Data.ChainCode)
tssKey, err = tssKey.NewChildKey(996)
// 2.2 获取私钥和公钥
x2 := tssKey.ShareI()
pubKey := &ecdsa.PublicKey{Curve: curve, X: tssKey.PublicKey().X, Y: tssKey.PublicKey().Y}
// 3. 签名阶段
fmt.Println("=========2/2 sign==========")
// 3.1 初始化 P1 和 P2
// 3.1.1 计算消息 hello 的 SHA-256 哈希值 message
hash := sha256.New()
hash.Write([]byte("hello"))
message := hash.Sum(nil)
// 3.1.2 初始化 P1 和 P2 的上下文。
p1 := NewP1(pubKey, hex.EncodeToString(message), paiPrivate)
p2 := NewP2(x2, p2SaveData.E_x1, pubKey, p2SaveData.PaiPubKey, hex.EncodeToString(message))
// 3.2 签名步骤 1
// P1 生成一个承诺 commit。
// P2 接收 commit 并生成 Schnorr 证明 bobProof 和点 R2。
commit, _ := p1.Step1()
bobProof, R2, _ := p2.Step1(commit)
// 3.3 签名步骤 2
// P1 验证 bobProof 并生成自己的 Schnorr 证明 proof 和承诺 cmtD。
// P2 验证 proof 并计算加密的 (h + xr)/k2。
proof, cmtD, _ := p1.Step2(bobProof, R2)
E_k2_h_xr, _ := p2.Step2(cmtD, proof)
// 3.4 签名步骤 3
// P1 解密 (h + xr)/k2 并计算最终的签名 (r, s)。
r, s, _ := p1.Step3(E_k2_h_xr)
fmt.Println(r, s)
}
分析
这个代码片段展示了一个两方 ECDSA 签名的过程,其中包括密钥生成、BIP32 派生密钥生成和签名过程。以下是对代码的详细分析:
1. 密钥生成阶段
1.1 KeyGen 函数
p1Data, p2Data, _ := KeyGen()
KeyGen 函数生成两个参与方的密钥片段 p1Data 和 p2Data。这是一个分布式密钥生成的过程,确保每个参与方只知道自己的私钥片段。
1.2 预计算参数
preParams := &keygen.PreParams{}
err := json.Unmarshal([]byte(preParamsStr), preParams)
if err != nil {
fmt.Println("preParams Unmarshal error, ", err)
return
}
这里加载预计算参数 preParams,这些参数可能包括一些椭圆曲线的基点或其他预计算的值。
1.3 Paillier 密钥对生成
paiPrivate, _, _ := paillier.NewKeyPair(8)
生成一个 Paillier 密钥对,用于后续的同态加密操作。
1.4 P1 和 P2 初始化
p1Dto, _ := keygen.P1(p1Data.ShareI, paiPrivate, p1Data.Id, p2Data.Id, preParams)
publicKey, _ := curves.NewECPoint(curve, p2Data.PublicKey.X, p2Data.PublicKey.Y)
p2SaveData, err := keygen.P2(p2Data.ShareI, publicKey, p1Dto, p1Data.Id, p2Data.Id)
fmt.Println(p2SaveData, err)
keygen.P1用于初始化 P1 的上下文并生成一个 DTO(数据传输对象)。keygen.P2用于初始化 P2 的上下文并返回 P2 的保存数据。
2. BIP32 派生密钥生成
2.1 BIP32 密钥派生
tssKey, err := bip32.NewTssKey(p2SaveData.X2, p2Data.PublicKey, p2Data.ChainCode)
tssKey, err = tssKey.NewChildKey(996)
使用 BIP32 协议生成一个新的派生密钥 tssKey。BIP32 是一种层级确定性钱包标准,允许从主密钥派生出子密钥。
2.2 获取私钥和公钥
x2 := tssKey.ShareI()
pubKey := &ecdsa.PublicKey{Curve: curve, X: tssKey.PublicKey().X, Y: tssKey.PublicKey().Y}
从 tssKey 中提取私钥片段 x2 和公钥 pubKey。
3. 签名阶段
3.1 初始化 P1 和 P2
hash := sha256.New()
hash.Write([]byte("hello"))
message := hash.Sum(nil)
p1 := NewP1(pubKey, hex.EncodeToString(message), paiPrivate)
p2 := NewP2(x2, p2SaveData.E_x1, pubKey, p2SaveData.PaiPubKey, hex.EncodeToString(message))
- 计算消息
hello的 SHA-256 哈希值message。 - 初始化 P1 和 P2 的上下文。
3.2 签名步骤 1
commit, _ := p1.Step1()
bobProof, R2, _ := p2.Step1(commit)
- P1 生成一个承诺
commit。 - P2 接收
commit并生成 Schnorr 证明bobProof和点R2。
3.3 签名步骤 2
proof, cmtD, _ := p1.Step2(bobProof, R2)
E_k2_h_xr, _ := p2.Step2(cmtD, proof)
- P1 验证
bobProof并生成自己的 Schnorr 证明proof和承诺cmtD。 - P2 验证
proof并计算加密的(h + xr)/k2。
3.4 签名步骤 3
r, s, _ := p1.Step3(E_k2_h_xr)
fmt.Println(r, s)
- P1 解密
(h + xr)/k2并计算最终的签名(r, s)。
总结
这个代码片段展示了两方 ECDSA 签名的完整流程,包括密钥生成、BIP32 派生密钥生成和签名过程。在整个过程中,双方通过交换必要的加密信息和零知识证明,确保各自的私钥片段不被泄漏,同时能够生成有效的签名。