土法炼钢兴趣小组的算法知识备份

【密码学百科】秘密共享:Shamir 方案、VSS 与安全多方计算入口

文章导航

分类入口
cryptography
标签入口
#secret-sharing#Shamir#threshold#VSS#Feldman#Pedersen#proactive#MPC#threshold-signature

目录

在传统密钥管理中,一把密钥由一个人或一台机器独占保管。这种”单点信任”模型既脆弱又危险:密钥丢失意味着资产永久不可用,密钥泄露则意味着全面失守。秘密共享(Secret Sharing)正是为了消除这一单点而诞生的密码学原语——它将一个秘密拆分成若干”份额”(share),分发给不同的参与方,只有满足特定条件的参与方子集合作,才能恢复出原始秘密。从 1979 年 Shamir 与 Blakley 分别独立提出门限方案以来,秘密共享已经成为安全多方计算(MPC)、门限签名(Threshold Signature)、分布式密钥生成(DKG)以及社交密钥恢复等众多协议的基石。

Shamir 秘密共享:多项式插值与 t-of-n 门限方案

一、秘密共享的动机与模型

先看一张图,把这一节的关键关系串起来。

flowchart LR
    A[秘密] --> B[生成分片]
    B --> C[分发给参与方]
    C --> D[满足阈值]
    D --> E[重构秘密]

1.1 为什么要拆分秘密

设想一座核弹发射井需要五名军官中至少三人同时转动钥匙才能发射——这就是一种物理层面的”门限控制”。在数字世界中,对称密钥、私钥、主密钥等同样需要类似机制。单点保管面临三大威胁:第一,保管人死亡、硬件损毁导致密钥不可恢复;第二,保管人被胁迫或被入侵导致密钥泄露;第三,保管人自身作恶导致内部攻击。秘密共享通过将信任分散到多个参与方来系统性地缓解上述风险。

1.2 (t, n)-门限模型

最经典的门限模型记为 (t, n)-门限方案(threshold scheme):将秘密 s 拆分成 n 份,分发给 n 个参与方,任意 t 个或更多参与方合作可以恢复 s,而任意少于 t 个参与方即使合谋,也无法获得关于 s 的任何信息。这里 t 称为门限(threshold),n 称为总份额数。当 t = n 时,方案要求全体参与方到齐;当 t = 1 时,方案退化为简单的复制分发。实际部署中,常见配置如 (3, 5) 或 (2, 3),在可用性与安全性之间取得平衡。

1.3 一般化访问结构

门限模型是一种特殊的”访问结构”(access structure)。更一般地,访问结构 A 是参与方集合 P = {P1, P2, …, Pn} 的一个子集族,其中每个子集称为”授权集”(authorized set)。属于 A 的子集能够恢复秘密,不属于 A 的子集则不能。门限方案对应的访问结构是所有大小不小于 t 的子集。更复杂的场景可能要求”部门 A 至少两人且部门 B 至少一人”这样的混合结构。Ito-Saito-Nishizeki 在 1989 年证明了任意单调访问结构都可以实现秘密共享,尽管份额大小可能随访问结构复杂度指数增长。

1.4 安全性定义

一个理想的秘密共享方案应满足两个性质:正确性(correctness)——任何授权集都能精确恢复秘密;保密性(privacy)——任何非授权集对秘密的后验分布与先验分布完全相同,即得到零信息。在信息论安全(information-theoretic security)的框架下,这一保密性不依赖任何计算假设,即使面对计算能力无限的敌手也成立。Shamir 方案正是一个信息论安全的门限方案。值得注意的是,信息论安全要求每个份额的大小至少等于秘密的大小——这是由 Shannon 的信息论基本定理所保证的下界。直觉上,如果份额比秘密更短,那么少于 t 个份额加在一起的信息量就不足以覆盖秘密的全部熵,敌手就可能通过排除法缩小秘密的候选范围。Shamir 方案的份额大小恰好等于秘密大小,因此是这一下界意义上最优的方案。

二、Shamir 秘密共享

2.1 核心思想:多项式插值

Shamir 方案的数学基础极为优雅:一个 t-1 次多项式由 t 个点唯一确定,而仅知道 t-1 个或更少的点则无法确定多项式的任何系数。具体来说,分发者(dealer)选择一个大素数 p,在有限域 F_p 上随机选取 t-1 个系数 a1, a2, …, a_{t-1},构造多项式:

f(x) = s + a1 * x + a2 * x^2 + ... + a_{t-1} * x^{t-1}  (mod p)

其中 f(0) = s 就是要共享的秘密。分发者为第 i 个参与方计算份额 si = f(i),将 (i, si) 秘密发送给对应参与方。任意 t 个参与方拿出各自的份额,通过拉格朗日插值(Lagrange interpolation)即可恢复 f(x),进而计算 f(0) = s。而任意少于 t 个参与方面对的 t-1 次多项式有无穷多种可能(在 F_p 上恰好有 p 种),每种对应一个不同的秘密值,且等概率出现——这正是信息论安全的保证。

