安全多方计算与密钥协商的关系:MPC基础、协议构成、联邦学习中的融合

安全多方计算(MPC)和密钥协商,表面上看着像两件事。一个管「怎么让多个不通信用的人一起算出结果」,一个管「怎么让两个人在不安全信道上拿到同一个秘密」。但一旦进了联邦学习,这两者就彻底绑死了。

我最早做 MPC 时,觉得密钥协商就是跑个 ECDH,跟 MPC 没啥关系。直到有一次项目里,联邦学习的客户端和服务端之间用的临时密钥被中间人拿到,所有本地模型的梯度直接裸奔……嗯,从那以后我再也不敢把密钥协商当配角了。

核心观点:联邦学习中的 MPC 节点是聚合引擎,而密钥协商为这个引擎提供每条「管道」的身份认证和对称加密种子。缺了后者,前者的安全承诺就是纸糊的。

1. MPC 基础:从「百万富翁问题」到实用化

MPC 最简单粗暴的解释——你想想两个百万富翁,不想暴露自己具体有多少钱,但想知道谁更有钱。这就是 MPC 的原始版本:每个参与方拥有一个秘密输入,共同计算一个函数 f(x₁, x₂, …),得到结果的同时不泄露任何中间信息。

我习惯把 MPC 的技术路线分成三类:

  • 秘密共享 (Secret Sharing) — 将每个输入拆成碎片分给多个节点,任何少于阈值的节点组合都得不到原值。联邦学习里最常用的是 Shamir 秘密共享,我觉得它最大的好处是不需要公钥基础设施。
  • 混淆电路 (Garbled Circuits) — 将计算逻辑变成加密过的门电路,一方构造电路,另一方在不解密的情况下评估。适合两方场景,但扩展到多方通信量巨大。
  • 同态加密 (HE) — 严格来说属于 MPC 的变种,直接在密文上做加法或乘法。我在项目中试过 BFV 方案做梯度聚合,性能瓶颈在密钥生成阶段。

给个提示:做联邦学习时,别一上来就纠结 MPC 用哪种技术。先看你的安全假设——是半诚实(参与者会老实执行协议但偷看中间结果)还是恶意(参与者可能篡改消息)?联邦学习大部分场景用半诚实模型就够了,选秘密共享方案性价比最高。

2. 协议构成:一个 MPC 协议到底长什么样?

一个完整的 MPC 协议,说白了由三个层叠的阶段组成。我习惯画成一张时序图来理解:

阶段做什么密钥协商的参与点
输入阶段各方将本地秘密输入拆成份额,分发给其他节点节点间需通过密钥协商建立安全信道,防止份额被窃听
计算阶段节点在份额上执行加、乘操作(通常需要 re-sharing)各轮通信的临时对称密钥由密钥协商派生,保证信道前向安全
输出阶段节点将结果份额广播给重构方,重构出明文结果输出方的身份验证依赖密钥协商的长期公钥证书

你可以看到,密钥协商并不是 MPC 协议里的一个单独模块,而是渗透到了每个阶段的底层通信层。我见过不少新人把 MPC 协议单独拎出来写,然后配一个「随便用什么密钥协商」的借口,结果就是协议跑得通但安全边界一推就倒。

这里特别说一下安全模型的区别。半诚实模型下,密钥协商只需要保证消息的机密性和完整性,通信双方都不会故意作弊;但在恶意模型下,密钥协商必须提供「可否认认证」或者「一致性证明」,防止某个节点在密钥协商阶段自己生成的假密钥骗取其他节点的份额。我曾经踩过一次坑:用普通的 TLS 做 MPC 节点间的通信,结果恶意攻击者伪造了一个中间人,把客户端 A 的份额偷换成虚假值,最终聚合出来的模型直接崩溃。后来换成了 ACL(可认证的密钥协商)配合承诺机制,才把这个问题堵上。

