钱包私钥管理方式 - 门限共享和 MPC 钱包

门限共享秘密是什么门限共享秘密(ThresholdSecretSharing,TSS)是一种密码学技术,它将一个秘密(如私钥)分割成多个碎片(Shares),并设定一个阈值(Threshold,t),只要收集到其中任意t个碎片,就能还原出原始秘密。

门限共享秘密

是什么

门限共享秘密(Threshold Secret Sharing, TSS)是一种密码学技术,它将一个秘密(如私钥)分割成多个碎片(Shares),并设定一个阈值(Threshold, t),只要收集到其中任意 t 个碎片,就能还原出原始秘密,而不足 t 个碎片则无法得知任何秘密信息。

TSS 最常用的方案是 Shamir 的秘密共享(Shamir’s Secret Sharing, SSS),基于多项式插值。 下面随我来理解下门限共享秘密是怎么起作用的。

流程图

image.png 跟随流程图走,我们用一个例子来分析门限共享秘密是怎么运作的:

假设我们有一个私钥,那么我们可以使用 Shamir 算法来将这个秘钥进行拆分成 3 片,并设定这个门限值为 2。我自己拥有一片,剩余两片分别交给 2 个我信任的亲友。

在需要使用这个私钥进行签名发起转账交易时,我们三人中的任何一个人都无法使用自己的私钥分片进行签名交易。

只有当三人中的任意两人协商好,恢复出来完整秘钥才可发起共同签名。这样保证了任一秘钥分片泄漏给第三方,都不会影响到我的资金安全。

升级版

上面的门限共享秘密,有可能存在一个问题:假如有两个人(超过门限值)联手作恶,恢复出来私钥坑我钱咋办? 那么有没有办法能解决这个问题?有的兄弟,有的。

这种门限共享秘密的方案,就是一个进阶版的方案,那就是:云端可抗秘密丢失的门限共享秘密 废话不多说,且上流程图 image.png 在这种方案中,最核心的要点就是:我们不直接对私钥分片交给别人,而是将私钥使用异或算法拆分出 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
}

image.png 可以看出,我们恢复出来的私钥和生成的私钥是一致的。

MPC 钱包

MPC 钱包(Multi-Party Computation Wallet,多方安全计算钱包)是一种不再生成或存储完整私钥的加密钱包,依赖多方协作完成签名过程,提升资产安全性并降低单点故障风险。

MPC 钱包方案相比于门限共享秘密方案来讲,最大的不同就是:MPC 系统中,私钥始终不会暴露出来。而单纯的门限共享秘密是需要恢复出来秘钥来进行签名操作的。

MPC 钱包中,签名操作是通过 MPC 方案进行局部签名,所有局部签名通过多轮和多次的交互进而合成完整签名。完整私钥始终不会被恢复出来。

话不多说,我们也是基于流程图来进行分析:

image.png

地址生成:在 MPC 钱包中,MPC 系统接收托管人的请求,经过 MPC 系统的注册,将公钥、地址给出来外部。而私钥始终没有暴露出去,并且 MPC 系统中的任一节点也是不拥有完整私钥的,仅拥有私钥的分片。

签名MPC 系统中,最重要就是签名这一步。钱包应用如果需要发送一笔交易,首先需要将这笔交易做出一个 32 字节的 message Hash ,然后将这个消息 Hash 交给 MPC 系统进行签名。MPC 系统中,经过超过 k (门限值)个节点的多轮多次的局部签名交互,然后汇总成一个签名,最终返回给到钱包层进行发起交易。

和门限秘密共享的异同点:

  • MPC 用到了门限共享秘密的 分片门限值 的概念。MPC 系统的每个节点,都拥有局部的私钥分片。但完整私钥在整个过程中不会出现,哪怕超过 k 个节点联合也无法恢复出完整的私钥。

  • MPC 系统中,也拥有门限值。也就是说,当我们请求地址生成的时候,需要全部节点都在线(因为每个节点都会分配到自己的私钥)。而当我们进行签名的时候,至少需要 k 个(门限值)个节点在线并完成多轮、多次的交互才可签名。

  • 增加节点会有什么影响? 因为每个节点都需要持有私钥分配,所以增加节点需要将私钥进行重新分片,即重新计算公钥、地址。这种操作需要涉及到资金的迁移、消耗较大,一般不进行此操作。

  • 节点宕机会有什么影响? 当节点宕机、掉线不低于 k(门限值)的时候,一般不会影响到整个签名的过程。因为签名只要求 k 个节点在线即可。如果低于 k(门限值)的时候,则需要等待节点重新上线或者重新设定门限值才可完成签名的流程。

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
shawn_shaw
shawn_shaw
web3潜水员、技术爱好者、web3钱包开发工程师、欢迎交流工作机会。欢迎闲聊、交流技术、交流工作:vx:cola_ocean