2.2 拉格朗日重构

给定 t 个点 {(x1, y1), (x2, y2), …, (xt, yt)},拉格朗日基函数(Lagrange basis polynomial)定义为:

L_i(x) = ∏_{j≠i} (x - xj) / (xi - xj)

恢复多项式为 f(x) = Σ_{i=1}^{t} yi * L_i(x)。在实际恢复秘密时,我们只需计算 f(0),因此可以简化:

s = f(0) = Σ_{i=1}^{t} yi * L_i(0)

其中 L_i(0) = ∏{j≠i} (-xj) / (xi - xj) = ∏{j≠i} xj / (xj - xi)。

这些拉格朗日系数可以预计算,实际重构只需 t 次乘法和 t-1 次加法(在模 p 运算下),计算效率极高。

2.3 Python 实现

以下是一个简洁但完整的 Shamir 秘密共享实现,涵盖份额生成与拉格朗日重构:

import secrets
from functools import reduce

# 使用一个足够大的素数作为有限域的模数
# 在生产环境中应选择密码学强度的素数
PRIME = 2**127 - 1  # 梅森素数 M127

def _mod_inv(a: int, p: int) -> int:
    """费马小定理求模逆:a^{-1} = a^{p-2} mod p"""
    return pow(a, p - 2, p)

def make_shares(secret: int, threshold: int, num_shares: int,
                prime: int = PRIME) -> list[tuple[int, int]]:
    """
    将 secret 拆分为 num_shares 份,任意 threshold 份可恢复。
    返回 [(x1, y1), (x2, y2), ...] 列表。
    """
    if threshold > num_shares:
        raise ValueError("门限不能超过总份额数")
    if secret < 0 or secret >= prime:
        raise ValueError("秘密必须在 [0, prime) 范围内")

    # 随机生成 t-1 个系数
    coeffs = [secret] + [secrets.randbelow(prime) for _ in range(threshold - 1)]

    def _eval_poly(x: int) -> int:
        """使用 Horner 方法求值多项式"""
        result = 0
        for coeff in reversed(coeffs):
            result = (result * x + coeff) % prime
        return result

    # 份额的 x 坐标从 1 开始(x=0 对应秘密本身)
    return [(i, _eval_poly(i)) for i in range(1, num_shares + 1)]

def reconstruct(shares: list[tuple[int, int]], prime: int = PRIME) -> int:
    """
    从任意 threshold 份份额恢复秘密 f(0)。
    使用拉格朗日插值在 x=0 处求值。
    """
    t = len(shares)
    secret = 0
    for i, (xi, yi) in enumerate(shares):
        # 计算拉格朗日基 L_i(0) = ∏_{j≠i} xj / (xj - xi)
        numerator = reduce(lambda a, b: a * b % prime,
                           (shares[j][0] for j in range(t) if j != i), 1)
        denominator = reduce(lambda a, b: a * b % prime,
                             (shares[j][0] - xi for j in range(t) if j != i), 1)
        lagrange = numerator * _mod_inv(denominator % prime, prime) % prime
        secret = (secret + yi * lagrange) % prime
    return secret

if __name__ == "__main__":
    original_secret = 123456789
    t, n = 3, 5
    shares = make_shares(original_secret, t, n)
    print(f"秘密: {original_secret}")
    print(f"方案: ({t}, {n})-门限")
    for idx, share in enumerate(shares):
        print(f"  份额 {idx+1}: ({share[0]}, {share[1]})")

    # 任取 3 份进行恢复
    subset = shares[:3]
    recovered = reconstruct(subset)
    print(f"从份额 1,2,3 恢复: {recovered}")
    assert recovered == original_secret

    # 换一组 3 份
    subset2 = [shares[0], shares[2], shares[4]]
    recovered2 = reconstruct(subset2)
    print(f"从份额 1,3,5 恢复: {recovered2}")
    assert recovered2 == original_secret

上述实现选用梅森素数 M127 = 2^127 - 1 作为模数,在实际生产中应根据秘密长度选择合适的素数。Horner 方法用于高效多项式求值,费马小定理用于模逆运算。

2.4 Shamir 方案的性质

Shamir 方案具有若干重要性质。首先是”完美性”(perfect):任何少于 t 份的份额集合对秘密的条件分布与无条件分布完全一致,泄露零比特信息。其次是”理想性”(ideal):每个份额的大小恰好等于秘密的大小,达到了信息论下界。此外,Shamir 方案天然支持”线性同态”(linear homomorphism):如果两个秘密 s 和 s’ 分别共享在同一组参与方上,那么将对应份额相加就得到 s + s’ 的合法份额——这一性质是后续 MPC 协议的关键基础。

