【FHE 同态加密】我们如何实现同态加密推理(四):为什么我们最终放弃了 BFV——明文模上的除法如何逼死 GELU(纯 C11 · 零依赖)

简介: 本文探讨同态加密大模型推理的方案选型:BFV因明文模环不支持非整数系数(如GELU/SiLU多项式),难以适配实数神经网络;CKKS凭借scale机制与模数切换,实现可控近似计算,成为更优选择。(239字)

关键词:同态加密 | FHE | BFV | CKKS | 方案选型 | 明文模 | GELU | SiLU | 密文非线性 | 大模型推理

导读:做同态加密推理,第一个绕不开的选择是"用哪套方案"。本篇记录我们为什么最终从 BFV 换到 CKKS:不是 BFV 不好,而是它的明文模环上"除法"得到的是模数意义下的解,而非整数系数的 GELU/SiLU 逼近多项式塞不进这个环。这是同态加密推理里关于"语义适配"的一次具体取舍。

项目仓库
Gitee 主仓:https://gitee.com/pei-xiaoguang/kestrel-llm
GitHub 镜像:https://github.com/m13253246268-ship-it/kestrel-llm

相关文档
术语与数据口径 |
性能与基准 |
构建与复现 |
快速上手 |
架构总览

0. 一句话结论

我们引擎里同时留着两代同态加密实现:vllm_fhe.c(BFV 风格)和 vllm_ckks.c(CKKS 风格)。

换代不是因为 BFV "不好",而是因为一个非常具体的语义问题:在 BFV 的明文模环上做除法,得到的是"模数意义下的解",不是实数除法。而 Transformer 里那些非线性函数(GELU、SiLU)的逼近多项式天然带非整数系数——它们塞不进整数模环。

CKKS 用 scale 管理近似误差,才让这条路走得通。


1. BFV 那一代的真实设计

先把话说明白:第一代实现不是玩具,它有一份完整、自洽的设计。以下摘自 include/core/vllm_fhe.h 的头注释(原文):

项 值 出处
方案 Ring-LWE / BGV 风格 leveled HE(Fan-Vercauteren BFV) vllm_fhe.h
环 R_q = Z_q[x]/(x^n+1),n = 1024 VFHE_N_DEFAULT
密文模 q = 2^64 - 2^32 + 1(Goldilocks prime,64-bit 域) VFHE_Q_BITS 64
明文模 t = 12289 VFHE_T_DEFAULT
缩放 Delta = floor(q/t),明文编码为 Delta * m(BFV scaling) 头注释
乘法语义 3 分量 tensor + (t/q) rescale;解密用 (1, s, s^2) 头注释
为什么选 t=12289 t-1 = 12288 = 6 × 2048,支持 n=1024 的 SIMD 槽位打包 头注释
噪声 均匀小范围 [-B, B),B=8 VFHE_B_NOISE
私钥 稀疏三元 {-1,0,1},非零个数 hw = 64 VFHE_KEY_HW

1.1 一个刻意的取舍:不做重线性化

头注释里写得很直接(原文):

不做 relinearization:一次乘法分量数 = deg(a)+deg(b),解密使用 1, s, s^2, ... 最高 5 分量(深度 2)。

代码里的体现是:

/* 密文分量数:2 (level1) / 3 (level2) / 5 (level3) ... */
#define VFHE_CT_MAX_COMP 5

这是个典型的原型期取舍:跳过 key-switch(重线性化)能少掉一整套密钥生成与数字分解逻辑,代价是密文尺寸随深度按分量数增长,而且深度被硬顶在 2。

1.2 它已经跑通了什么

同一份头文件里列出的自测项,说明这一代确实端到端验证过:

T1 定点编码往返精度
T2 对称/公钥 加密-解密往返
T3 同态加法(含负数中心化)
T4 同态乘法(深度 1)
T5 混合表达式 ((a*b)+c) 深度 2
T6 定点数同态加/乘

注意 T4 标注"深度 1"——这不是谦虚,是硬限制。


2. 出问题的地方:非整数系数无处安放

Transformer 的非线性激活不是多项式。工程上的做法是用多项式逼近它,例如 SiLU / GELU 的逼近式、LayerNorm 里的倒数、以及自举里的 sin 折叠。

这些逼近式的系数是实数,比如 0.5x + 0.7978...x³ - ...。

在 BFV 里,明文住在 Z_t(模 t 的环)里。你想表示 0.7978,只能把它"放进"模环——比如取 round(0.7978 × Delta)。问题在于:接下来所有的运算都在模 t 的意义下进行,除法给出的不是实数除法,而是模逆。

