想象你揣着一块沉甸甸的金疙瘩走进街角金匠铺,想让老师傅把它打成一只婚戒。可你怕他偷金、换金,又不肯把金子直接交出去。于是你买来一个带密码锁的玻璃保险柜,把金疙瘩锁进去,隔着玻璃递给师傅。神奇的是,玻璃柜并不妨碍他干活——他可以隔着柜子敲打、塑形、抛光,全程看不见、摸不着金子,柜里也不漏出一丝金屑。几天后你取回柜子,开锁一看,金疙瘩真的变成了一枚戒指,和你站在旁边盯着他做的一模一样。 这就是“全同态加密”(Full Homomorphic Encryption,FHE)想要实现的魔法:数据还处于密文状态时,计算就已经完成了。传统加密像密封的牛皮纸箱,封上口谁都别想动里面的东西;全同态加密则像玻璃柜,既能保密,又能隔柜加工。本文用“保险柜里的金匠”这一比喻,带你从零理解 FHE 的原理、半同态与全同态的区别、噪声与自举(Bootstrapping)这对核心矛盾,最后看看它为什么是隐私计算的“圣杯”,又为什么至今难以大规模普及。

岗位关联

对 AI 从业者而言,全同态加密是隐私计算皇冠上的明珠。弄懂它,你就能在医疗、金融等敏感数据场景中设计“数据可用不可见”的方案,也能在技术选型时准确评估加密计算的成本与边界。

目录
  1. 可视化演示
  2. 同态加密基础
  3. 半同态走向全同态
  4. 噪声与自举
  5. 主流实现方案
  6. 性能瓶颈
  7. 优化方向
  8. 应用落地
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

动态演示全同态加密入门的核心机制,通过入门/进阶/实战/优化四种模式展示关键概念与交互流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

全同态加密入门:一同态加 一、同态加密的基本概念与密文计 二、半同态与全同态加密的能力差 核心机制可视化 全同态加密入门整体架构与关键组件

同态加密基础

金匠隔着玻璃柜雕金子的故事,看似只是个美好的想象,但它恰好概括了密码学中“同态”(Homomorphic)一词的本意:运算规则在加密前后保持一致。上世纪 80 年代,密码学家设想:如果我们能设计一种加密方式,让“密文上的操作”与“明文上的操作”形成某种对应关系,那么第三方就能在不接触明文的情况下,替我们完成计算。这个设想在很长时间里被认为接近科幻,因为常见的加密算法都像牛皮纸箱——一旦封装,谁也别想再碰内容。

传统加密为什么“不能算”?以 AES 为例,密文是明文经过多轮替换和混淆得到的乱码,密文与明文之间没有简单的加减乘关系。你拿到两个密文,把它们加起来,解出来的东西跟两个明文的加和毫无关系。这就像把两个纸箱叠在一起,里面的物品不会自动合并。而全同态加密要造的是“会运算的保险柜”:柜子里的数值可以隔着玻璃被变换,变换后的结果解出来,恰好等同于你直接对明文做了同样的变换。

用数学语言说,设 Enc 是加密函数,a、b 是两个明文,如果存在密文域上的运算 ⊙ 和明文域上的运算 ⊕,使得下面的等式成立,那么这种加密就具备了同态性质:

回到金匠的比喻:玻璃柜既保护了金子不被偷看,又允许加工动作穿透玻璃传递到金子上。“同态”就是这层神奇的玻璃。不过,要让锤子、钳子、刻刀全部能在玻璃外使用,并不是一朝一夕的事——这正是我们从“半同态”走向“全同态”要讲的下一步。

Enc(a)⊙Enc(b)=Enc(a⊕b)\displaystyle \text{Enc}(a) \odot \text{Enc}(b) = \text{Enc}(a \oplus b)
这个公式想表达一句话:先加密再运算,与先运算再加密,殊途同归。它是全同态加密一切魔法的起点。
  1. 加密函数 Enc把明文变成密文的“锁”,相当于你把金子放进玻璃柜、挂上锁的那一下。
    Enc\text{Enc}
  2. 明文运算 ⊕现实世界里你想做的事,比如加法、乘法、比较大小,对应 K 金匠脑海中“把金块打成环形”的工序。
    a⊕ba \oplus b
  3. 密文运算 ⊙与 ⊕ 对应的、作用在密文上的“影子操作”,相当于金匠隔着玻璃挥舞锤子,整个过程只作用于保险柜外观。
    Enc(a)⊙Enc(b)\text{Enc}(a) \odot \text{Enc}(b)
  4. 等号成立两条路径到达同一终点——左边先加密再在密文上算,右边先在明文上算再加密,二者结果一致。
    Enc(a⊕b)\text{Enc}(a \oplus b)