笔者认为,Shamir 秘密共享是多项式插值这一纯数学工具最优美的密码学应用。拉格朗日插值在数学课堂上不过是一个拟合曲线的练习题,但 Shamir 用一个极其精练的洞察将它变成了强大的安全原语:t-1 次多项式被 t 个点唯一确定,却被 t-1 个点完全不约束。前半句保证了正确性——够多的份额一定能恢复秘密;后半句保证了信息论安全性——不够多的份额对秘密毫无帮助。密码学中的许多「高级」构造——门限签名、分布式密钥生成、基于秘密共享的 MPC——本质上都是在 Shamir 的这个洞察之上叠加额外的结构。理解了「多项式插值 = 门限控制」这个等式,就抓住了整个门限密码学体系的数学内核。

三、Blakley 方案与其他经典方案

3.1 Blakley 的超平面方案

与 Shamir 几乎同时,George Blakley 于 1979 年提出了基于几何的秘密共享方案。其核心思想是:在 t 维空间中,t 个不平行的超平面(hyperplane)交于唯一一点。将秘密编码为该交点的某个坐标,每个份额对应一个超平面方程。Blakley 方案虽然直观,但并非”完美”——少于 t 个超平面虽然不能确定交点,但会将秘密的可能范围缩小到一个低维子空间,从而泄露部分信息。此外,份额大小为秘密的 t 倍,不满足”理想性”。因此在实际应用中,Shamir 方案通常更受青睐。

3.2 中国剩余定理方案

Asmuth 和 Bloom 在 1983 年提出了基于中国剩余定理(Chinese Remainder Theorem, CRT)的秘密共享方案。选取一组两两互素的正整数 m0 < m1 < m2 < … < mn,使得任意 t 个 mi(i >= 1)的乘积大于 m0 乘以任意 t-1 个 mi 的乘积,则可利用 CRT 实现 (t, n)-门限共享。该方案的计算主要是模运算,在某些嵌入式场景中可能具有性能优势。

3.3 一般访问结构的实现

Ito、Saito 和 Nishizeki 在 1989 年提出了一种通用构造,能够为任意单调(monotone)访问结构实现秘密共享。其基本思路是将访问结构分解为若干门限子结构的组合,然后对每个子结构分别运行 Shamir 方案,将对应的份额拼接起来作为参与方的最终份额。这种方法的缺点是份额大小可能随访问结构的复杂度指数级增长。后续的研究——如 Benaloh-Leichter 方案——利用单调公式(monotone formula)来更紧凑地表达访问结构,但从信息论角度来看,某些访问结构不可避免地需要超线性大小的份额。

四、可验证秘密共享

4.1 恶意分发者问题

在标准 Shamir 方案中,参与方必须无条件信任分发者:如果分发者故意发送不一致的份额(即这些份额并非来自同一个 t-1 次多项式),则恢复阶段将得到错误结果,而参与方事先无法察觉。可验证秘密共享(Verifiable Secret Sharing, VSS)正是为了解决这一问题——它允许每个参与方在收到份额后独立验证其一致性。

考虑一个具体的攻击场景。在 (3, 5)-Shamir 方案中,诚实的分发者应当用同一个二次多项式 f(x) 计算五份份额。但恶意分发者可以用两个不同的多项式 f(x) 和 f’(x)(满足 f(0) != f’(0))分别给不同参与方发送份额——例如将 f(1), f(2), f(3) 发送给参与方 1、2、3,将 f’(4), f’(5) 发送给参与方 4、5。此时,参与方 {1,2,3} 恢复出秘密 f(0),而参与方 {1,4,5} 则可能恢复出完全不同的值。更恶劣的是,分发者可以精心构造 f’ 使得特定子集恢复出分发者想要的任意值——这等于分发者完全操控了恢复结果。在标准 Shamir 方案中,参与方在收到份额时无法检测这一攻击,因为单个份额看起来只是一个随机数,没有任何参照物来判断它是否「正确」。

4.2 Feldman VSS

Feldman 在 1987 年提出了第一个高效的 VSS 方案。其核心思想是利用离散对数(discrete logarithm)的单向性来公开承诺(commitment)多项式的系数,而不泄露系数本身。设 g 是一个循环群 G 的生成元,分发者在共享秘密的同时公布:

C0 = g^s,  C1 = g^{a1},  C2 = g^{a2},  ...,  C_{t-1} = g^{a_{t-1}}

每个参与方 i 收到份额 si = f(i) 后,验证:

g^{si} = C0 * C1^i * C2^{i^2} * ... * C_{t-1}^{i^{t-1}}

如果等式成立,则份额与承诺一致。Feldman VSS 的安全性基于离散对数困难假设(Discrete Logarithm Assumption)。其优点是验证过程仅需 t 次群指数运算和一次群乘法链,计算开销适中。但 Feldman VSS 的承诺方案是”计算隐藏”(computationally hiding)的——一个能计算离散对数的敌手可以从承诺中提取秘密值。

