读完这篇,你会得到一份关于同态加密(FHE)推理引擎的完整「体检报告」:哪些指标合格、哪些已经亮红灯、哪些是我们主动放弃的、哪些是还没堵上的漏洞。适合正在评估 FHE 推理可行性,或打算在现有开源实现上继续开发的工程团队。
0. 先说三句话
- 这套同态加密推理引擎能跑——28 层 Transformer 的完整推理链路已跑通。
- 它能复现——在两套独立工作区(一份含既有数据、一份全新克隆)里,逐字节比对通过。
- 它不安全——参数是机制验证级(n=2048),远低于 128-bit 安全标准,不得用于保护真实数据。
这三句是本系列所有结论的前提。下面展开。
1. 安全边界:三条非安全事实
本项目所有参数(n=2048、112 素数内层链、2100 素数自举链)都是机制验证级,不是生产级。在此之外,还有三个具体的非安全事实:
| # | 事实 | 后果 |
|---|---|---|
| 1 | 随机数源是原型级 xorshift,非密码学 RNG | 安全性分析不成立 |
| 2 | 私钥 sk.bin 与密文一起在接力包内流转 | 无密钥托管、无分段解密 |
| 3 | 为换取自举的数值可行性,私钥稀疏度 hw 被降到 8 | 私钥更稀疏、更不安全 |
这三条不是「待改进项」,是「当前状态」。任何引用本项目的输出,都请连带引用这三条。
2. 阻塞级:三个最关键的未解决问题
2.1 位级可复现性缺陷尚未修复
现象:线程数 T23_NT=4 与 T23_NT=8 的输出位级不同。
根因:_Thread_local RNG 以固定常量播种,随机数消耗与线程调度绑定。
方案:按自同构指数 k 播种(代码里已有按 k 的入口),但尚未落地。源码仍是:
c static _Thread_local uint64_t ckks_rng_state = 0x243F6A8885A308D3ull;
影响:所有「位级可复现」声明必须绑定线程数。如果你复现时用了不同的线程数,结果不会逐字节相同。
2.2 精度余量不宽,链尾已有超阈项
| 对象 | 结果 | 最大误差 |
|---|---|---|
| u0(层 0) | PASS 8/8 | 1.27e-03 |
| u0r112(自举刷新后) | PASS 8/8 | 1.27e-03 |
| u26 / u26r112(链尾) | PASS 8/8 | 4.47e-03 ~ 2.30e-02 |
| u27(链尾) | ⚠️ 6/8 | t1h1=3.82e-02、t3h1=7.97e-02(超默认容差 3e-2) |
两个要点:
- 自举几乎不改变数值:1.2712e-03 → 1.2706e-03。自举是「加油」,不是「纠错」。
- 误差随深度增长约一个数量级:从层 0 的 1.27e-03 到链尾的 2.3e-02。
我们不调容差把它「变成通过」,但「这两项算不算失败」还没有定论。
2.3 密文 attention 的定标越界无兜底
softmax 用「预定标」替代了 max-sub。一旦真实输入让 score 跑出统计区间,拟合多项式在区间外的行为没有任何保证,而且不会报错。
这是整个系列里最让人担心的一处:它是静默的,且随输入而定。你可能拿到一个「跑通了」的结果,但它在数学上是错的。
3. 重要的技术缺口(按严重程度排序)
| # | 缺口 | 说明 | 篇目 |
|---|---|---|---|
| 1 | 自举域变换未归因 | coeff_to_slot + slot_to_coeff 占自举 80%,但「为什么贵」只有推测(疑为内存带宽),没有微架构 profiling | 第 15 篇 |
| 2 | 精度预算无闭环 | 逐层独立定标 + 事后整链验收,没有「从 28 层反推每层可用误差」的推导 | 第 9 篇 |
| 3 | 无最小可用链长扫描 | boot 编到 2100,实际用多少、能压到多少,是拍的 | 第 5、7 篇 |
| 4 | 「缺失即默认」模式未清理 | 全树同类文件读取需逐一审查 | 第 8 篇 |
| 5 | DIRECT_LAYERS 是固化调参 | 不是推导规则,换模型不能自动适配 | 第 8 篇 |
| 6 | 协议无版本号、无输入指纹 | 参数一变,旧包新包长得一样,下一棒无法验证输入 | 第 11、14 篇 |
| 7 | 线程池无非重入断言、无 A/B 数据 | 非可重入是静默失败;「省了多少」没有同轮实测 | 第 12 篇 |
| 8 | NTT 只做 radix-2 | 未 SIMD 化;两条模乘路径未做交叉验证 | 第 3 篇 |
| 9 | 预处理脚本未做完整性对拍 | 只验了权重(9/9)与 silu(26/26),拟合脚本产出未逐字节对拍 | 第 2 篇 |
| 10 | 换模型需整体重跑 + 人工判断 | 定标、拟合、SiLU 路径选择都依赖对明文参考的统计 | 第 9 篇 |
4. 性能账本:已知的和未知的
4.1 已知数字(本项目,AMD Ryzen 7 9800X3D,8 核,纯 CPU)
- 一跳(lay + boot)约 1.8 小时(≈ 6205 s)
- 其中自举(boot)约 1.2 小时,层内前向约 0.6 小时
- 自举的两段域变换(coeff_to_slot 1688 s + slot_to_coeff 1716 s)合计约 3400 s,占自举耗时的 80%
4.2 未知的
- 域变换为什么贵,没有微架构归因。我们只测了「这段花了多少时间」,没有测缓存命中、带宽、指令数。要证实「瓶颈是带宽」,需要额外一轮 profiling——按项目纪律,这里标注为未验证的假设。
- 单跳耗时里「内存带宽」的占比未测。如果瓶颈真是带宽,优化方向应该是减少取数(降链长、减密钥体积),而不是加速计算。
4.3 与前沿的横向对比(仅供参考,非本项目数据)
| 系统 | 硬件 | 结果 |
|---|---|---|
| Cerium(arxiv 2512.11269) | NVIDIA GPU(多 GPU) | 自举 7.5 ms;BERT-Base 8 s;Llama-3-8B 134 s |
| Odin(arxiv 2609.12378) | 单张 H100 80 GB | Llama-3-8B 366.4 s(端到端) |
| Cachemir(arxiv 2602.11470) | GPU | Llama-3-8B 每 token < 100 s |
| PQC-LLaMA-3(arxiv 2604.12168) | i9 CPU | 237 ms/步,最高 80 token/s,精度 98% |
本项目不主张与任何其他方案的优劣对比——跨平台、跨实现的绝对值不可比。
5. 已知取舍:我们主动做了哪些选择
这些不是 bug,是主动权衡。列出来是为了避免被当成疏漏:
| 取舍 | 我们换到了什么 |
|---|---|
| hw = 8(私钥更稀疏、更不安全) | 自举折叠的混叠变小 → sin 逼近只需 9 次多项式 |
| 保留 BFV 那代实现不删 | 它是最简正确性自检(T1–T6),也是「为什么走不通」的原始证据 |
| 自研线程池不支持嵌套并行 | 更低的调度开销 + 确定的分块 |
| 数据包不随仓库分发(约 7 GB) | 仓库体积可控;代价是「必须能自助生成」(已验证逐字节一致) |
| 不追求链尾全项通过 | 照实记账,而不是调容差 |
| 接力包内含 sk.bin | 免去密钥分发协议;代价是没有隐私性质 |
6. 文档与一致性欠账
| # | 欠账 |
|---|---|
| 1 | vllm_ckks.h 顶部「架构」段仍写「4 个 60-bit 素数,支持深 3」,而 CKKS_NPRIMES 默认已是 32——描述停留在最初原型 |
| 2 | boot 日志中 out np=2083 与编译期 2100、落盘 112 的精确关系未核实,我们在文档里显式标注而不做断言 |
| 3 | phase 2 (l1) 与 phase 6 (lay) 语义重叠,属开发阶段遗留 |
| 4 | fin 阶段的判据与前面几层不同,描述不够显眼——我们自己复现时撞过 |
| 5 | 各篇标注的「未核实项」会随代码演进过期,需要一次统一的审计 |
7. 如果你想接着做:从哪开始
按「收益 ÷ 难度」排序,前三件是:
- 落地 RNG 按 k 播种(第 2.1 条)。结构现成、方案明确、影响面清晰。做完之后,「位级可复现」才能不带星号地讲。顺手在 CI 里加一条「不同线程数比字节」的回归检查。
- 给自举的域变换做一次真正的 profiling(第 3.1 条)。80% 的时间在那里。哪怕只是确认「瓶颈是带宽还是算力」,就能把优化方向从「优化卷积」改成正确的那个。
- 让 DIRECT_LAYERS 变成推导出来的规则(第 3.5 条)。判据(窄值域→直接拟合)原理上可以从明文参考统计自动生成。这一步做完,「换模型」才有自动适配的可能。
8. 一件我没能做到的事
本系列写到这里,有件事必须说清楚:
我们还没有让这套东西「陌生人可用」。 仓库、文档、Release 资产都准备好了,但还没走到能被外部独立复现那一步——因为公开访问的入口(仓库推送 + Release 上传)还没完成。
也就是说,本系列所有「可复现」「可独立验证」的结论,目前都是我们自己在两套独立工作区里验证的,还没有第三方跑过。
这正是最初那 21 跳待认领的原因,也是这套设计存在的意义。
如果你读到这里,并且手上有一台愿意跑 1.8 小时的机器——欢迎接手一跳。
附:全系列 16 篇索引
| 篇目 | 主题 |
|---|---|
| 第 1–2 篇 | 预处理与数据对拍 |
| 第 3 篇 | NTT 与多项式乘法 |
| 第 5 篇 | 链长与参数选择 |
| 第 7 篇 | 自举流水线 |
| 第 8 篇 | DIRECT_LAYERS 与 SiLU 路径 |
| 第 9 篇 | 逐层定标与精度预算 |
| 第 10 篇 | 密文 attention 定标 |
| 第 11 篇 | 协议与接力包 |
| 第 12 篇 | 线程池 |
| 第 13 篇 | 位级复现 |
| 第 14 篇 | 接力验证 |
| 第 15 篇 | 性能剖析(1.8 小时账本) |
| 第 16 篇 | 未完成清单与已知边界(本篇) |
系列完。全系列 16 篇。若发现任何与源码不符之处,以源码为准——本文档的每一处断言都标注了它的依据与不确定性。