想象一个火锅店后厨,五个大厨都想联合研发一款招牌汤底。每位大厨手里有一种秘密配料的数量,比如“我放了几克辣椒”“我放了几克花椒”。他们愿意一起算出汤底的最终总量,但谁都不想把自己的数字亮给其他人。没有裁判,没有监控,怎么才能放心地把自己的配料数字“交出去”?这正是安全多方计算(MPC)要解决的问题。SPDZ 协议给出了一套巧妙的方案:大厨们先把所有配料数字打散成碎片,再提前批量制备一批“魔法调料包”,等到真正下锅时只需要拆包、倒入、搅拌,整个过程透明却又保密。如果有人想偷偷换包下毒,贴在调料包上的防伪标签会立刻破裂,全员马上喊停。这套“先备料、再下锅、带防伪”的流程,让 SPDZ 成为支持恶意安全的安全多方计算代表性协议。
理解 SPDZ 协议,你就能看懂隐私计算中最“硬核”的一环:如何在没有可信裁判的情况下,仍然让多方数据联合计算而不泄露原始数据。这是隐私计算工程师、密码学工程师和数据安全架构师的核心竞争力。
可视化演示
动态演示SPDZ协议的核心机制,通过源头/管道/节点/终端四种模式展示关键概念与交互流程。
本节配有交互动效(进入视口后自动加载,约 3KB)。
SPDZ协议:SPDZ SPDZ协议的定位与恶意安全目 带MAC的加性秘密共享 核心机制可视化 SPDZ协议整体架构与关键组件
SPDZ诞生背景
火锅店后厨的墙壁上贴着一张“无人监工”的规矩:五个大厨可以合作研发汤底,但谁也不能偷看别人的配方。没有裁判,这意味着每个人既可能是帮手,也可能是卧底。安全多方计算要做的,就是在这群“既合作又提防”的人之间,找到一个共同计算目标,却不暴露任何私有输入的方案。SPDZ 正是一套把这个问题变成现实的高效协议。
“多方安全计算”听起来像学术黑话,拆开看却很朴素:多个参与方各自拿着私密数据,想一起算一个函数,比如“求所有配料的总重量”。最终,大家只得到结果,却谁也看不到别人输入。SPDZ 在密码学上的贡献,是进一步承诺“即便参与者中有人故意作恶,也偷不到任何秘密”——我们称这种能力为恶意安全。
SPDZ 属于隐私计算领域的重要实现,它把整个任务分成两个阶段:离线预处理和在线计算。离线阶段像提前切菜、拌料,不关心这次到底要做什么汤;在线阶段才真正根据大家的输入开火下锅。整个协议有严格的安全证明:无论敌手采用什么恶作剧,协议要么给出正确结果,要么中止,绝不会泄露额外信息。
这就像五位大厨把各自配料交给一个看不见的“联合锅”,锅只吐出一锅汤,却不说每份配料是多少。SPDZ 的任务,就是制造这样一口让人放心的“联合锅”。
- 私有输入每位参与方都拥有一个属于自己的私密数字,这个数字不能直接给别人看。
- 共同函数所有人想一起计算某个函数,可以把它想象成一条“汤底配方规则”。
- 最终输出函数把所有输入混合后,产生一个公开的最终结果。
秘密共享基础
要做出这口“联合锅”,第一步不是炖汤,而是把秘密“打散”。大厨不会直接把“30克辣椒”写在纸上,而是把 30 拆成三个数,例如 10、15、5,分别装进三个碗,每个碗单独看起来都只是一堆普通数字,必须把三个碗加在一起才等于 30。这就是秘密共享的直觉。
SPDZ 的秘密共享采用加法形式:秘密值 \(x\) 被拆成 \(n\) 个碎片 \(x_1, x_2, \dots, x_n\),分给 \(n\) 个参与方。任何单独一个碎片都不含有效信息,只有把全部碎片相加,才能恢复出原秘密。为了让数学封闭,所有运算都在一个很大的素数 \(p\) 构成的有限域上进行,你可以把 \(p\) 想象成一个“循环大表盘”,数字加到 \(p\) 就会从头开始绕圈。
这种“打散”方式还有一个额外好处:碎片支持加法同态。两个秘密的碎片分别相加后,再把和恢复出来,正好等于两个秘密相加的结果。这为后面高效应付加法运算打下了基础。
用火锅来想:一勺盐分成三个小杯,每个小杯尝不出咸味;只有三个小杯同时倒进汤锅,咸度才出来。秘密共享,就是这种“把咸味藏在多个杯子里”的数学版本。
- 随机前 n-1 个碎片先随手生成 \(n-1\) 个随机数,作为前几个碎片。
- 补出最后一个碎片用秘密值减去前面所有随机碎片,得到最后一个碎片。
- 恢复秘密把全部碎片相加,取模后即可还原原值。
离线预处理
真正的 SPDZ 协议之所以高效,是因为它把最重的密码学准备工作放到了“客人还没来”的时候。大厨们在后厨提前批量制作魔法调料包:每个调料包里有三个随机数字 \(a\)、\(b\) 和 \(c\),并且满足 \(c = a \times b\)。这样的调料包叫 Beaver 三元组。等真正需要算乘法时,大厨只需拆开调料包,用它遮住真实输入,就能快速完成计算。
离线预处理阶段与真实输入完全无关。无论最后要算的是辣椒总量还是花椒总量,提前生成的调料包都一样能用。因此,系统可以在空闲时大量制备,把昂贵但耗时的密码学操作囤起来;到了在线计算阶段,就只剩拆包、对暗号、搅拌这些轻量动作。
需要注意的是,三元组本身也是秘密。\(a\)、\(b\)、\(c\) 不能直接出现在黑板或聊天群里,它们同样要被拆成碎片分给所有人。离线阶段还同时生成 MAC 密钥,这相当于给每个调料包贴上防伪标签,供后面查验有没有人偷换。
离线阶段就像一个中央厨房,提前把成千上万个“c = a×b”的调料包封好。等到真正做菜时,大厨们只管拆包,而不必在顾客面前现场磨香料。
- 随机挑选 a从有限域里随机选一个数,作为调料包的第一味料。
- 随机挑选 b独立随机选另一个数,作为第二味料。
- 计算 c令第三个数等于前两个相乘,形成三元组。
在线计算
客人点单后,在线计算阶段正式登场。这个阶段里,加法和乘法都变得十分轻快。先看加法:秘密共享的碎片是逐位相加的,每个参与方只需在自己的碎片上做本地加法,不需要和任何人通信,最后打开结果即可。
乘法稍微复杂一点。假设大家要算两个共享值 \(x\) 和 \(y\) 的乘积,手边正好有一个 Beaver 三元组 \((a, b, c)\)。首先,所有人共同打开遮蔽后的差值 \(d = x - a\) 和 \(e = y - b\)。因为 \(a\)、\(b\) 是随机数,所以 \(d\)、\(e\) 不会泄露 \(x\)、\(y\) 的信息。然后,每个参与方在本地把碎片重新组合,得到乘积的碎片:
这可以理解成:用调料包遮住真实食材,再通过公开差值完成乘法。整个过程不需要昂贵的公钥加密,只有一次公开打开和一次本地线性组合,所以在线阶段非常快。
把这一幕放回火锅店:大厨们已经提前备好了“数学调料包”,真正做菜时只需当众倒出两个小差值,然后各人把各自的碗一拌,结果自然出来。外人看到的只是差值,真正的秘方依然安全。
- 打开差值 d把 \(x\) 的碎片和 \(a\) 的碎片分别恢复,再相减,得到公开的 \(d = x - a\)。
- 打开差值 e同理得到公开的 \(e = y - b\)。
- 本地组合乘积碎片每个参与方用自己持有的 \(c, b, a\) 碎片计算自己的结果碎片。
- 加入常数项由某一个参与方把公开常数 \(d \times e\) 加进自己的碎片,完成整个乘法。
恶意安全
只有速度还不够,SPDZ 还要提防“坏厨子”趁着搅汤时偷换调料。为此,每个共享值旁边都会贴上一张数学防伪标签,叫作消息认证码(MAC)。每个秘密值 \(x\) 都对应一个标签,由一把全局密钥 \(\alpha\) 和一个随机偏移 \(\beta\) 共同决定:
当有人想要打开某个值时,所有参与方同时公开自己的碎片和 MAC 碎片。如果大家拼出来的标签对不上,说明一定有人篡改过数据。这个时候,协议不会继续输出错误结果,而会立刻中止,像火锅店发现假调料包后直接倒掉整锅汤,谁也别想喝。
MAC 机制的关键在于“检测”:它可以发现恶意行为,并阻止错误结果产生,但并不承诺能精准指认是谁下了黑手。这就好比防伪标签能告诉你“这包料被换过”,却不一定会拍下换料人的脸。尽管如此,恶意参与者仍然无法偷走任何人的秘密,因为在数据打开之前,所有碎片都已经过随机掩码和标签保护。
这就像每一份魔法调料包除了内容物,还附带一张无法仿造的防伪贴纸。一旦有坏厨子偷偷拆开换料,贴纸立刻破裂,全厨房警铃大作,大家宁可这次合作流掉,也不接受被污染的结果。
- 全局密钥 alpha系统预先选择一个随机密钥,像打印机里的防伪版纹。
- 随机偏移 beta为每个共享值额外选一个随机偏移。
- 计算标签用密钥和偏移对共享值加密生成 MAC 标签。
- 校验结果当秘密被打开时,所有人把碎片拼起来重新计算标签;不一致就中止。
对比与局限
SPDZ 并不是市场上唯一的菜谱。早期的 GMW、BGW 等协议更像是“君子协定”:它们假设所有参与者都会照着规则来,顶多是“好奇但守规矩”的半诚实敌手。而 SPDZ 考虑的是“可能使坏”的恶意敌手,安全性更强,代价也更贵。
把两种安全模型写成公式可以更清楚:半诚实安全只要求存在一个模拟器,让每个参与者无法从自己的视角区分真实执行和模拟执行;恶意安全则要求无论敌手怎样偏离协议,模拟器都能模拟整个过程,且真实世界与理想世界不可区分:
因为 SPDZ 要同时对抗“偷看”和“捣乱”,它必须付出额外的预处理开销。Beaver 三元组和 MAC 密钥的生成都需要大量随机性和密码学计算,不能免费获得。因此,SPDZ 特别适合“一批数据反复计算”或“在线响应要快”的场景,却不太适合只需要跑一次、且对延迟不高的小型任务。
回到火锅店:SPDZ 不是最便宜的下厨方式,因为要提前买防伪设备、准备大量调料包。但如果这桌客人里有间谍,这套设备就能派上大用场。安全升级,自然要付成本。
- 真实世界敌手 \(\mathcal{A}\) 实际运行协议,可能随时搞小动作。
- 理想世界所有输入交给一个可信函数 \(f\) 直接计算,模拟器 \(\mathcal{S}\) 代替敌手对外发言。
- 不可区分两个世界的输出分布近似相同,敌手察觉不到自己到底在哪个世界。
AI 应用场景
银联黑名单跨行联合查询
阶段:联合统计 / 数据安全融合
解决的问题:多家银行各自掌握欺诈账户名单,想共同找出同一批高风险人群,但又不能直接交换客户名单,否则会违反数据隐私法规。SPDZ 让各方把名单哈希后进行安全求交与统计,最终只得到交集数量,无法反推其他银行名单。
具体案例:三家中型银行怀疑某团伙在多个银行开户洗钱。通过 SPDZ 协议联合执行多方计算,它们在几秒内确认了 127 个共同可疑账户,同时每家银行都没有看到其他银行的客户名单。
多中心医疗临床试验统计
阶段:多中心数据聚合 / 统计建模
解决的问题:多家医院希望联合统计某种新药对患者的疗效指标,但患者隐私数据不允许离开医院。SPDZ 可以用秘密共享把统计所需的均值、方差、相关系数等中间结果安全组合起来,避免任何一方掌握完整患者记录。
具体案例:五家三甲医院联合观察 2000 名患者数据,使用 SPDZ 完成安全求和与均值计算,生成疗效统计报告,全程未传输任何原始病历字段。
联邦学习中的安全梯度聚合
阶段:模型训练 / 梯度聚合
解决的问题:纵向联邦学习中,不同机构拥有同一批用户的不同特征,需要聚合梯度更新模型,但梯度也可能反推原始数据。SPDZ 的在线乘法可以支持安全聚合、安全求平均,让各方只能拿到更新后的模型参数。
具体案例:一家电商和一家物流公司联合训练配送时效预测模型,双方使用 SPDZ 预处理生成的三元组完成每一轮梯度掩码聚合,最终模型准确率比单方模型提升 18%,而双方都没有泄露用户特征明细。
Python 演示
import random P = 2**61 - 1 def share(secret, n): shares = [] total = 0 for _ in range(n - 1): r = random.randrange(P) shares.append(r) total = (total + r) % P shares.append((secret - total) % P) return shares def open_shares(shares): return sum(shares) % P def make_beaver_triple(n): a = random.randrange(P) b = random.randrange(P) c = (a * b) % P return (share(a, n), share(b, n), share(c, n)) def beaver_mul(x_shares, y_shares, triple): a_shares, b_shares, c_shares = triple a = open_shares(a_shares) b = open_shares(b_shares) d = (open_shares(x_shares) - a) % P e = (open_shares(y_shares) - b) % P z_shares = [] for i in range(len(x_shares)): z_i = (c_shares[i] + d * b_shares[i] + e * a_shares[i]) % P z_shares.append(z_i) z_shares[0] = (z_shares[0] + d * e) % P return z_shares def make_mac(secret, alpha, beta): return (alpha * secret + beta) % P def verify_mac(secret, mac, alpha, beta): return make_mac(secret, alpha, beta) == mac def main(): x = 7 y = 5 n = 2 x_shares = share(x, n) y_shares = share(y, n) triple = make_beaver_triple(n) z_shares = beaver_mul(x_shares, y_shares, triple) z = open_shares(z_shares) alpha = 123456789 beta = 987654321 mac = make_mac(z, alpha, beta) print("x =", x, " y =", y) print("z =", z) print("MAC verify:", verify_mac(z, mac, alpha, beta)) if __name__ == "__main__": main()
x_shares = share(x, n)把原始输入 \(x\) 拆成 \(n\) 个随机碎片,每个碎片单独看不含秘密。triple = make_beaver_triple(n)生成一个 Beaver 三元组,并像普通秘密一样拆成碎片。a = open_shares(a_shares)打开三元组中的随机数 \(a\),用于掩盖真实输入。d = (open_shares(x_shares) - a) % P打开遮蔽后的差值,\(x\) 的真实信息被随机 \(a\) 遮住。z_i = (c_shares[i] + d * b_shares[i] + e * a_shares[i]) % P每个参与方本地组合自己的碎片。z_shares[0] = (z_shares[0] + d * e) % P把公开常数项 \(d \times e\) 加到第一个碎片上。mac = make_mac(z, alpha, beta)给最终结果贴上数学防伪标签。verify_mac(z, mac, alpha, beta)校验标签是否一致,模拟恶意安全中的 MAC 检查。
常见误区
误区很多人以为 SPDZ 的预处理阶段一定要有个“上帝服务器”来生成三元组,否则没法保证安全。
正解SPDZ 的设计目标是“无可信第三方”。离线阶段的随机数、三元组、MAC 密钥都由参与者之间通过秘密共享和密码学抽签协议共同生成,最终被打散成碎片,任何单独一方都不掌握完整材料。
为何常见:因为“提前备好调料包”听起来像中央厨房统一发货,很容易让人联想到一个集中可信的机构。
误区以为 MAC 就像监控摄像头,一旦有人使坏就能回放画面,直接指认恶意者的身份。
正解SPDZ 的 MAC 更接近“防伪标签被撕坏后整包拒收”。它能证明数据确实被篡改,并让协议中止,但通常不能直接确定具体是哪一方动了手脚。安全目标不是抓人,而是保证错误结果不会被接受。
为何常见:现实中我们习惯“证据指向某个人”,但密码学协议优先保证“结果正确”,追责往往需要额外机制。
误区既然离线阶段已经准备好大量材料,在线阶段应该所有人都静默本地算完,网络开销为零。
正解加法确实可以在本地完成,但每一个乘法仍然需要广播差值 \(d\) 和 \(e\),才能让所有人同步计算结果。所以在线阶段虽然有别于在线下?在线阶段依然有通信,只是比传统公钥密码方案轻很多。
为何常见:“离线备料、在线开包”的比喻容易让人以为在线就是完全不联网。
误区有人觉得三元组只是随机数,反正和输入无关,直接贴在公告板上也没问题。
正解三元组虽然不依赖输入,但它是掩盖乘法过程的“暗号”。一旦公开 \(a\) 和 \(b\),任何人都能从公开差值 \(d = x - a\) 中反推出真实输入 \(x\)。三元组必须像秘密一样被打散和保密。
为何常见:因为“随机数”给人大可公开的直觉,忽略了它作为掩码的核心作用。
误区以为 SPDZ 是两方安全计算的专用协议,三方以上就得换方案。
正解SPDZ 是多方协议,参与方数量 \(n\) 可以大于 2。秘密共享碎片分给多少人、在线阶段有多少人参与,都由系统参数自由决定。它在多方协作场景中同样适用。
为何常见:很多入门教程用两个参与者举例,导致读者误以为协议只支持两方。
面试题
Q1. SPDZ 中“离线预处理”的主要目标是什么?
- A.生成随机三元组和 MAC 材料← 正确答案
- B.直接计算最终函数结果
- C.把数据交给可信第三方
- D.建立参与者网络连接
答案:A。离线阶段像提前包好调料包,目标是生成 Beaver 三元组、MAC 密钥等密码学材料;直接计算是在线阶段的事,且 SPDZ 不依赖可信第三方。
Q2. 在加法秘密共享中,若秘密值为 s,参与方有 n 个,应如何构造 s 的碎片?
- A.随机生成前 n-1 个碎片,最后一个由 s 减去它们得到← 正确答案
- B.让每个参与方掌握完整 s
- C.把 s 平均切成 n 等份
- D.用公钥加密后分给所有人
答案:A。加法秘密共享需要随机碎片,让最后一个碎片“补齐”秘密值,这样所有碎片相加可还原 s。平均切分会让单个碎片泄露比例信息,公钥加密也不是秘密共享。
Q3. 在线乘法使用 Beaver 三元组时,三元组的三个数满足什么关系?
- A.满足 c = a × b← 正确答案
- B.满足 b = a + c
- C.满足 a = b + c
- D.满足 c = a + b
答案:A。Beaver 三元组 \((a,b,c)\) 的核心约束是第三个等于前两个的乘积。这样在线乘法才能用差值 \(d=x-a\)、\(e=y-b\) 完成安全计算。
Q4. 为什么公开差值 d = x - a 不会泄露 x 的信息?
- A.因为 a 是随机掩码,单独看 d 与随机数无异← 正确答案
- B.因为差值一定是 0
- C.因为 x 本来就不需要保密
- D.因为 MAC 会隐藏 d
答案:A。a 是未知的随机数,d 相当于在随机数上叠加了 x,从密码学角度看和随机数不可区分。MAC 校验的是完整性,不负责隐藏已经公开的 d。
Q5. SPDZ 的 MAC 机制可以提供哪些安全能力?
- A.检测共享值被篡改← 正确答案
- B.发现异常后中止协议← 正确答案
- C.准确揪出恶意参与者
- D.让所有人都能看到完整原始数据
答案:AB。SPDZ 的 MAC 能检测篡改并触发 abort,但通常不提供身份指认,也不会公开原始数据。它能阻止错误结果输出,却不会把秘密发给所有人。
Q6. 关于离线预处理阶段生成的三元组,下列说法正确的是?
- A.不依赖参与方的实际输入← 正确答案
- B.三元组本身需要保密← 正确答案
- C.必须等输入确定后才生成
- D.可以直接对所有人公开
答案:AB。预处理阶段可以在真实输入进入前批量完成,像提前切好葱姜蒜。三元组是掩码材料,一旦公开就会被敌手利用,所以必须保密。
Q7. 与半诚实协议相比,SPDZ 的核心优势是什么?
- A.能抵抗恶意敌手篡改← 正确答案
- B.完全不需要通信
- C.不需要预处理阶段
- D.只能在两方场景使用
答案:A。半诚实协议只防“偷看”,不防“捣乱”;SPDZ 通过 MAC 和预处理材料检测恶意篡改。它仍然需要通信和预处理,并支持多方。
Q8. 秘密共享中,单个碎片为什么没有意义?
- A.因为碎片是随机分布的← 正确答案
- B.因为碎片是负数
- C.因为碎片经过哈希运算
- D.因为碎片长度太短
答案:A。除了最后一个碎片,其余碎片都是随机数,单个自然无法还原信息;秘密信息分散在所有碎片的组合中。
Q9. 下列哪些阶段属于 SPDZ 协议的执行流程?
- A.离线预处理阶段← 正确答案
- B.在线计算阶段← 正确答案
- C.数据标注阶段
- D.模型推理阶段
答案:AB。SPDZ 把计算分为“提前备料”的离线预处理和“真正下锅”的在线计算两部分。数据标注、模型推理属于机器学习流程,不是协议阶段。
Q10. 如果 MAC 校验失败,SPDZ 协议通常如何处理?
- A.中止协议并放弃本次输出← 正确答案
- B.忽略错误继续计算
- C.自动切换成半诚实模式
- D.从结果推算出恶意者身份
答案:A。MAC 失败说明数据被篡改,SPDZ 会立即中止,避免错误结果被接受。继续计算会导致不可信输出,而恶意者身份通常无法从一个简单 MAC 校验中直接确定。