半同态走向全同态

金匠铺里不是所有师傅都十八般武艺俱全。有的师傅只会抡锤子,见到金块就敲成薄片;有的师傅只会用磨石,把金块抛光成圆珠。如果只能隔着保险柜做一种动作,柜里的金子就只能变成一种固定形状——这就是“半同态加密”(Partially Homomorphic Encryption,PHE)。

现实中最常见的半同态有两种。一种叫加法同态:密文相加后解密,等于明文相加。经典代表是 Paillier 加密,常用于电子投票——每个投票人加密自己的选票,计票人员把所有密文相加后解密,得到总数,却始终不知道任何一个人的选择。另一种叫乘法同态:早期 RSA、ElGamal 这类加密天然支持密文相乘对应明文相乘,适合做签名的盲化处理。但它们都只支持一种运算,就像只会一门的金匠,无法完成复杂造型。

加法同态像单臂锤,乘法同态像单臂磨,而全同态让金匠的双手彻底解放。不过,全同态的实现并非简单叠加——柜子里的“碎屑问题”(噪声)随之浮出水面,成为整个领域最核心的矛盾。

D(E(a)+E(b))=a+b,D(E(a)×E(b))=ab\displaystyle D\big(E(a)+E(b)\big)=a+b, \qquad D\big(E(a)\times E(b)\big)=ab
公式左侧是“密文加法”和“密文乘法”两条半同态路线,右侧是对应的明文运算。若加法、乘法都能同态支持,就离全同态不远了。
  1. 加法同态线路密文之和的解密结果等于明文之和,对应金匠只靠锤击让两块金子融合,D(...) 表示解密函数。
    D(E(a)+E(b))=a+bD\big(E(a)+E(b)\big)=a+b
  2. 乘法同态线路密文之积的解密结果等于明文之积,对应只用磨石把金子打磨成标准圆珠。
    D(E(a)×E(b))=abD\big(E(a)\times E(b)\big)=ab
  3. 双线并轨如果能同时拿到加法和乘法,就可以组合出任意多项式,而多项式可以逼近几乎所有可计算函数。
    E(a)+E(b),E(a)×E(b)⇒E(f(a,b))E(a)+E(b),\quad E(a)\times E(b) \Rightarrow E(f(a,b))
  4. 全同态飞跃2009 年,Gentry 在博士论文中证明:只要容忍噪声增长并引入自举,就能把这两种能力叠起来,解锁任意函数的密文计算。金匠终于学会了全部工序。
    FHE: E(a)⊙E(b)=E(a⊕b),∀ 运算 ⊙\text{FHE: } E(a) \odot E(b) = E(a \oplus b), \quad \forall \text{ 运算 } \odot

噪声与自举

现在回到玻璃柜内部。金匠每敲打一次,金子上总会掉下一些微不可见的金屑;每打磨一次,也会扬起一缕粉末。这些碎屑在真实 FHE 里就是噪声(noise)。加密时,我们先把明文乘以一个大整数 delta(相当于把金块放在专用模具里),再加上一个随机小扰动 e(相当于故意撒上的一层细沙),得到密文:

解密时只要把细沙拂去、按模具位置取整,就能找回明文。麻烦的是,每一次同态运算都会让噪声变大——两次密文相加,噪声大约是两次噪声之和。当噪声累积超过容限(delta/2),解密取整就会出错,金子的形状被碎屑完全淹没。

噪声与自举,就像柜内碎屑与定期大扫除:只要扫除足够及时,金匠就能无限期地加工下去。理解了这对矛盾,你再看不同实现方案时,就能明白它们各自的取舍了。

