当业务开始把大模型推理、用户画像、个性化搜索放进云端的时候,最先被挑战的往往不是模型效果,而是“数据和隐私能不能被安全地交给服务方”。早期的做法是传输前加密、内存中隔离,再进一步是可信执行环境;但若你希望数据在服务端始终以密文状态参与推理,那么同态加密(Homomorphic Encryption, HE)就成了绕不开的技术方向。
本篇文章围绕“Google 正在让私有 AI 通过同态加密走向实用”的话题,从同态加密的基本原理、工程约束、典型 AI 场景,到可直接运行的 Python 加密推理 Demo,整理一套适合入门到工程落地的完整笔记。无论你是做后端服务、隐私计算,还是正在调研 AI 模型部署中的数据保护方案,都能按本文思路快速建立认知并动手验证。
1. 从“私有 AI 不隐私”谈起
1.1 AI 服务背后的隐私错位
现阶段的 AI 服务,尤其是云端推理,普遍采用“用户传明文 -> 服务端计算 -> 返回明文结果”的模型。用户为了得到模型能力,不得不把文本、图片、搜索词、业务数据全部暴露给服务方。这在很多场景下并不等价于用户真正知情同意,更多时候是“没有别的选择”。
更深层的矛盾来自模型本身的价值:
- 模型权重是服务方的核心资产,不能直接交付给用户;
- 用户输入是用户的核心隐私,不能明文上传;
- 可预测的业务逻辑如果被批量探测,还可能形成模型窃取、数据重放等安全风险。
传统的 TLS 加密只保护了网络传输过程,服务端拿到数据后仍然能直接读取明文。解决“数据可用不可见”的关键,并不是再加一层传输加密,而是让计算本身发生在密文上。这就是同态加密被称为“隐私 AI 最终答案之一”的原因。
1.2 同态加密到底是什么
同态加密是一种允许直接在密文上执行计算的加密技术。用公式可以直观表达为:
Enc(a) ⊕ Enc(b) = Enc(a + b)如果定义一种对应的密文运算“⊕”,那么加密后的数据经过计算再解密,得到的结果与明文上执行相同计算的结果一致。根据支持运算程度的不同,HE 可分为几个层次:
- 部分同态加密(PHE):只支持加法或只支持乘法,例如 RSA 乘法同态、Paillier 加法同态;
- 近似同态加密(Somewhat HE):支持一定深度的加法和乘法,但深度超过上限后噪声膨胀,结果无法正确解密;
- 全同态加密(FHE):理论上支持任意深度的加法和乘法,代表方案有 BFV、BGV、CKKS、TFHE 等。
AI 推理本质上是大量矩阵乘法、卷积、激活函数的组合,所以能否同时支持加法和乘法,决定了该方案能否用于神经网络。这也是 Google 等团队研究“私有 AI”时聚焦全同态加密或层次同态加密的原因。
1.3 为什么一直说“不实用”
提到同态加密,很多开发者的第一反应是“性能太差,工业界用不了”。这种印象并非没有依据。
同态加密的核心瓶颈在于三个层面:
- 密码学开销:密文尺寸通常是明文的几十到上千倍,密文乘法远比明文乘法复杂;
- 噪声管理:每次密文乘法都会扩大噪声,必须通过重线性化(relinerization)、模数切换(modulus switching)控制噪声;
- 算子不匹配:ReLU、Softmax、除法等 AI 常用非线性函数,很难直接拆解成有限次的加法和乘法。
因此,把 HE 从学术论文推进到 AI 工程,真正困难的不是“加密数据可计算”这个结论,而是如何让推理框架、编译器、硬件加速器和模型量化策略协同工作,在可接受的时延内完成密文推理。
2. 先把 HE 的关键设计搞清楚
2.1 四种常见 HE 方案怎么选
在实际落地时,首先要分清底层使用哪种 HE 方案。不同方案在数据编码、计算深度、性能偏好上差异很大。
| 方案 | 支持的密文运算 | 适合的数据类型 | 常见用途 |
|---|---|---|---|
| BGV/BFV | 加法、乘法 | 整数、有限域元素 | 离散特征、规则引擎、整数运算 |
| CKKS | 加法、乘法 | 浮点数、复向量 | 水平联邦学习、矩阵运算、AI 推理 |
| TFHE | 加法、二进制门电路 | 布尔值、整数位电路 | 安全比较、查表、逻辑分支 |
| Paillier | 加法 | 整数 | 聚合统计、求和场景 |
需要注意,BGV/BFV 和 CKKS 都支持“批量编码”。BFV 适合把多个整数打包进同一个明文多项式,CKKS 则适合把浮点向量批量编码后执行 SIMD 风格运算。神经网络的权重和特征图非常适合用向量打包表示,所以 CKKS 方案在 AI 推理研究中更常见。
2.2 编码、加密、计算与解码链路
一个 HE 推理系统通常不会直接把“人类可读的权重”送去加密,而是先经过编码器转换为同态明文结构,再进行加密。
基本的计算链路如下:
- 将明文数值编码到多项式环或向量槽位;
- 用公钥加密为密文;
- 在密文上执行加减乘等运算;
- 必要时执行重线性化,降低密文大小和噪声;
- 将结果返回给持有私钥的一方;
- 解密后得到明文结果。
对开发者来说,最容易踩坑的地方是“编码”而不是“加密”。例如 BFV 使用整数模 t 表示明文,超过 t/2 的负数会被映射成模 t 的大整数。若计算中间结果溢出明文模数,解密结果会发生回绕,程序不一定报错,但数值会完全错误。
2.3 噪声增长是绕不开的工程限制
可以把 HE 密文理解为“真实数据 + 一层随机噪声”。每次乘法都会让噪声显著增长,当噪声超过阈值,解密时无法取出原始信号。
因此,全同态加密在执行一轮深层计算时,还需要做两件事:
- 重线性化:把乘法后膨胀的三元素密文压缩回两元素,控制密文膨胀。
- 模数切换:通过降低模数抵消一部分噪声增长,同时也会降低可继续计算的深度。
这也是 HE 推理“按深度设计”的根本原因。由于深度限制,把神经网络的非线性层直接替换成高次多项式并不划算,工程上更倾向于使用低次多项式近似激活函数,或者在客户端解密后完成最终非线性判断。
3. 从 Google 视角看私有 AI 的实用性路径
3.1 想保护的是哪一方的数据
在讨论 Google 或任何企业的同态加密实践前,先要厘清一条容易混淆的边界:同态加密并没有同时保护“模型权重”和“用户输入”两方。
典型的隐私推理有两种模式:
- 用户输入加密,模型权重明文:服务端用明文权重对密文输入做推理,返回加密结果。重点保护用户查询内容。
- 模型权重加密,用户输入明文:用户用模型公钥加密自己的输入?不对,这里是保护模型权重,常见于模型分发场景。
由于真正有价值的商业模型通常不直接暴露给用户,业界更常见的“私有 AI”其实是第一种。用户可以把搜索词、图片、文本加密后发给服务端,服务端用公开模型完成一次计算,全程看不到用户输入。
3.2 搜索、推荐与私有信息检索
Google 的很多核心业务都涉及大规模检索。传统搜索场景中,服务端可以通过用户搜索日志优化推荐,但这同时也带来很大的隐私隐患。
如果引入同态加密,一个自然的落地形态是:用户对查询条件做同态加密,服务端在密文上计算“哪些候选文档与查询最匹配”,最后仅返回命中的结果。服务端不知道查询关键词,也不知道最终用户点击了哪一条。这里的检索并不需要复杂的神经网络推理,涉及大量加法和比较运算,是 HE 更容易工程化的场景。
不过必须指出,端到端私有搜索的整体链路远比“计算相似度”复杂。索引结构、Top-K 排序、缓存、个性化模型都可能泄露查询隐私。Google 这类企业的价值,不只是实现一个 HE 算子,而是把搜索系统中不同环节都改造成满足隐私边界的版本。
3.3 神经网络推理的密文化
随着大模型落地,另一个方向是把神经网络的完整推理过程放到同态加密环境中。
对于线性层,例如全连接层和卷积层,HE 可以胜任,因为本质是乘法和累加。但对于 ReLU、MaxPool、Softmax 这样的非线性操作,HE 很难直接执行。目前常见做法有两种:
- 使用多项式近似激活函数,例如用低阶多项式拟合 ReLU;
- 引入 TFHE 的查表能力,把非线性函数以密文查找表方式实现。
大模型的注意力机制包含 Softmax 以及大量的归一化计算,在密文上执行会消耗极深的乘法预算。因此,当前研究往往停留在“中等规模模型”或“推理切分”层面,把一块可以密文计算的部分放入 HE,其余部分留在明文或可信边界内。
3.4 为什么现在“开始变实用”
很多人关注到 Google 这条新闻,是因为技术信号变了。近年的变化主要体现在几个方面:
- 硬件加速:GPU、FPGA 和专用加速器开始针对大整数乘法、NTT 变换做优化;
- 编译工具链:出现了从高级语言到 FHE 电路的转译方案,降低了开发门槛;
- 模型量化:把浮点网络改成低比特整数网络,使得 BFV 这类整数方案有机会参与推理;
- 编码封装:成熟开源库把多项式、密钥、噪声控制封装成高度抽象 API,普通后端开发不需要从头读懂数论。
所以,让私有 AI 变得“实用”,是一个系统工程问题,密码学只是其中一个基础组件。真正的突破点是算子编译、模型压缩、密钥调度和硬件协同。
4. 手把手:用 Python 实现一个 HE“私有推理”Demo
前面解读了纸上原理,下面回到代码。这段演示的目标不是复现 Google 的生产系统,而是让你在本地搭建一个小型同态加密运算示例,直观理解“密文乘积 -> 解密得到明文结果”的过程。
4.1 环境准备
本文以 Ubuntu 22.04 或 macOS 环境为例,Python 环境中需要安装 Pyfhel。
Pyfhel 是基于微软 SEAL 的 Python 封装,支持 BFV/BGV/CKKS 等方案。它比较适合用来学习 HE 的工程接口。
pip install pyfhel如果你更熟悉 OpenMined 系列,也可以参考 TenSEAL:
pip install tenseal需要说明的是,不同同态加密库的 API 迭代速度较快。建议先按本文思路理解完整流程,再根据自己所使用的库版本调整上下文参数。
4.2 验证两个整数在密文域相乘
我们先把一个乘法的链路跑通。BFV 模式适合加密整数,先建立一个 BFV 上下文,生成公钥、私钥和重线性化密钥。
from Pyfhel import Pyfhel # 1. 初始化 BFV 上下文 HE = Pyfhel() HE.contextGen(scheme="bfv", n=4096, t=1032193) # 2. 生成密钥 HE.keyGen() HE.relinKeyGen() # 3. 明文数据 x = 7 w = 9 # 4. 加密 enc_x = HE.encryptInt(x) enc_w = HE.encryptInt(w) # 5. 密文乘法 enc_result = HE.mult(enc_x, enc_w) enc_result = HE.relin(enc_result) # 6. 解密 result = HE.decryptInt(enc_result) print("明文期望结果:", x * w) print("密文解密结果:", result)这段代码的运行结果会打印相同的 63。你可能会觉得这显得很基础,但它揭示了关键一点:只要密文乘法能正确工作,我们就能把神经网络中的权重乘法迁移到同态加密域。
这里要强调一个细节:密码学乘法之后,需要调用relinKeyGen()并执行relin()。如果没有生成重线性化密钥,密文会膨胀,后续计算性能会快速劣化。如果示例库 API 有差异,请优先查找你当前版本文档中的relin方法。
4.3 实现一个简单的加密线性推理
一个神经元的前向计算可以表示为:
z = w1 * x1 + w2 * x2 + b如果 x1、x2 来自用户,w1、w2 和 b 是服务端模型的参数,那么我们可以让用户加密 x1 和 x2,服务端在密文上完成乘加,再返回加密结果。
为了模拟真实架构,我们构造三个角色:
- 客户端:持有私钥,加密输入,解密最终结果;
- 服务端:只持有公钥和模型权重,在密文上执行
z = w1*x1 + w2*x2 + b; - 模型权重:明文存储在服务端。
按照明文计算,先写一个对照版本:
def plain_inference(x1, x2): w1 = 3 w2 = 5 b = 1 return w1 * x1 + w2 * x2 + b print(plain_inference(4, 6))明文结果是3*4 + 5*6 + 1 = 43。
接下来是加密推理版本。客户端加密输入后,把两个密文发送给服务端;服务端把模型权重作为明文乘进去。
def encrypted_inference_demo(): # 服务端可公开的模型参数 w1 = 3 w2 = 5 b = 1 # 初始化上下文与密钥,实际中客户端完成 HE = Pyfhel() HE.contextGen(scheme="bfv", n=4096, t=1032193) HE.keyGen() HE.relinKeyGen() # 客户端明文输入 x1 = 4 x2 = 6 # 客户端加密输入 enc_x1 = HE.encryptInt(x1) enc_x2 = HE.encryptInt(x2) # 服务端:密文与明文权重乘法 enc_t1 = HE.mult(enc_x1, HE.encryptInt(w1)) enc_t2 = HE.mult(enc_x2, HE.encryptInt(w2)) enc_t1 = HE.relin(enc_t1) enc_t2 = HE.relin(enc_t2) # 服务端:累加 enc_z = HE.add(enc_t1, enc_t2) enc_z = HE.add(enc_z, HE.encryptInt(b)) # 客户端解密 z = HE.decryptInt(enc_z) return z注意,这里的w1也执行了encryptInt。严格来说,明文权重并不需要加密,可以直接使用“明文乘法”。许多库也提供了明文乘法接口。为了把链路写清楚,例子中先加密权重,服务端看到的是一个无法解密的权重密文。
实际部署中要权衡的是权限模型:
- 如果把权重加密后发给服务端,服务端无法直接使用权重做检索或调试,但它也不会泄露模型明文;
- 如果权重明文放在服务端,那服务端有机会复制权重,这时“隐私”主要保护的是用户查询本身。
4.4 把流程抽象成类
业务代码不适合把 HE 上下文、密钥生成和推理逻辑全部揉在一起。我们把上面的思路整理成一个简单的PrivateInferenceService:
class PrivateInferenceService: def __init__(self, weight1, weight2, bias): self.w1 = weight1 self.w2 = weight2 self.b = bias def predict_encrypted(self, enc_x1, enc_x2): # 该接口位于服务端,无法看到明文 x1、x2 enc_t1 = self.he.mult(enc_x1, self.he.encryptInt(self.w1)) enc_t2 = self.he.mult(enc_x2, self.he.encryptInt(self.w2)) enc_t1 = self.he.relin(enc_t1) enc_t2 = self.he.relin(enc_t2) enc_z = self.he.add(enc_t1, enc_t2) enc_z = self.he.add(enc_z, self.he.encryptInt(self.b)) return enc_z在这个抽象中,he实例必须在服务端初始化,客户端和服务端共享同一套 BFV 上下文参数。生产环境不会直接把私钥暴露在服务端,服务端只持有公钥和重线性化密钥。这里为了演示方便,把加密和解密放到同一个进程里,真实项目需要拆成两个进程或两台机器。
4.5 预期输出与运行说明
当你运行上面的方法时,最终解密输出应该是:
明文推理结果:43 密文推理结果:43这里能看到“密文参与计算但结果保持一致”。如果选择小明文模数t=65537,模型参数又比较大,多次乘法后可能出现回绕错误。遇到结果诡异时,优先检查是否超过了明文模数范围。
5. 常见问题与排查思路
5.1 为什么解密结果变成了模数回绕后的数值
同态加密的明文空间是一个有限域,所有运算都基于模 t。如果计算中出现了超过模数一半的正数,解密结果可能变成一个看起来毫无关系的大整数。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 解密结果比预期大很多 | 明文溢出模 t | 换更大的明文模数,或者把参数取模后运算 |
| 小规模乘法正常,多次累加后异常 | 噪声累计超过阈值 | 调用重线性化并检查乘法深度 |
| 只有第一种参数能正常解密 | BFV vs CKKS 编码方式不同 | 根据数值类型选择 BFV 或 CKKS |
| 同一个 SDK 在另一台机器无法运行 | 编译器、C++ 依赖版本不一致 | 优先使用官方 wheel 或容器运行环境 |
5.2 我可以把现成的 PyTorch 模型直接改造成 HE 推理吗
不能直接改造。PyTorch 模型默认使用浮点张量,权重和激活是动态图。HE 推理要求所有计算深度预先可知,且非线性函数必须做多项式近似。
建议的改造流程:
- 先用 ONNX 或 TorchScript 导出模型计算图;
- 统计每一层的算子类别和乘法深度;
- 把所有浮点权重量化为低比特整数;
- 将 ReLU 等激活替换为多项式近似;
- 把计算图转换为密文友好的算子序列;
- 使用加密向量或打包编码完成批量推理。
这个流程中每一步都有对应工具,但很难做到“零人工介入”。
5.3 服务端能通过多次提交推理结果反推用户输入吗
能。如果在交互式协议中,用户每次都提交不同输入并拿到解密后的明文结果,那么服务端可以把模型当成一个查询接口,通过多次探测逼近用户输入。同态加密只保护“单次计算的数据不可见”,不解决推理接口的滥用问题。
这也是为什么私有 AI 系统通常还需要增加:
- 查询频率限制;
- 结果脱敏;
- 差分隐私噪声;
- 访问审计。
5.4 公钥、私钥、重线性化密钥应该怎么管理
同态加密系统里,至少有三种密钥语义容易被混淆:
- 私钥:只能留在客户端或受信任环境,用于解密;
- 公钥:任何数据方都可以持有,用于加密数据;
- 评估公钥:也就是重线性化密钥。它发给服务端,让服务端能够执行乘法后的压缩,但它不会让服务端解密。
在密钥管理上,一个常见误区是把私钥和评估密钥一起发给服务端。要避免这种错误,需要在系统启动前明确密钥用途,并把私钥落盘策略纳入安全审计范围。
6. 最佳实践:把 HE 放进 AI 工程体系
6.1 先定隐私边界,再选加密算法
很多团队一上来就选 CKKS 或生成大密钥,但忽略了一个问题:我们到底要保护谁的数据不被谁看到?
建议先画一张数据流转图,标清:
- 客户端上送的数据包含什么;
- 服务端运行的模型权重是否敏感;
- 返回结果会不会被服务端记录用于日志分析;
- 是否涉及合规审计下的数据留存义务。
只有明确这些边界,才能判断同态加密用在哪里,哪些地方还需要配合可信执行环境或安全多方计算。
6.2 模型和推理策略要按 HE 的特性重新设计
HE 并不适合原封不动部署一个大模型。应用层可以做的优化非常多:
- 把模型权重量化到 8bit 或 16bit,使 BFV 整数运算效率更高;
- 将激活函数换成低阶多项式,避免高次乘法消耗噪声预算;
- 把大模型切分成“密文区 + 明文区”,只加密关键隐私层;
- 使用批处理编码,把多个独立的样本打包进同一个密文,提高吞吐。
最有效的工程经验是“不要在加密域做所有事”,而是把计算图中最适合 HE 的算子挑出来,让传统安全模块处理其余部分。
6.3 使用容器化封装时注意密钥注入方式
把 HE 服务部署成微服务时,要避免把私钥环境变量直接写死在镜像或应用配置里。推荐使用独立密钥管理系统分发密钥,让每个推理实例只拿到当前任务所需的最小权限。
# 不建议 ENV HE_PRIVATE_KEY="..." # 建议 # 在部署编排平台中通过 secret 挂载注入6.4 性能和安全需要分级评估
同态加密的“安全性”通常由底层密码学方案参数决定,例如多项式阶数 n、明文模数 t、安全强度 bit。参数越大越安全,但性能也会急剧下降。
上线前建议做一组基准测试表,记录不同参数下的执行时间,而不是只跑单条数据就下结论。一个可参考的性能维度:
| 上下文参数 | 单次乘法耗时 | 可推理的最大层数 | 内存峰值 | 适用场景 |
|---|---|---|---|---|
| n=2048,t 较小 | 快 | 低 | 低 | 教学、原型验证 |
| n=4096,中等 t | 较慢 | 中 | 中 | 小型线性模型 |
| n=8192,大 t | 慢 | 高 | 高 | 更深的多层神经网络 |
这些数据会因为机器、库版本而明显变化,建议用脚本自动化测量,避免随手估算。
6.5 从最小可行性开始,不要首次上线就追求全密文推理
真正做私有 AI 项目的经验是:先跑通一个明文等价系统,把 HE 当做一个独立的计算后端替换部分接口,保证接口返回格式不变,再逐步扩大密文覆盖范围。这样既能验证业务效果,也便于定位是密码学参数问题还是模型结构问题。
7. 下一步可以学什么
回到最初的问题:Google 正在让私有 AI 变成工程现实,但这不是靠一个算法就能完成的事。同态加密只解决了“密文可计算”的基础能力,真正让它在业务中跑起来,还需要模型量化、计算图编译、硬件加速、密钥治理和隐私评估的联合投入。
如果你想继续深入,建议从下面几个方向依次实践:
- 阅读 Microsoft SEAL、OpenFHE、Pyfhel 等开源项目的示例代码,重点理解 BFV 与 CKKS 编码差异;
- 把一个简单的单层感知机改造成 HE 推理并测量性能;
- 用一个公开模型,把 ReLU 替换为低阶多项式,观察精度下降程度;
- 实验批处理编码,一次加密多个样本并计算推理;
- 尝试把 HE 推理包装成 REST 接口,打通客户端加密到服务端推理的完整链路。
HE 的门槛主要在跨领域,你需要同时理解密码学参数、模型算子、后端部署和安全审计。建议不要一开始就啃复杂的数论公式,而是用上面这种可运行 Demo 建立直觉,再逐渐往底层研究。