门限共享秘密是什么门限共享秘密(ThresholdSecretSharing,TSS)是一种密码学技术,它将一个秘密(如私钥)分割成多个碎片(Shares),并设定一个阈值(Threshold,t),只要收集到其中任意t个碎片,就能还原出原始秘密。
门限共享秘密(Threshold Secret Sharing, TSS
)是一种密码学技术,它将一个秘密(如私钥)分割成多个碎片(Shares
),并设定一个阈值(Threshold, t
),只要收集到其中任意 t
个碎片,就能还原出原始秘密,而不足 t
个碎片则无法得知任何秘密信息。
TSS
最常用的方案是 Shamir
的秘密共享(Shamir’s Secret Sharing, SSS
),基于多项式插值。
下面随我来理解下门限共享秘密是怎么起作用的。
跟随流程图走,我们用一个例子来分析门限共享秘密是怎么运作的:
假设我们有一个私钥,那么我们可以使用 Shamir
算法来将这个秘钥进行拆分成 3
片,并设定这个门限值为 2
。我自己拥有一片,剩余两片分别交给 2
个我信任的亲友。
在需要使用这个私钥进行签名发起转账交易时,我们三人中的任何一个人都无法使用自己的私钥分片进行签名交易。
只有当三人中的任意两人协商好,恢复出来完整秘钥才可发起共同签名。这样保证了任一秘钥分片泄漏给第三方,都不会影响到我的资金安全。
上面的门限共享秘密,有可能存在一个问题:假如有两个人(超过门限值)联手作恶,恢复出来私钥坑我钱咋办? 那么有没有办法能解决这个问题?有的兄弟,有的。
这种门限共享秘密的方案,就是一个进阶版的方案,那就是:云端可抗秘密丢失的门限共享秘密
废话不多说,且上流程图
在这种方案中,最核心的要点就是:我们不直接对私钥分片交给别人,而是将私钥使用异或算法拆分出
head
部分和 body
部分。其中 head
部分交给云端托管,body
部分执行正常的 Shamir
拆分秘密的过程。
在恢复私钥进行签名的时候,先用逆门限共享算法恢复出来 body
部分,再使用云端上的 head
来恢复出来完整的私钥进行签名。
这种方案,持有秘密的节点作恶,哪怕超过了 2
个人(门限值),也没办法联合作恶,因为他没有云端上的 head
部分,所以没办法联合作恶恢复出私钥。
门限共享秘密常用于钱包系统中的多人控制签名的实现。因为他能保证单个人无法进行作恶签名。
门限工作秘密也经常作为 MPC
系统中的一部分而存在。MPC
系统中的私钥拆分、门限值等概念与门限共享秘密的核心是一致的。(MPC
系统我们将在后文介绍)
以下代码给定一个极简的 Shamir
门限共享算法的 Go
语言实现
import (
"crypto/rand"
"fmt"
"github.com/hashicorp/vault/shamir"
)
func main() {
// 假设你已有私钥(32字节)
originPrivKey := make([]byte, 32)
_, err := rand.Read(originPrivKey)
if err != nil {
panic(err)
}
fmt.Printf("原始私钥: %x\n", originPrivKey)
// 随机数生成 K_head(与私钥等长)
kHead := make([]byte, 32)
_, err = rand.Read(kHead)
if err != nil {
panic(err)
}
fmt.Printf("K_head(存云端): %x\n", kHead)
// K_body = K ⊕ K_head
kBody := xor(originPrivKey, kHead)
fmt.Printf("K_body: %x\n", kBody)
// 对 K_body 做门限共享(3-of-5)
shares, err := shamir.Split(kBody, 5, 3)
if err != nil {
panic(err)
}
// 假设从节点收集了3个 share 恢复 K_body
recovered, err := shamir.Combine(shares[:3])
if err != nil {
panic(err)
}
// 恢复原始私钥 = K_head ⊕ K_body
recoveredPrivKey := xor(recovered, kHead)
fmt.Printf("恢复私钥: %x\n", recoveredPrivKey)
if string(recoveredPrivKey) == string(originPrivKey) {
fmt.Println("✅ 恢复成功!")
} else {
fmt.Println("❌ 恢复失败。")
}
}
// xor 两个等长字节数组
func xor(a, b []byte) []byte {
out := make([]byte, len(a))
for i := range a {
out[i] = a[i] ^ b[i]
}
return out
}
可以看出,我们恢复出来的私钥和生成的私钥是一致的。
MPC 钱包(Multi-Party Computation Wallet,多方安全计算钱包)是一种不再生成或存储完整私钥的加密钱包,依赖多方协作完成签名过程,提升资产安全性并降低单点故障风险。
MPC 钱包方案相比于门限共享秘密方案来讲,最大的不同就是:MPC 系统中,私钥始终不会暴露出来。而单纯的门限共享秘密是需要恢复出来秘钥来进行签名操作的。
MPC 钱包中,签名操作是通过 MPC 方案进行局部签名,所有局部签名通过多轮和多次的交互进而合成完整签名。完整私钥始终不会被恢复出来。
话不多说,我们也是基于流程图来进行分析:
地址生成:在 MPC
钱包中,MPC
系统接收托管人的请求,经过 MPC
系统的注册,将公钥、地址给出来外部。而私钥始终没有暴露出去,并且 MPC
系统中的任一节点也是不拥有完整私钥的,仅拥有私钥的分片。
签名:MPC
系统中,最重要就是签名这一步。钱包应用如果需要发送一笔交易,首先需要将这笔交易做出一个 32
字节的 message Hash
,然后将这个消息 Hash
交给 MPC
系统进行签名。MPC
系统中,经过超过 k
(门限值)个节点的多轮多次的局部签名交互,然后汇总成一个签名,最终返回给到钱包层进行发起交易。
和门限秘密共享的异同点:
MPC
用到了门限共享秘密的 分片
、门限值
的概念。MPC
系统的每个节点,都拥有局部的私钥分片。但完整私钥在整个过程中不会出现,哪怕超过 k
个节点联合也无法恢复出完整的私钥。
MPC
系统中,也拥有门限值。也就是说,当我们请求地址生成的时候,需要全部节点都在线(因为每个节点都会分配到自己的私钥)。而当我们进行签名的时候,至少需要 k
个(门限值)个节点在线并完成多轮、多次的交互才可签名。
增加节点会有什么影响? 因为每个节点都需要持有私钥分配,所以增加节点需要将私钥进行重新分片,即重新计算公钥、地址。这种操作需要涉及到资金的迁移、消耗较大,一般不进行此操作。
节点宕机会有什么影响?
当节点宕机、掉线不低于 k
(门限值)的时候,一般不会影响到整个签名的过程。因为签名只要求 k
个节点在线即可。如果低于 k
(门限值)的时候,则需要等待节点重新上线或者重新设定门限值才可完成签名的流程。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!