Caloogy 文章
English

Shamir 秘密分享:把私钥拆成 n 份,任意 k 份就能还原

日期
2026 年 10 月 20 日
系列
密码学
阅读
4 分钟
主题
Secret sharingShamirLagrange interpolationThreshold

一句话版本

把秘密藏在一个 k−1k-1 次多项式的常数项 f(0)f(0) 里,发给每个人多项式上的一个点 (i,f(i))(i, f(i))。 任意 kk 个点可以用拉格朗日插值唯一确定多项式,从而还原秘密;少于 kk 个点时,秘密的每一个可能值都同样可能,一点信息都不泄露。

全文分三层:

  1. 通俗理解:两点确定一条直线
  2. 实际用处:钱包备份、MPC 钱包、门限签名、DNSSEC 根密钥
  3. 数学原理:有限域上的多项式、拉格朗日插值、完美安全性,附手算例子

第一层:通俗理解

1.1 为什么要"拆"私钥

一把比特币私钥如果只存一份:

多存几份能防丢,却让被偷的风险翻倍。我们想要的是:拆成 5 份,分给 5 个人(或 5 个地方),任意 3 份凑在一起才能还原;任意 2 份凑在一起一点用都没有。这叫 (3,5)(3, 5) 门限方案。

1.2 两点确定一条直线

先看最简单的 (2,n)(2, n) 方案:

  1. 把秘密 SS 画在 yy 轴上,即点 (0,S)(0, S);
  2. 过这个点随便画一条(随机斜率的)直线;
  3. 在直线上取 x=1,2,…,nx = 1, 2, \dots, n 处的点,每人发一个。

任意两个人把点拿出来,两点确定一条直线,延长到 yy 轴就看到了 SS。但只有一个点的人,过这个点的直线有无数条,与 yy 轴的交点可以是任何值,所以完全猜不到 SS。

要门限为 3,就把直线换成抛物线(三点确定一条抛物线);门限为 kk,就用 k−1k-1 次多项式。

1.3 和 RS 纠错码是一回事

Reed–Solomon 纠错码的做法是:把数据当作多项式系数,发送多项式在多个点上的值,丢掉一些点也能插值还原。Shamir 秘密分享用的是同一个代值映射,只是关注点不同:纠错码关心"丢了能补回来",秘密分享还额外关心"点不够时什么都看不出"。


第二层:实际用处

场景 怎么用
助记词分片备份(SLIP-39,Trezor 等硬件钱包) 把钱包种子拆成若干份助记词,比如"5 份里任意 3 份"
企业 / 交易所冷钱包 私钥分给多个高管或多个保险柜,防止单人作恶或单点丢失
MPC 钱包与门限签名 更进一步:私钥从来不在任何一处完整出现,各方用自己的份额协同算出签名(如 FROST、GG20 协议)
DNSSEC 根密钥 互联网根区签名密钥的恢复凭据分给全球多位受信任社区代表保管,需要多人到场
HashiCorp Vault 解封主密钥默认拆成 5 份、门限 3

和多签的区别

比特币多签(multisig)是链上规定"需要 3 个不同私钥的签名",规则公开可见。门限签名是链下用秘密分享,最后只产生一个普通签名,链上看起来和单人钱包一样,更省手续费、更隐私。

朴素 Shamir 的两个弱点

  1. 还原的那一刻,完整秘密会出现在某台机器上,这台机器就成了攻击目标。MPC 钱包的意义就在于连这一刻都避免。
  2. 如果发份额的人(dealer)作弊,发了不一致的份额,接收者发现不了。可验证秘密分享(Feldman / Pedersen VSS)给每个系数附上一个承诺来解决这个问题。

第三层:数学原理

3.1 在有限域里做

实数上的多项式会泄露信息(比如份额的大小能暗示秘密的范围),所以一律在有限域 Fp\mathbb{F}_p 上做,pp 是一个比秘密大的素数。

分发:秘密 S∈FpS \in \mathbb{F}_p,门限 kk。随机选 a1,…,ak−1∈Fpa_1, \dots, a_{k-1} \in \mathbb{F}_p,令

f(x)=S+a1x+a2x2+⋯+ak−1xk−1,f(x) = S + a_1 x + a_2 x^2 + \cdots + a_{k-1} x^{k-1},

第 ii 个人拿到份额 (i,f(i))(i, f(i)),i=1,…,ni = 1, \dots, n。