从安全性质的角度看,Feldman VSS 的承诺具有两个互补的属性。其一是「计算隐藏」:给定承诺 C0 = g^s,在离散对数困难假设下,敌手无法反推出 s 的值;但这一隐藏性并非无条件的——如果离散对数问题在未来被攻破(例如量子计算机成熟),所有历史承诺中的秘密值都将暴露。其二是「无条件绑定」(unconditionally binding):一旦分发者公布了承诺序列 C0, C1, …, C_{t-1},就唯一确定了一个多项式 f(x)(在指数意义上),分发者无法找到另一组系数产生相同的承诺——这一点不依赖任何计算假设,即使拥有无限算力也无法作弊。直觉上,Feldman VSS 用「指数函数的单向性」作为屏障:参与方可以在指数空间中验证等式是否成立,但无法穿透指数屏障还原出底层的系数值。

4.3 Pedersen VSS

Pedersen 在 1991 年提出了信息论隐藏的 VSS 方案。分发者额外选择一个随机多项式 g(x) = r + b1x + … + b_{t-1}x^{t-1},其中 r 为随机值。设 h 是群中另一个生成元(使得 log_g(h) 未知),公布承诺:

C_j = g^{a_j} * h^{b_j},   j = 0, 1, ..., t-1

每个参与方 i 收到两个值 (si, ti),其中 si = f(i), ti = g(i),验证:

g^{si} * h^{ti} = ∏_{j=0}^{t-1} C_j^{i^j}

Pedersen VSS 的承诺是完美隐藏(perfectly hiding)的,因为即使拥有无限计算能力,也无法从承诺中区分不同的秘密值。然而它是计算绑定(computationally binding)的——如果能够计算 log_g(h),分发者可以更换承诺对应的值。在大多数实际场景中,Pedersen VSS 的信息论隐藏性是更理想的选择,因为它确保了即使未来计算能力飞跃性进步,过去共享的秘密仍然安全。

将两者对比来看,Feldman 和 Pedersen 在安全性质上形成了精确的对偶关系。Feldman 的承诺是计算隐藏、无条件绑定——秘密在计算意义上安全,但承诺对多项式的约束是绝对的。Pedersen 的承诺是无条件隐藏、计算绑定——秘密在信息论意义上安全(即使量子计算机也无法从承诺中提取秘密),但承诺对多项式的约束依赖于离散对数困难假设。在实际协议设计中,如果主要威胁是外部窃听者试图从公开信息中推断秘密,Pedersen 更优;如果主要威胁是恶意分发者试图事后篡改承诺对应的值,Feldman 更优。许多现代协议(如某些 DKG 方案)同时使用两种承诺来兼得两种安全性。

4.4 异步 VSS

在异步网络(asynchronous network)中,消息可能被无限期延迟,经典 VSS 协议需要额外的广播信道和一致性协议(agreement protocol)。Cachin、Kursawe 和 Shoup 在 2002 年提出了基于门限加密的异步 VSS 方案(AVSS),在 n >= 3t + 1 的条件下实现了异步环境中的可验证秘密共享。这对区块链共识等异步场景至关重要。

4.5 份额分发、验证与恢复的完整流程

将前述各节的内容串联起来,以下流程图展示了一个完整的 (t, n)-门限秘密共享方案从分发到恢复的全生命周期:

┌───────────────────────────────────────────────────────────────┐
│                      分发者(Dealer)                          │
│                                                               │
│  1. 选择秘密 s ∈ F_p                                          │
│  2. 构造随机多项式:                                            │
│     f(x) = s + a₁x + a₂x² + ... + a_{t-1}x^{t-1} (mod p)   │
│  3. 计算 n 个份额: sᵢ = f(i),  i = 1, 2, ..., n             │
│  4.(若使用 VSS)公布承诺:                                     │
│     Feldman:  Cⱼ = g^{aⱼ}           (j = 0, ..., t-1)       │
│     Pedersen: Cⱼ = g^{aⱼ} · h^{bⱼ}  (j = 0, ..., t-1)      │
└───────┬───────────────────────────────────────────────────────┘
        │  秘密信道分发 (i, sᵢ) 给参与方 Pᵢ
        ▼
┌───────────────────────────────────────────────────────────────┐
│               各参与方 P₁, P₂, ..., Pₙ                        │
│                                                               │
│  5. 收到份额 (i, sᵢ)                                          │
│  6.(若使用 Feldman VSS)验证:                                 │
│     检查 g^{sᵢ} ≟ C₀ · C₁^i · C₂^{i²} · ... · C_{t-1}^{i^{t-1}}│
│  7.(若使用 Pedersen VSS)验证:                                │
│     检查 g^{sᵢ} · h^{tᵢ} ≟ ∏ Cⱼ^{i^j}                      │
│  8. 验证通过 → 接受份额;验证失败 → 投诉并启动争议解决         │
│  9. 安全存储份额,等待恢复请求                                 │
└───────┬───────────────────────────────────────────────────────┘
        │  当需要恢复秘密时,≥ t 个参与方提交份额
        ▼
┌───────────────────────────────────────────────────────────────┐
│                    恢复阶段                                    │
│                                                               │
│  10. 收集 t 个份额: {(x₁, s₁), (x₂, s₂), ..., (xₜ, sₜ)}    │
│  11. 计算拉格朗日系数:                                         │
│      Lᵢ(0) = ∏_{j≠i} xⱼ / (xⱼ - xᵢ)  (mod p)              │
│  12. 恢复秘密:                                                │
│      s = Σ sᵢ · Lᵢ(0)  (mod p)                              │
└───────────────────────────────────────────────────────────────┘