于是会出现两种后果:

  1. 精度语义错位:t 上的模运算结果,在解密后需要除以 Delta 才回到实数。当中间结果经过多次乘法与"除法",噪声不再只是"加性小扰动",而是与模数结构耦合——你很难再给出干净的误差界。
  2. 动态范围被 t 卡死:t=12289 只有约 13.6 bit。头注释里已经标注了这条硬限制(原文):

    深 2 需 t < ~5150,仅深 1

    也就是说,为了保住深度 2 的正确性,t 要压到 5150 以下;而我们默认的 12289 只够深度 1。这与 T4 标注的"深度 1"完全对应。

这就是死结:一个 28 层的模型,加上自举内部几十层深的折叠逼近,需要的乘法深度是几十,而 BFV 原型被卡在 1~2。

这里要特别说明:BFV 本身不是错的,也不是弱于 CKKS。BFV 适合精确整数运算的场景(例如需要精确的整数聚合、计票、集合运算)。我们的场景是"近似实数神经网络的推理",与 BFV 的精确整数语义天然不匹配。 头部注释里把这条判断写得很清楚,原文:

非整数系数多项式(GELU 等)在 BFV 明文模下不可行(模环除法给出模数解),CKKS 的 scale 管理 + 模数切换(rescale)天然支持——本模块解决该缺口。


3. CKKS 补上了什么

第二代 vllm_ckks.c 换了两件事:用 RNS 多素数链代替单一模数,用 scale 代替"精确整数除法"。

项 BFV 那代 CKKS 这代 出处
密文模 单个 64-bit Goldilocks q RNS 链:CKKS_NPRIMES 个 60-bit 素数,每个 q_i ≡ 1 mod 2n vllm_ckks.h
实数编码 定点 round(x · 2^K) mod t scale = 2^60:X = round(x · S) CKKS_SCALE_BITS 60
乘法后处理 (t/q) rescale(BFV scaling) rescale = 模数切换切掉一个素数,把 scale 从 2^120 拉回 2^60 ckks_rescale()
深度瓶颈 t 的大小(t<~5150 才够深 2) 链长(NPRIMES),32 个素数 ≈ 常规深 10 CKKS_NPRIMES 注释
乘法分量 不做 relin,comps = 深度+2,上限 5 有 relin,3 → 2 分量 ckks_relin()
槽位旋转 无 Galois 自动态 + key-switch ckks_rotate_k()

关键的一句话:CKKS 把"精确"换成了"可控的近似"。 乘法后 scale 从 2^60 翻到 2^120,rescale 切掉一个素数把它拉回来——误差不再被模数结构耦合,而是变成可以被 scale 追踪的近似误差。这才是能量化误差、逐层定标(本系列第 9 篇)的前提。

还有一个副作用值得单说:CKKS 这代的私钥非零个数从 hw=64 降到了 hw=8。原因写在头注释里(原文):

降 hw 控制 bootstrapping 折叠混叠:混叠 I ~ hw/2 = 4,sin 逼近多项式 9 次;原型无安全可接受。

也就是说,为了自举的折叠逼近能收敛,我们主动把私钥稀疏度降下来——代价是安全性进一步退化(本项目本身就不主张安全强度,见 §5)。这类"为了数值可行性牺牲密码学参数"的取舍,在原型阶段是常态,但必须写清楚。


4. 两代并存:为什么不删掉旧的那代

vllm_fhe.c 至今留在源码树里。原因有三:

  1. 它是槽位打包与定点编码的参考实现。vllm_ckks.c 的头注释明确写着它复用了 vllm_fhe 的评估同态(R_t ≅ ∏ F_t)与槽位打包思想。
  2. 它是自测链条的基础。vfhe_self_test() 的 T1–T6 是"最简单的正确性验证",改动底层的 NTT 或模乘时,它是最快的一道防线。
  3. 它是一份"反面教材的正本"。把"为什么这条路走不通"的原样设计留在树里,比写一篇总结文档更有说服力——注释里的那条限制(t<~5150,仅深 1)就是证据本身。

代价也很实在:两套密钥/密文结构、两套自测、两份维护成本,而且新人容易走错门。这个取舍我们目前是选择保留。


5. 安全边界(务请读完)

本文所述参数为机制验证级,远低于 HE 参数标准的 128-bit 水平,
不得用于保护真实数据。
本文主张的是:设计取舍的工程记录。
本文不主张:安全强度、性能优越性、与 BFV/CKKS 任一方案本身的优劣评判。