注意:MPC 协议的通信轮数直接影响密钥协商的开销。如果协议需要反复多次交换份额(比如做乘法时需要 Beaver 三元组),那么密钥协商的握手频率就要精心设计。我的建议是:先做一次长期密钥协商建立长连接,然后用该连接派生短期会话密钥,而不是每轮都跑一次完整的 D-H。

3. 联邦学习中的融合:密钥协商成为桥梁

现在把 MPC 塞进联邦学习的经典架构里。典型的横向联邦学习有三个角色:客户端、聚合服务器、以及可选的 MPC 节点(通常由服务器集群承担)。

流程是这样的:

  1. 每个客户端用本地数据训练模型,得到梯度或模型参数。这一步跟 MPC 无关。
  2. 客户端将梯度加密或拆分后发送给 MPC 节点。这里的关键——加密用的密钥来自哪里? 就是通过密钥协商建立「客户端 ↔ MPC 节点」的安全信道。
  3. MPC 节点(至少 t 个以上)在密文或份额上执行安全聚合(加法或加权平均),最终重构出聚合梯度。
  4. 聚合结果返回给服务器,服务器更新全局模型,再分发给下一轮客户端。

密钥协商在这个融合架构里玩出了新花样。不止是点对点的静态密钥,联邦学习的场景经常需要群组密钥协商——所有客户端和 MPC 节点一起生成一个共同公钥,每个客户端用自己的私钥加密梯度,MPC 节点用那个公钥对应的私钥集合进行聚合。我去年在一家金融公司的项目里就用了类似方案:基于树形结构的群组密钥,把客户端数量从 50 个扩展到 500 个,性能下降还能接受。

下面这张图展示了联邦学习 + MPC 融合的基本关系:

联邦学习 + MPC 融合流程 客户端 1 客户端 2 客户端 3 本地训练 本地训练 本地训练 密钥协商 MPC 安全聚合 全局模型 模型分发(下一轮) 说明: 密钥协商节点负责生成和管理客户端与 MPC 节点之间的对称密钥,确保梯度传输的机密性和完整性。 MPC 安全聚合节点在密态下完成梯度求和或加权平均,只有最终结果才能被重构。

从图上你能看到,密钥协商的位置在客户端训练和 MPC 聚合的中间。这里有个常见的误解——有人觉得密钥协商只在「客户端-服务器」之间做一次就够了。实际上,联邦学习里每轮参与客户端可能变化,密钥协商必须支持动态成员变更。我习惯的做法是先通过公钥基础设施给每个客户端分配固定身份,然后在每轮训练开始时,用广播式的 Diffie-Hellman 协商出本轮专用的群组密钥。

一些实际的避坑经验

  • 别把密钥协商的密钥和 MPC 的秘密共享密钥混用。 我曾经试过把 ECDH 算出来的密钥直接当作秘密共享的份额种子,结果固定种子导致 MPC 的随机性被攻击者预测。分开管理,各用各的。
  • MPC 节点数量别太少。 如果只放 2 个 MPC 节点,那它们的密钥协商虽然快,但诚实方只要有一个被攻破,整个聚合就完蛋。至少设 3 个节点,配合阈值秘密分享。
  • 注意密钥的生命周期。 联邦学习的训练可能跑几个星期,密钥不能一成不变。定期轮换密钥,并在轮换时做一次「重新共享」(resharing),不然之前的份额累积到一定程度会泄露信息。

一个小技巧: 在设计通信协议时,可以把密钥协商的握手信息合并到 MPC 的每一轮消息里。比如在发送份额的同时附加一个密钥协商的临时公钥,这样能减少一次额外的消息交换。不过要小心消息长度膨胀,我在实际项目中把公钥压缩到 32 字节(curve25519),效果还行。

好了,关于 MPC 和密钥协商的关系,我把我踩过的坑和学到的经验都摊在这儿了。说白了,没有密钥协商的 MPC 就像没有锁的门——协议本身再安全,传输线路上也能被人动手脚。联邦学习里把这个关系理清楚,你的安全边界才算真正立住了。