这一流程清晰地展示了三个阶段的分工:分发阶段由 Dealer 完成多项式构造与份额计算;验证阶段(仅在 VSS 中存在)由各参与方独立完成,确保 Dealer 的诚实性;恢复阶段由门限数量的参与方协作完成拉格朗日插值。

个人思考。 秘密共享是整个门限密码学的概念地基——门限签名、分布式密钥生成、MPC 乃至链上多签,其核心逻辑都可以追溯到「将秘密多项式化、再通过插值恢复」这一优雅的范式。但我认为,从 Shamir 到 VSS 的跳跃才是真正深刻的一步。Shamir 方案假设分发者是诚实的,这在理论上足够优美,却在现实中危险得不可接受——如果分发者可以被信任,我们为什么还要分拆秘密?VSS 的本质不是增加了更多的数学,而是回答了一个信任问题:如何在分发者本身可能作恶的前提下,仍然保证秘密共享的正确性?从这个角度看,Feldman 和 Pedersen 的贡献不仅仅是两个精巧的协议,更是一种设计哲学的转变——从「假设信任存在」到「用密码学构造信任」。

五、前摄秘密共享

5.1 移动敌手模型

标准秘密共享假设敌手在整个协议生命周期内最多腐化 t-1 个参与方。但在长期运行的系统中,敌手可能在不同时段分别腐化不同的参与方——虽然任一时刻被腐化的不超过 t-1 个,但累计可能超过 t-1 个。这就是”移动敌手”(mobile adversary)模型。在此模型下,标准方案不再安全:如果敌手先后获取了 t 个不同参与方的份额,就能恢复秘密。

前摄安全的核心动机有二。第一是「入侵恢复」(compromise recovery):即使某个参与方的份额在某个时段内被泄露,只要在下一个刷新周期完成后,泄露的旧份额就完全失效,敌手需要在同一时段内获取 t 份才能威胁秘密。第二是「长期安全」(long-term security):对于需要存续数年甚至数十年的密钥(如 CA 根密钥、冷存储密钥),参与方的人员变动、硬件老化和安全事件几乎是必然的;前摄刷新将安全假设从「整个生命周期内至多 t-1 个参与方被腐化」弱化为「任一时段内至多 t-1 个参与方被腐化」,极大地提升了方案的实际可部署性。

5.2 前摄刷新协议

Herzberg、Jarecki、Krawczyk 和 Yung 在 1995 年提出了前摄秘密共享(Proactive Secret Sharing, PSS)。核心思想是周期性地”刷新”(refresh)所有份额,使得旧份额失效,而秘密本身保持不变。刷新协议的流程如下:

  1. 每个参与方 i 生成一个随机的 t-1 次多项式 delta_i(x),满足 delta_i(0) = 0。
  2. 参与方 i 将 delta_i(j) 秘密发送给参与方 j。
  3. 每个参与方 j 将收到的所有 delta_i(j) 累加到自己的旧份额上:sj’ = sj + Σ_i delta_i(j)。

由于 Σ_i delta_i(0) = 0,新份额对应的多项式 f’(x) = f(x) + Σ_i delta_i(x) 在 x=0 处的值仍然是原始秘密 s。但新旧份额完全不同,敌手在上一周期获得的份额对新周期毫无用处。

一个完整的前摄刷新协议还需要结合 VSS 来防止恶意参与方注入错误的刷新值。完整流程如下:

  1. 生成刷新多项式:每个参与方 P_i 独立生成随机多项式 delta_i(x),满足 delta_i(0) = 0 且次数为 t-1。注意 delta_i(0) = 0 这一约束确保了刷新不改变秘密值。
  2. 分发并验证刷新份额:P_i 对 delta_i(x) 执行 Feldman VSS,即公布承诺 g^{delta_{i,1}}, g^{delta_{i,2}}, …, g^{delta_{i,t-1}}(注意不需要公布 g^{delta_{i,0}} 的承诺,因为 delta_i(0) = 0,对应承诺为 g^0 = 1)。然后 P_i 将 delta_i(j) 秘密发送给 P_j。每个 P_j 验证收到的刷新份额是否与承诺一致。
  3. 累加刷新:验证通过后,每个 P_j 计算新份额 s_j’ = s_j + Σ_i delta_i(j) mod p。
  4. 安全擦除旧份额:P_j 从内存和存储介质上彻底擦除旧份额 s_j。这一步在工程上至关重要——如果旧份额残留在磁盘上,前摄安全的理论保证将被完全架空。

5.3 前摄方案的应用

前摄秘密共享在长寿命密钥管理系统中尤为关键。例如,证书颁发机构(Certificate Authority, CA)的根密钥可能需要使用数十年;加密货币的冷存储密钥可能需要跨越人员变动。前摄刷新确保即使参与方硬件定期更换、人员轮岗,秘密依然安全。结合 VSS 技术,前摄刷新还可以检测并隔离发送错误刷新值的恶意参与方。