c=m×delta+e(modq)\displaystyle c = m \times \text{delta} + e \pmod q
Boot(c)=Encsk′(Decsk(c)),noise(Boot(c))≪noise(c)\displaystyle \text{Boot}(c) = \text{Enc}_{sk'}\big(\text{Dec}_{sk}(c)\big), \qquad \text{noise}\big(\text{Boot}(c)\big) \ll \text{noise}(c)
这就是 Gentry 的天才一跃:与其让噪声无限膨胀,不如趁它还没爆表,用“加密的密钥”在密文上执行一次解密,把当前状态重置为低噪声。这个过程叫自举(Bootstrapping),相当于金匠戴上一副能透视碎屑的神奇手套,隔着柜子把里面打扫得一尘不染,再继续加工。
  1. 解密函数 Dec理论上需要一个函数能把密文变回明文,但在自举场景中,这个函数是被加密地“虚拟执行”的——金匠不是真的打开柜子,而是在脑子里“回想”金子的形状。
    Decsk(c)\text{Dec}_{sk}(c)
  2. 加密密钥与密文同时参与构造 Enc(sk) 和 Enc(c),让解密运算在密文域上进行,全程不暴露明文,金匠始终摸不到金子。
    Eval(DecCircuit,Enc(sk),Enc(c))\text{Eval}\big(\text{DecCircuit}, \text{Enc}(sk), \text{Enc}(c)\big)
  3. 重新加密得到新密文自举输出的新密文 c' 与旧密文解密结果一致,但内部的细沙被换成刚撒的新沙,噪声回到初始水平。
    Boot(c)=c′∈Enc(m)\text{Boot}(c) = c' \in \text{Enc}(m)
  4. 噪声对比自举前后的噪声量级从“危险区”降到“安全区”,运算次数得以继续累积,这也是全同态加密能“任意深度计算”的根本保障。
    noise(c′)≪noise(c)\text{noise}(c') \ll \text{noise}(c)

主流实现方案

既然噪声和自举是全同态的命门,各路“金匠流派”就开始比拼谁的大扫除更快、谁的工具更趁手。经过十几年发展,目前工业界主流的全同态方案主要有三支。

第一支是 BGV 与 BFV。它们面向整数精确运算,适合记账、投票这类不能容忍误差的场景。就好像一位严谨的老金匠,每一锤都有精确标尺,做出来的戒指必须毫米不差。代价是噪声预算消耗较快,深度较大的计算需要多次自举。

第二支是 CKKS。它另辟蹊径,允许计算结果带有可控的微小误差,换来极高的效率。想象一位擅长雕花的艺术家,追求整体造型神似,不纠结于 0.01 毫米的偏差。这套方案天然适合机器学习——神经网络的权重本来就带有浮点容差,CKKS 因而成为 AI 隐私推理的首选。

第三支是 TFHE。它把运算拆成最基本的布尔门(与、或、非),并把自举加速到毫秒级,每一次门的计算都可以紧跟一次自举。就像一位手脚麻利的小学徒,每做一步就打扫一次,虽然单个动作简单,但胜在可以无限组合,特别适合做查找表、比较器这类控制流运算。

CKKS 的加解密可以用内积形式表达,其近似性一目了然:

选择哪一支方案,取决于你的“金器”是精密齿轮(BGV),还是写意雕塑(CKKS),还是需要无数道工序的机关匣(TFHE)。但不管选谁,全同态加密的代价都高得惊人——这正是下一节要直面的话题。

Dec(⟨c,sk⟩)≈m(modq)\displaystyle \text{Dec}\big(\langle \mathbf{c}, \mathbf{sk}\rangle\big) \approx \mathbf{m} \pmod q
这里 c 是密文向量,sk 是私钥向量,⟨c, sk⟩ 是两者的内积。解密结果只是“大约等于”明文向量 m——这正是 CKKS 引入近似误差换取性能的秘诀。
  1. 密文向量 cCKKS 的密文不是一个数,而是一个向量,可以同时装下多个数值,相当于一个多格保险柜。
    c=(c0,c1)\mathbf{c} = (c_0, c_1)
  2. 私钥向量 sk与密文配对的解密钥匙,也是一条向量,金匠手里那把万能钥匙的数学化身。
    sk=(1,−s)\mathbf{sk} = (1, -s)
  3. 内积计算把两个向量对应分量相乘再相加,这个操作在解密时把噪声与消息分离出来。
    ⟨c,sk⟩=c0−s⋅c1\langle \mathbf{c}, \mathbf{sk} \rangle = c_0 - s \cdot c_1
  4. 近似等于明文由于 CKKS 主动引入缩放误差,解密结果与明文只差一个微小量,这个微小量在浮点模型里通常可以接受。
    ⟨c,sk⟩≈m(modq)\langle \mathbf{c}, \mathbf{sk} \rangle \approx \mathbf{m} \pmod q

性能瓶颈

金匠隔着保险柜打戒指,再心灵手巧也会比徒手操作慢上许多。全同态加密的性能瓶颈就集中体现在这两点:慢和大。

先说“慢”。同态运算涉及大整数多项式乘法,一次普通的密文加法比明文加法慢好几个数量级;一次密文乘法在未优化的实现中可能慢上百万倍。即便经过多年优化,主流库(如 Microsoft SEAL、IBM HElib)的密文运算仍然比明文运算慢 10^5 ~ 10^6 倍。换句话说,明文上跑 1 秒的活儿,密文上可能要跑一整天。

再看“大”。密文体积相对明文通常膨胀几十到上千倍。一个 32 位整数,加密后的密文可能占据几千字节甚至更多。这就像把一枚小戒指坯子放进一个冰箱大的保险柜里搬运。传输带宽、内存占用随之水涨船高。

除了慢和大,密钥管理也让人头疼:噪声预算越高,所需密钥尺寸越大,多层运算还需要“密钥切换”“模数切换”等辅助数据,像是给金匠配备了一整车备用工具。庆幸的是,工程师们没有坐以待毙,一系列优化手段正在一点点把冰箱缩小成手提箱。

R=∣ct∣∣pt∣,S=TFHE(f)Tplain(f)\displaystyle R = \frac{|ct|}{|pt|}, \qquad S = \frac{T_{\text{FHE}}(f)}{T_{\text{plain}}(f)}
第一个式子 R 叫密文膨胀率,是密文长度与明文长度的比值;第二个式子 S 叫减速比,是同一函数在密文上运行时间与明文上运行时间的比值。两者是衡量 FHE 工程成本最直观的标尺。
  1. 密文体积 |ct|密文对象在内存里占据的字节数,柜子本身的体积。
    ∣ct∣|ct|
  2. 明文体积 |pt|原始数据的字节数,金子的净重。
    ∣pt∣|pt|
  3. 膨胀率 R两者相除,R 越大说明“柜子越重”,通常几十到上千。
    R=∣ct∣∣pt∣R = \frac{|ct|}{|pt|}
  4. 减速比 S同一函数 f 在密文域耗时与明文域耗时之比,S 动辄十万百万,是性能问题最尖锐的体现。
    S=TFHE(f)Tplain(f)S = \frac{T_{\text{FHE}}(f)}{T_{\text{plain}}(f)}

优化方向

既然金匠隔着柜子干活效率低,那就想办法让他一次多处理几件金器,或者给他配上更趁手的机器。全同态加密的优化路线,正是围绕这两条思路展开的。

第一条是明文打包(也叫 SIMD 技术)。既然一个密文向量能装下多个明文,不如把成百上千个数值塞进同一个密文,让一次密文运算同时作用于所有分量。这就像金匠把一整排戒指坯子同时摆在柜台上,一锤下去,十枚戒指同时成型。批处理让有效吞吐量提升了数百倍。

第二条是并行与硬件加速。FHE 的多项式乘法天然适合 GPU 并行;FPGA 上也有专门的 NTT(数论变换)加速单元。OpenFHE、HElib 等库都支持多线程;cuHE、HEGPU 等项目把密文运算搬运到显卡上,整套流程可以获得一到两个数量级的加速。

第三条是混合方案。在设计系统时,不全盘使用 FHE,而是把它与可信执行环境(TEE)、安全多方计算(MPC)组合。比如用 FHE 保护数据计算的核心环节,用 TEE 保护密钥分发,用 MPC 处理需要多方参与的交互协议。扬长避短,才是工程落地的最优解。

这些优化有一个共同的数学支点——把多个明文装入同一密文:

优化仍在继续,但 FHE 已经走出了纯理论的象牙塔,开始在真实世界里解决“数据可用不可见”的难题。最后我们来看看金匠的生意已经开到了哪些行业。

Enc(m)=Enc(m1,m2,…,mℓ),Dec(Enc(m))=(m1,m2,…,mℓ)\displaystyle \text{Enc}(\mathbf{m}) = \text{Enc}(m_1, m_2, \ldots, m_\ell), \qquad \text{Dec}\big(\text{Enc}(\mathbf{m})\big) = (m_1, m_2, \ldots, m_\ell)
一个密文同时携带 ℓ 个明文分量,一次密文运算等价于 ℓ 次明文运算。这就是明文打包的精髓:让金匠的一锤子同时落在 ℓ 件金器上。
  1. 明文向量 m把 ℓ 个独立数值拼成一个向量,相当于把 ℓ 枚戒指坯子排成一排。
    m=(m1,m2,…,mℓ)\mathbf{m} = (m_1, m_2, \ldots, m_\ell)
  2. 整体加密对整个向量做一次加密,得到单个密文,相当于把所有坯子放进同一口保险柜。
    Enc(m)\text{Enc}(\mathbf{m})
  3. 分量级解密解密后还原出完整的向量,每一位分量互不干扰。
    Dec(Enc(m))=(m1,…,mℓ)\text{Dec}(\text{Enc}(\mathbf{m})) = (m_1, \ldots, m_\ell)
  4. 并行语义密文上的单次加法/乘法,等价于对所有 ℓ 个分量同时做同样操作,吞吐量提高 ℓ 倍。
    Enc(m)⊙Enc(m′)=Enc(m⊕m′)\text{Enc}(\mathbf{m}) \odot \text{Enc}(\mathbf{m}') = \text{Enc}(\mathbf{m} \oplus \mathbf{m}')

应用落地

金匠的玻璃柜一旦真的能用,第一个找上门的往往是隐私最敏感的行业:医疗、金融和搜索。

在医疗领域,多家医院想联合统计某种疾病的发病率,却不愿把原始病历交给对方。使用 FHE,各医院把患者特征加密后上传到中心服务器,服务器在密文上完成计数与加权,最后解密出一份统计报告。整个过程没有任何一条病历离开医院,但统计结论却真实可信。

在金融领域,银行之间有一张共享的“欺诈黑名单”——但谁都不愿意把名单直接给别人,查询方也不希望暴露自己正在查谁。借助 FHE,查询方把客户 ID 加密后发给名单持有方,名单库在密文上做匹配,返回加密的命中结果。金融机构既能拦住风险客户,又不泄露任何一方的隐私。

在云端 AI 推理场景,用户把敏感输入(比如病历影像特征)加密后传给云上的模型服务,云服务器用 CKKS 在密文上执行神经网络的前向计算,返回加密的预测结果。模型看到的是密文,用户拿到的是明文预测——这就实现了“模型可用、数据不裸奔”。

这类应用背后是一个通用的密文统计范式:

从医院到银行再到云端,全同态加密正在把“不信任”变成一种可计算的资源。虽然它还很慢、很大、很贵,但正如保险柜里的金匠正在一步步把粗活细活都接过来——隐私计算的黄金时代,或许已经拉开帷幕。

Result=Dec(∑i=1nEnc(xi)⋅wi)\displaystyle \text{Result} = \text{Dec}\left(\sum_{i=1}^{n} \text{Enc}(x_i) \cdot w_i\right)
公式表示:各方把数据 x_i 加密后,服务器用公开权重 w_i 做密文加权求和,最后解密得到聚合结果。个体数据被密码学保护,全局统计则被允许揭露。
  1. 个体加密第 i 个参与方把本地数据 x_i 加密成 Enc(x_i),相当于每家把自己的金器锁进柜子再送出来。
    Enc(xi)\text{Enc}(x_i)
  2. 密文加权求和服务器在不知道 x_i 的情况下,计算密文与权重乘积之和,金匠隔着所有柜子完成统一的铸型工序。
    ∑i=1nEnc(xi)⋅wi\sum_{i=1}^{n} \text{Enc}(x_i) \cdot w_i
  3. 一次解密出全局结果只有授权方持有私钥,能打开最后的汇总柜,得到加权平均或其他统计量。
    Dec(∑i=1nEnc(xi)⋅wi)\text{Dec}\left(\sum_{i=1}^{n} \text{Enc}(x_i) \cdot w_i\right)

AI 应用场景

医疗多中心联合统计

阶段:数据融合与建模

解决的问题:传统多中心研究需要把各医院的患者数据汇到一处,但病历受《个人信息保护法》和医院伦理约束,物理汇聚几乎不可能;匿名化处理又会损失统计精度。用 FHE 后,各中心只需上传密文,服务器在密文上直接完成统计聚合,既满足合规要求,又保留全量数据的统计效力。

具体案例:某医联体搭建慢病风险预测平台,五家医院分别用 CKKS 加密患者血糖、血压等特征,中心节点在密文上训练线性模型并完成梯度聚合,最终模型 AUC 与明文训练仅差不到 1%。自始至终,任何一家医院都无法看到其他医院的原始病历。

金融黑名单密文查询

阶段:安全数据查询与风控决策

解决的问题:传统黑名单共享存在两难:名单持有方担心名单泄露,查询方担心查询记录暴露业务动向。FHE 让查询方把待查 ID 加密后交给名单库,库方在密文上完成比对,返回加密结果,双方各得其所。

具体案例:某支付机构与征信公司合作,将 600 万条欺诈账户名单加密入库。每次交易前,支付机构把用户 ID 用 BGV 方案加密后发起查询,密文匹配耗时约 300 毫秒,命中结果解密后即时触发风控拦截,而征信公司完全不知道被查的是谁。

云端私有机器学习推理

阶段:模型推理服务

解决的问题:企业想用云上的大模型,又担心输入数据(如客户合同、医疗影像)泄露给云厂商;模型方同样担心推理逻辑被逆向。FHE 让用户加密输入上传,云服务器在密文上跑模型,返回加密结果,实现双向隐私保护。

具体案例:某保险公司的智能核保系统把理赔文本分类模型部署在公有云上,用户提交的理赔描述先用 CKKS 加密,云端完成嵌入层与线性层计算(激活函数用多项式近似),端到端推理耗时约 2 秒,相比明文慢约 200 倍,但在“可接受延迟”范围内换来了数据不出本地的合规承诺。

Python 演示

python74 行
"""玩具级全同态加密:演示噪声累积与自举刷新"""import random  class ToyFHE:    """基于整数 LWE 思想的教学玩具,明文空间为 {0, 1}"""     def __init__(self, q=10**6, noise_range=3000):        self.q = q        self.delta = q // 4          # 明文缩放因子,决定噪声预算        self.noise_range = noise_range        self.sk = random.randint(1, q // 10)     def encrypt(self, m):        """加密:明文 * delta + 密钥 + 随机小噪声,整体对 q 取模"""        if m not in (0, 1):            raise ValueError("明文只能为 0 或 1")        e = random.randint(-self.noise_range, self.noise_range)        return (m * self.delta + self.sk + e) % self.q     def decrypt(self, c):        """解密:先减去密钥,再按 4v/q 取整并对 2 取模"""        v = (c - self.sk) % self.q        x = 4 * v / self.q        return round(x) % 2     def xor(self, c1, c2):        """密文加法:对应明文 XOR,多出的 sk 用减法对齐"""        return (c1 + c2 - self.sk) % self.q     def noise_of(self, c):        """估算密文当前噪声大小"""        m = self.decrypt(c)        e = (c - self.sk - m * self.delta) % self.q        if e > self.q - e:            e -= self.q        return abs(e)     def bootstrap(self, c):        """自举:重加密当前消息,把噪声重置到初始水平"""        return self.encrypt(self.decrypt(c))  def run_until_warning(he, acc, warn_line):    """持续 XOR 运算直到噪声逼近预警线,返回新密文和运算次数"""    count = 0    while count < 50000:        acc = he.xor(acc, he.encrypt(1))        count += 1        if he.noise_of(acc) > warn_line:            break    return acc, count  def main():    he = ToyFHE()    warn_line = he.delta // 3    print("q=%d 噪声预算约%d 预警线约%d" % (he.q, he.delta // 2, warn_line))     acc = he.encrypt(0)    acc, n1 = run_until_warning(he, acc, warn_line)    print("第一轮:%d 次 XOR 后噪声=%d 解密=%d(期望%d)"          % (n1, he.noise_of(acc), he.decrypt(acc), n1 % 2))     acc = he.bootstrap(acc)    print("自举后噪声=%d 解密=%d" % (he.noise_of(acc), he.decrypt(acc)))     acc, n2 = run_until_warning(he, acc, warn_line)    print("第二轮:又完成 %d 次 XOR 解密=%d(期望%d)"          % (n2, he.decrypt(acc), n1 % 2 ^ n2 % 2))  if __name__ == "__main__":    main()
目的:用 50 行代码模拟全同态加密的核心矛盾——噪声随运算次数增长、逼近阈值后解密仍有风险、自举可把噪声重置回安全区。跑一遍就能直观感受“为什么 FHE 不能无限运算”。
  1. self.delta = q // 4明文被放大到 q/4 的刻度上,噪声只要不超过一半就不会越界,这是整个玩具方案的噪声预算。
  2. return (m * self.delta + self.sk + e) % self.q加密时同时混入密钥和随机噪声,噪声就是“柜里的碎屑”。
  3. return round(x) % 2解密时按 4 倍缩放取整再模 2;噪声一旦超过 delta/2,取整会落到错误格点。
  4. return (c1 + c2 - self.sk) % self.q密文加法后减去一个密钥,模拟现实中密钥切换(KeySwitch)保证密钥对齐。
  5. if he.noise_of(acc) > warn_line预警线设在噪声预算的 2/3 左右,提前触发自举,避免解密刚好处在出错边缘。

常见误区

误区很多初学者以为 FHE 的流程是“先解密→算完→再加密”,觉得这和传统加密没什么本质区别,只是把解密过程藏在了服务器内部。

正解这是对 FHE 最深的理解偏差。全同态加密全程在密文域上做运算,服务器从头到尾拿不到明文,也无法通过内存转储、日志打印等方式窥探到任何中间结果。就像金匠隔着玻璃柜干活,柜子从头到尾没打开过,那只“特制手套”(自举)也是在密文状态下执行解密电路,而不是真的把金子掏出来。

为何常见:自举(Bootstrapping)的名字里带着“解密”,很容易让人误以为它就是在解密。实际上 Bootstrapping 是“在密文上执行一次解密操作”,输入、输出都是密文。

误区有人认为只要愿意做自举,FHE 就能无限次运算,性能问题也迎刃而解。

正解自举确实能把噪声重置回低水平,但它本身也是一次极重的同态运算,消耗大量计算时间和内存。现实中每做一次自举都要付出“大扫除”的成本,频繁自举会让性能雪上加霜。工程师的策略通常是精心控制噪声预算,尽量攒够一批运算再统一自举,而不是每步都扫。

为何常见:概念课上只讲“自举刷新噪声”这一面,容易让人忽略自举本身的开销和复杂度,以为它是免费的万能药。

误区既然 CKKS 支持浮点数的密文运算,很多人以为可以直接把 `numpy` 里的任意函数搬到 FHE 上跑。

正解CKKS 只是对加法和乘法友好,神经网络里常见的 softmax、ReLU、max-pooling 这类非线性函数,FHE 支持得极其吃力,往往需要用多项式近似(如 x^2 逼近 ReLU)或查表重写。每引入一个非线性操作,都会带来额外的噪声增长和巨大的开销。

为何常见:看到“支持浮点近似”就误以为“什么都能算”,忽略了 FHE 只擅长加乘同态的基本盘,非线性操作是它的软肋。

误区FHE 在理论上比 TEE 更安全(不依赖硬件信任根),于是有人认为 FHE 将很快取代 TEE、MPC 等所有其他隐私计算技术。

正解FHE 当前性能仍比明文慢 5~6 个数量级,工程复杂度极高;TEE 依赖 CPU 硬件隔离但性能接近明文;MPC 适合多方交互但通信量大。现实中三者常常组合使用——FHE 管计算、TEE 管密钥、MPC 管分布式协作。这是一种“组合拳”而非“你死我活”。

为何常见:理论安全性对比容易被拿来炒作,但工程选型要看延迟、吞吐、成本、合规等多维指标,单一技术通吃是不现实的。

面试题

Q1. 关于同态加密与传统加密的区别,下列说法正确的是

单选题 · easy

  • A.传统加密也能直接运算
  • B.同态加密允许密文计算← 正确答案
  • C.同态加密不需要密钥
  • D.传统加密更加安全可靠

答案:B。传统加密(如 AES)像密封纸箱,只能防窥看,不能在密文上做运算;同态加密像玻璃柜,支持在密文上直接计算。选项 A 把传统加密说成可运算是错的,C 说同态加密不需要密钥是错的,D 没有依据,两类加密的安全性取决于算法与参数,并非传统更优。

Q2. 加法同态最适合下列哪一场景

单选题 · easy

  • A.密文投票计数← 正确答案
  • B.密文模型训练
  • C.密文图像压缩
  • D.密文用户登录

答案:A。加法同态让“多个密文相加后解密等于明文相加”,电子投票正好只需要把所有选票密文加起来再解密得到总数,是最典型的应用。模型训练需要加法和乘法组合(全同态),图像压缩和用户登录与同态运算没有直接关系。

Q3. 全同态加密中的“噪声”主要来自哪里

单选题 · mid

  • A.加密时密钥长度过短
  • B.每次加密和同态运算都引入随机扰动← 正确答案
  • C.网络传输过程发生丢包
  • D.明文数据本身包含噪声

答案:B。LWE 类方案加密时故意在密文里混入小随机扰动以保证安全性,每次同态运算(如密文加法、乘法)会让扰动叠加增大。这不是密钥过短或网络问题,也不是明文自带的噪声,而是密码学构造刻意为之的设计。

Q4. 下列哪些属于全同态加密的主流实现方案

多选题 · mid

  • A.BGV 整数精确方案← 正确答案
  • B.CKKS 浮点近似方案← 正确答案
  • C.RSA 乘法方案
  • D.TFHE 快速自举方案← 正确答案

答案:ABD。BGV、CKKS、TFHE 都是当今 FHE 的主流方向,分别主打整数精确、浮点近似、布尔快速自举。RSA 是传统公钥加密,只天然支持乘法同态,属于半同态而非全同态,因此不选。

Q5. 自举(Bootstrapping)的核心作用是

单选题 · mid

  • A.扩大密钥规模以抵抗攻击
  • B.刷新密文中的累积噪声← 正确答案
  • C.把明文切分成更小片段
  • D.缩短密文在网络的传输距离

答案:B。自举的本质是在密文上加密地执行解密电路,从而把噪声重置回初始水平,让计算可以继续下去。它不改变密钥规模(A 错),不分割明文(C 错),也不涉及网络传输(D 错),而是针对“噪声膨胀”这一核心瓶颈的对症之策。

Q6. CKKS 与 BGV/BFV 最关键的差异是

单选题 · mid

  • A.CKKS 不支持任何加密运算
  • B.CKKS 面向近似计算而非精确← 正确答案
  • C.BGV 不需要噪声预算管理
  • D.BGV 只能处理单个数值

答案:B。CKKS 主动允许结果携带微小误差,换来对浮点数和高效运算的支持,特别适合机器学习;BGV/BFV 追求整数精确。CKKS 完全支持加乘运算(A 错),BGV 同样需要噪声管理(C 错),BGV 也支持密文打包多值(D 错)。

Q7. 全同态加密实际落地的主要瓶颈包括

多选题 · hard

  • A.密文膨胀导致通信开销大← 正确答案
  • B.密文运算比明文慢多个数量级← 正确答案
  • C.安全性完全依赖硬件隔离
  • D.密钥管理与切换非常复杂← 正确答案

答案:ABD。FHE 的密文体积可膨胀几十到上千倍(A),运算速度慢 5~6 个数量级(B),多层计算还要频繁做密钥切换和模数切换(D)。FHE 的安全性基于数学困难问题而非硬件隔离(C 错),这恰恰是它相对 TEE 的优势。

Q8. 当密文噪声逼近预算上限时,最稳妥的操作是

单选题 · hard

  • A.立即更换主密钥重新加密
  • B.执行自举刷新噪声水平← 正确答案
  • C.减小明文缩放因子
  • D.把密文传给第三方处理

答案:B。噪声逼近上限意味着下一次运算可能导致解密失败,此时应执行自举把噪声降回安全区。更换主密钥需要重新加密全部数据,不解决当前密文的噪声问题(A 错);缩放因子由方案参数决定,不能随意减小(C 错);传给第三方只是转移问题(D 错)。

Q9. 半同态加密与全同态加密的核心区别是

单选题 · easy

  • A.支持的密文运算种类数量不同← 正确答案
  • B.加密算法实现难度不同
  • C.密钥长度完全不同
  • D.密文长度完全不同

答案:A。半同态只支持一类运算(要么加法、要么乘法),全同态支持加法和乘法任意组合,从而能计算任意函数,这是两者最本质的差异。算法难度、密钥长度、密文长度都是衍生特征,不是定义性区别。

Q10. 下列哪些是改善全同态加密性能的可行手段

多选题 · hard

  • A.用明文打包实现批处理← 正确答案
  • B.使用 GPU/FPGA 加速多项式运算← 正确答案
  • C.放弃噪声预算管理简化实现
  • D.混合 FHE 与 TEE/MPC 分工协作← 正确答案

答案:ABD。明文打包(SIMD)让一次密文运算处理多个明文(A),GPU/FPGA 能大幅加速 NTT 与多项式乘法(B),混合架构则扬长避短、把 FHE 用在最需要的地方(D)。放弃噪声管理必然导致解密出错或安全崩溃(C 错),这不是优化而是自毁。