特别提醒:本文 §3 提到的 hw=8、非密码学 RNG、以及 n=2048,共同意味着这套实现不具备密码学安全强度。它验证的是"近似实数神经网络能不能在密文下算得动、算得对"。


6. 这一篇的未解问题

  1. t 的上界推导我们只做了实测:头注释里"深 2 需 t < ~5150"是一个经验界,我们没有把它整理成一条可复用的噪声增长公式。如果谁有干净的推导,欢迎指教。
  2. 换到 CKKS 之后的误差传播仍是逐层实测:scale 让误差"可追踪",但"可追踪"不等于"有闭式界"。链尾出现的超阈项(u27 中 t1h1=3.82e-2、t3h1=7.97e-2,超出 verify_layer 默认容差 3e-2)就是这个问题的一次现形。
  3. 是否该给 BFV 那代一个明确的退役条件:目前是"保留但不用"。什么情况下可以删、什么时候必须修它,还没有判据。

下一篇我们回到密码学内核的最低层:手写 negacyclic NTT——为什么不用现成库,以及"怎么证明自己写对了"这件事在密文计算里意味着什么。

相关文章
|
14天前
|
人工智能 JSON API
全网刷屏的 Jev 模型正式开放!一手实战测评 + 保姆级教程
全网爆火的 Jev 模型是什么?有什么用?怎么使用?怎么接入 AI 编程工具?效果真的好么?傻子可懂的 Jev 保姆级实战教程 + 项目实战测评来啦
8073 15
|
13天前
|
人工智能 并行计算 PyTorch
秋叶 ComfyUI 2026 整合包 v3.2 完整部署教程:Python 3.13 + Torch 2.13 全栈升级
秋叶aaaki ComfyUI 2026年8月整合包v3.2正式发布!全面升级Python 3.13.11、PyTorch 2.13.0+cu130及ComfyUI v0.30.2,原生支持MiniMax H3、Wan 2.2、Qwen-Image-2.1等2026主流音视频/图像模型,解压即用,无需环境配置。
2091 12
|
12天前
|
人工智能 测试技术 API
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
Jev是TypeSafe AI推出的“系统一模型”,不生成文本,专做毫秒级结构化决策:Choice(多选)、Score(打分)、Noul(是非概率)。响应快193倍、成本低444倍,适合工单路由、内容审核、测试定级等高频判断场景。
1802 4
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
|
11天前
|
人工智能 编解码 并行计算
MiniMax-H3 一键整合包技术文档:8G 显存运行 AI 漫剧制作 —— 角色替换 / 动作迁移 / 文图生视频部署与调参指南
MiniMax H3 是 MiniMax 开源的全模态视频生成模型,支持文/图/音/视多条件输入,输出最高2K、15秒带双声道音频视频。本文档详述其Int8量化版在8GB显存下的本地一键部署、三段式工作流(EDIT/REPLACE/CONTINUE)、参数调优及常见问题排查。(239字)
|
7天前
|
人工智能 Linux 开发者
【2026国内使用】Codex安装过程一篇讲透(Win/Mac/Linux全支持)
Codex是OpenAI推出的AI编程智能体,可读取本地项目、理解需求并自动修改代码。支持桌面GUI、命令行(CLI)及VS Code/Cursor插件三种形态,覆盖可视化操作、终端高效开发与编辑器无缝集成场景,助开发者用自然语言驱动编码全流程。(239字)
【2026国内使用】Codex安装过程一篇讲透(Win/Mac/Linux全支持)
|
26天前
|
人工智能 自然语言处理 安全
阿里云千问办公 QwenWork详细介绍:产品核心能力、典型场景、价格及常见问题解答
千问办公是阿里云推出的一站式AI办公平台,主打"不止于对话,更注重交付",依托通义千问旗舰大模型,用户一句话即可完成数据分析、PPT生成、视频剪辑等复杂任务,直接输出可用成果。产品深度打通钉钉生态与企业OA,覆盖桌面端、网页端,提供企业标准版198元/人/月等多档订阅方案,新用户注册即赠2000积分,适配工程师、HR、财务等多职业办公场景,成为能动手干活的"全能AI同事"。
3845 10
|
21天前
|
缓存 IDE Java
【保姆级】Android Studio下载、安装和汉化教程(2026最新)
Android Studio 是 Google 官方推出的免费 Android 应用开发集成环境,基于 IntelliJ IDEA,内置模拟器、调试器、性能分析及 Compose 界面工具,功能全面,文档丰富,是安卓开发首选工具。(239字)
2196 1

热门文章

最新文章