一个值得深思的现象是:前摄秘密共享的数学原理简洁到几乎可以用一句话概括——「各方联合生成一个零秘密的共享并加到旧份额上」——但在实际部署中却极为罕见。从工程实践来看,真正的障碍不是数学,而是运维。周期性份额刷新要求所有参与方在同一时间窗口内协调执行刷新协议,这意味着需要解决时间同步、网络可用性、旧份额的安全擦除(不仅是逻辑删除,还要防止磁盘级残留)、以及刷新失败后的回滚策略等一系列工程难题。任何一个环节出错——比如某个参与方在刷新过程中崩溃,新旧份额状态不一致——都可能导致整个秘密不可恢复。笔者认为,这正是密码学从理论到实践最典型的鸿沟:一个数学上优美、安全模型上清晰的协议,往往会被运维复杂度扼杀在部署的最后一公里。对于任何管理长寿命密钥的系统,前摄刷新都应当是默认配置而非可选功能——但这需要密码工程师像设计协议本身一样认真地设计其运维流程。

六、秘密共享与安全多方计算

6.1 从秘密共享到 MPC

安全多方计算(Secure Multi-Party Computation, MPC)的目标是让 n 个参与方在不泄露各自输入的前提下共同计算一个函数。秘密共享是实现 MPC 的两大范式之一(另一大范式是混淆电路)。基于秘密共享的 MPC 协议将每个参与方的输入共享给所有参与方,然后在份额上直接进行计算。

6.2 BGW 协议

Ben-Or、Goldwasser 和 Wigderson 在 1988 年提出的 BGW 协议是基于秘密共享的 MPC 的里程碑。利用 Shamir 方案的线性同态性,加法门(addition gate)可以本地完成——参与方将各自持有的两个输入份额相加即可。乘法门(multiplication gate)则更为复杂,因为两个 t-1 次多项式的乘积是 2(t-1) 次多项式,需要一轮交互式的”度数缩减”(degree reduction)协议将结果重新降为 t-1 次。BGW 协议在诚实多数(honest majority)条件下(即 n >= 2t + 1)实现了信息论安全的 MPC。对于乘法门密集的电路,通信复杂度为 O(n^2) 每个乘法门。

6.3 一个完整的例子:三方计算平均工资

为了将上述抽象描述具体化,考虑以下场景:Alice、Bob、Charlie 三人希望计算他们的平均工资,但不希望任何人知道其他人的具体薪资。这是一个典型的三方 MPC 问题,可以用 (2, 3)-Shamir 秘密共享直接实现。

设三人的工资分别为 a = 100, b = 200, c = 150(单位:万元)。选取素数 p = 1009,使用 (2, 3)-Shamir 方案(即一次多项式 f(x) = s + rx)。

第一步:各方共享输入。 每个参与方将自己的工资作为秘密,独立执行 Shamir 分发:

Alice (a=100): 选择随机系数 r_a=17
  f_a(x) = 100 + 17x (mod 1009)
  份额: f_a(1)=117,  f_a(2)=134,  f_a(3)=151
  → 发送 117 给自己, 134 给 Bob, 151 给 Charlie

Bob (b=200): 选择随机系数 r_b=42
  f_b(x) = 200 + 42x (mod 1009)
  份额: f_b(1)=242,  f_b(2)=284,  f_b(3)=326
  → 发送 242 给 Alice, 284 给自己, 326 给 Charlie

Charlie (c=150): 选择随机系数 r_c=73
  f_c(x) = 150 + 73x (mod 1009)
  份额: f_c(1)=223,  f_c(2)=296,  f_c(3)=369
  → 发送 223 给 Alice, 296 给 Bob, 369 给自己

第二步:本地计算。 计算平均工资等价于计算 (a + b + c) / 3。由于 Shamir 份额的线性同态性,各方可以在本地将持有的三个份额直接相加,无需任何通信:

Alice 持有: f_a(1)=117, f_b(1)=242, f_c(1)=223
  → 本地求和: s_1 = 117 + 242 + 223 = 582

Bob 持有: f_a(2)=134, f_b(2)=284, f_c(2)=296
  → 本地求和: s_2 = 134 + 284 + 296 = 714

Charlie 持有: f_a(3)=151, f_b(3)=326, f_c(3)=369
  → 本地求和: s_3 = 151 + 326 + 369 = 846

此时 (1, 582), (2, 714), (3, 846) 正是多项式 f_a(x) + f_b(x) + f_c(x) = 450 + 132x 的三个点值——其常数项 450 = 100 + 200 + 150 正是工资总和。

第三步:重构与输出。 各方公开自己的求和份额,通过拉格朗日插值恢复 f(0):

L_1(0) = (0-2)(0-3) / ((1-2)(1-3)) = 6/2 = 3
L_2(0) = (0-1)(0-3) / ((2-1)(2-3)) = 3/(-1) = -3 → 1006 (mod 1009)
L_3(0) = (0-1)(0-2) / ((3-1)(3-2)) = 2/2 = 1