3.2 为什么 kk 个点能唯一确定多项式

域上一个非零的、次数不超过 k−1k-1 的多项式最多有 k−1k-1 个根(抽象代数:F[x]F[x] 是整环,因式定理)。如果两个次数 ≤k−1\le k-1 的多项式在 kk 个点上取值相同,它们的差有 kk 个根,只能是零多项式。所以唯一。

3.3 拉格朗日插值

给定 kk 个点 (xj,yj)(x_j, y_j),构造

Lj(x)=∏m≠jx−xmxj−xm,L_j(x) = \prod_{m \ne j} \frac{x - x_m}{x_j - x_m},

它在 xjx_j 处等于 11,在其他 xmx_m 处等于 00。于是 f(x)=∑jyjLj(x)f(x) = \sum_j y_j L_j(x)。我们只需要常数项:

S=f(0)=∑jyj Lj(0),Lj(0)=∏m≠j−xmxj−xm.S = f(0) = \sum_j y_j \, L_j(0),\qquad L_j(0) = \prod_{m \ne j} \frac{-x_m}{x_j - x_m}.

注意 SS 是份额的线性组合。这一点很关键:门限签名里,各方不用交出份额,只要各自算出"份额 ×Lj(0)\times L_j(0)"这一部分,再在指数或椭圆曲线点上相加即可。

3.4 为什么 k−1k-1 个份额毫无信息

固定任意 k−1k-1 个份额。对秘密的每一个候选值 S′∈FpS' \in \mathbb{F}_p,加上点 (0,S′)(0, S') 一共 kk 个点,恰好唯一确定一个多项式。所以每个 S′S' 都对应同样多(恰好一种)的系数选法,而系数是均匀随机选的,于是每个 S′S' 的概率都是 1/p1/p。

这叫信息论安全(完美安全):不依赖任何计算难题,算力再强、有量子计算机也没用。和一次一密的道理相同。

3.5 手算例子

(3,5)(3, 5) 方案,F13\mathbb{F}_{13}

秘密 S=7S = 7,随机选 a1=3a_1 = 3,a2=5a_2 = 5: f(x)=7+3x+5x2(mod13).f(x) = 7 + 3x + 5x^2 \pmod{13}.

五个份额:

ii f(i)f(i) 计算 份额
1 7+3+5=157 + 3 + 5 = 15 (1,2)(1, 2)
2 7+6+20=337 + 6 + 20 = 33 (2,7)(2, 7)
3 7+9+45=617 + 9 + 45 = 61 (3,9)(3, 9)
4 7+12+80=997 + 12 + 80 = 99 (4,8)(4, 8)
5 7+15+125=1477 + 15 + 125 = 147 (5,4)(5, 4)

用第 1、3、5 份还原:

  • L1(0)=(−3)(−5)(1−3)(1−5)=158L_1(0) = \dfrac{(-3)(-5)}{(1-3)(1-5)} = \dfrac{15}{8}。15≡215 \equiv 2,8−1≡58^{-1} \equiv 5(8⋅5=40≡18 \cdot 5 = 40 \equiv 1),所以 L1(0)=10L_1(0) = 10
  • L3(0)=(−1)(−5)(3−1)(3−5)=5−4L_3(0) = \dfrac{(-1)(-5)}{(3-1)(3-5)} = \dfrac{5}{-4}。−4≡9-4 \equiv 9,9−1≡39^{-1} \equiv 3,所以 L3(0)=15≡2L_3(0) = 15 \equiv 2
  • L5(0)=(−1)(−3)(5−1)(5−3)=38=3⋅5=15≡2L_5(0) = \dfrac{(-1)(-3)}{(5-1)(5-3)} = \dfrac{3}{8} = 3 \cdot 5 = 15 \equiv 2

S=2⋅10+9⋅2+4⋅2=46≡7(mod13).S = 2 \cdot 10 + 9 \cdot 2 + 4 \cdot 2 = 46 \equiv 7 \pmod{13}.

还原出 77。(已用 Python 验算。)


总结

层次 要点
直觉 kk 个点确定 k−1k-1 次多项式,秘密在 yy 轴截距上
代数 域上多项式根的个数有上限;拉格朗日插值;秘密是份额的线性组合
安全 少于 kk 份时信息论安全,量子计算机也无能为力
工程 钱包备份、MPC 钱包、门限签名;需要防 dealer 作弊(VSS)