f(0) = 582*3 + 714*1006 + 846*1
     = 1746 + 718284 + 846
     = 720876
     = 450 (mod 1009)

总和为 450,除以 3 得到平均工资 150 万元。整个过程中,没有任何参与方知道其他人的具体工资——Alice 持有的 (242, 223) 是 Bob 和 Charlie 秘密的随机份额,对原始值提供零信息。这正是 BGW 协议处理加法门的核心机制:Shamir 份额的加法在本地完成,因为多项式加法与点值加法是相容的。如果需要计算乘法(例如方差),则需要额外的交互轮次来执行度数缩减——这正是 BGW 协议中乘法门的处理方式。

6.4 GMW 协议

Goldreich、Micali 和 Wigderson 提出的 GMW 协议则使用”加性秘密共享”(additive secret sharing)而非 Shamir 的多项式共享。在加性共享中,秘密 s 被拆分为 n 个随机值 s1, s2, …, sn,满足 s1 + s2 + … + sn = s。加法仍然是本地操作,乘法则通过”不经意传输”(Oblivious Transfer, OT)实现。GMW 协议可以在不诚实多数的情况下工作,但安全性从信息论降级为计算安全(computational security)。

6.5 SPDZ 协议族

现代实用 MPC 协议如 SPDZ(读作”Speedz”)在预处理模型(preprocessing model)下运行:离线阶段生成大量与输入无关的”乘法三元组”(Beaver triple),在线阶段利用这些三元组高效完成乘法。SPDZ 使用加性秘密共享结合消息认证码(MAC)来保证恶意安全(malicious security),在线阶段的通信复杂度与参与方数量无关。SPDZ 的成功表明,秘密共享为基础的 MPC 在实际部署中已经具备可行性。

七、门限签名

7.1 从密钥共享到签名共享

门限签名(Threshold Signature)将签名密钥通过秘密共享分布到多个参与方,使得 t 个参与方合作才能生成有效签名,而签名在链上验证时与普通单签名无异。这对加密货币托管(custody)、分布式验证者(distributed validator)等场景具有巨大价值。

7.2 门限 BLS 签名

BLS 签名(Boneh-Lynn-Shacham)因其天然的线性结构而特别适合门限化。在 BLS 方案中,签名是消息哈希映射到椭圆曲线点后乘以私钥的结果:sigma = sk * H(m)。如果私钥 sk 通过 Shamir 方案共享,每个参与方计算”部分签名”sigma_i = sk_i * H(m),收集 t 个部分签名后通过拉格朗日插值在指数上重构完整签名:sigma = Σ L_i * sigma_i。由于椭圆曲线群上的加法与 Shamir 重构在数学上同构,BLS 门限签名无需复杂的交互式协议。以太坊 2.0 的验证者机制正是基于 BLS 门限签名。

7.3 门限 ECDSA

相比之下,ECDSA 的门限化要困难得多,因为 ECDSA 签名公式 s = k^{-1}(H(m) + r*sk) 中包含乘法和模逆运算,这些在秘密共享的份额上无法本地完成。Gennaro 和 Goldfeder 在 2018 年提出了实用的门限 ECDSA 协议(GG18),利用加法同态加密(如 Paillier)来完成关键的乘法步骤。后续的 GG20 和 CGGMP21 进一步优化了安全性和效率。门限 ECDSA 在比特币和以太坊的多方托管中得到广泛应用。

7.4 分布式密钥生成

门限签名的前提是密钥的分布式生成(Distributed Key Generation, DKG)——密钥不应由任何单一实体生成后再拆分,而应由所有参与方协作生成,使得没有任何单一参与方知晓完整私钥。经典的 Pedersen DKG 协议让每个参与方 i 运行一次 Feldman VSS,共享自选的随机值 si,最终的聚合私钥为 sk = Σ si,而公钥 pk = g^{sk} 可由所有承诺公开计算得到。Gennaro 等人在 2007 年指出 Pedersen DKG 在恶意敌手模型下存在”偏差攻击”(bias attack),并提出了改进方案。

八、密钥恢复与社交恢复

8.1 Shamir 备份

Shamir 秘密共享最直接的应用之一是密钥备份。用户将钱包助记词或主私钥拆分为 (t, n) 份,分别存放在保险箱、亲友处、律师事务所等不同物理位置。只要丢失不超过 n-t 份,就可以恢复密钥。SLIP-0039(Shamir Backup)是由 SatoshiLabs 为 Trezor 硬件钱包设计的标准化方案,使用 GF(2^8) 上的 Shamir 共享对 BIP-0039 助记词进行拆分,并增加了校验和与迭代加密层。

8.2 社交恢复

社交恢复(Social Recovery)是钱包安全领域的新兴范式。用户指定若干”监护人”(guardian)——可以是朋友、家人或机构。当用户丢失访问权限时,达到门限数量的监护人合作即可帮助用户恢复。Vitalik Buterin 是社交恢复钱包的积极倡导者。在以太坊智能合约钱包(如 Argent)中,社交恢复不直接使用 Shamir 方案,而是通过合约逻辑实现门限投票——监护人中的多数签名一笔”恢复交易”来更换钱包的签名密钥。然而底层原理与秘密共享的门限思想一脉相承。

8.3 企业级密钥托管

在企业环境中,秘密共享用于保护根证书私钥、数据库主密钥、硬件安全模块(HSM)的备份密钥等。典型部署采用 (3, 5) 或 (5, 9) 门限方案,份额由不同地理位置的管理员保管。恢复时,管理员在安全仪式(key ceremony)中各自输入份额进行重构。HashiCorp Vault 的”Unseal”机制正是基于 Shamir 秘密共享:Vault 在初始化时生成主密钥并拆分为若干 Shamir 份额,启动时需要达到门限数量的份额才能解封(unseal)数据库。Apple 的 iCloud 密钥保管库(Key Vault)同样使用门限方案来保护用户数据的加密密钥,通过将份额分布在多个 HSM 集群中防止单点失败。

九、实践与性能

9.1 有限域的选择

Shamir 方案需要在有限域上运算,域的大小必须大于 max(秘密值, n)。在实际中,常见选择包括:大素数域 F_p,其中 p 为 256 位素数(与椭圆曲线的标量域对齐,方便门限签名);扩展域 GF(2^8),适合对字节级数据逐字节共享(如 SLIP-0039);梅森素数域,如 F_{2^{127}-1} 或 F_{2^{521}-1},因为模运算可以通过位移和加法高效实现。域的选择直接影响份额大小:在 F_p 上每个份额为 log2(p) 位,在 GF(2^8) 上每个份额仅 8 位(但需要对每个字节独立共享)。

9.2 份额的存储与传输

份额的安全存储与传输是实践中的关键环节。每个份额必须独立存储在不同的安全介质上——纸质记录(如钢板刻录)、硬件令牌、HSM 或加密的云存储。份额的传输应使用端到端加密信道,如 TLS 或 Signal 协议。一个常见的工程错误是将多个份额存储在同一位置或通过同一信道传输——这会使门限方案的安全性退化。此外,份额上应附带元数据(如份额编号、门限值、方案标识符)以便恢复时正确组装。

9.3 份额更新与轮换

如前文所述,前摄秘密共享提供了份额更新机制。即使不采用完整的前摄协议,定期重新共享(resharing)也是良好的安全实践:分发者或参与方子集恢复秘密后立即用新的随机多项式重新共享,销毁旧份额。这可以应对参与方变更(如人员离职、新增成员)的场景。

9.4 性能基准

Shamir 方案的计算开销极低。在现代硬件上,对 256 位素数域的份额生成和重构可以在微秒级完成。以 Rust 实现的 vsss-rs 库为例,(3, 5) 方案的份额生成耗时约 5 微秒,重构耗时约 3 微秒。即使扩展到 (50, 100) 的大规模方案,性能仍在毫秒级。相比之下,VSS 和门限签名中的群运算(如椭圆曲线标量乘法)才是性能瓶颈。在 DKG 协议中,每个参与方需要广播 O(t) 个群元素并验证 O(nt) 个指数运算,通信与计算复杂度均为 O(n^2t)。

9.5 实际部署案例

秘密共享在工业界的部署日益广泛。Fireblocks 的 MPC 钱包使用门限 ECDSA 保护数十亿美元的数字资产;Lit Protocol 构建了去中心化密钥管理网络,利用门限 BLS 和分布式密钥生成为 Web3 应用提供密钥托管;Cloudflare 的 Geo Key Manager 使用秘密共享将 TLS 私钥拆分到全球多个数据中心,确保任何单一数据中心被入侵都不会导致密钥泄露;Signal 的 Secure Value Recovery 使用秘密共享结合 SGX 飞地来保护用户的 PIN 恢复密钥。

9.6 常见陷阱

实践中需要警惕的陷阱包括:第一,份额的随机性不足——如果多项式系数的随机数生成器有缺陷,份额之间可能存在统计关联,降低安全性;第二,错误的域参数——如果模数 p 不是素数或小于 n,方案的正确性和安全性都无法保证;第三,未验证份额一致性——在没有 VSS 的场景中,恶意分发者可以发送不一致的份额,导致不同子集恢复出不同的秘密;第四,份额泄露后未及时刷新——一旦发现某个份额可能已经泄露,应立即执行前摄刷新或重新共享。

秘密共享作为密码学最基本的构建模块之一,其影响力远超最初的”密钥拆分”用途。从 Shamir 1979 年的开创性论文到今天的门限签名钱包、分布式验证者网络和隐私计算平台,秘密共享始终处于分布式信任的核心。理解秘密共享的原理、变体和工程实践,是深入学习安全多方计算与现代密码协议不可或缺的一步。


密码学百科系列 · 第 40 篇

← 上一篇:计算复杂性与归约 | 系列目录 | 下一篇:安全多方计算

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。


By .