深夜食堂的厨房里,一位经验丰富的大厨被迫蒙上眼睛做菜。他看不见食材,却要完成“少放盐、多放醋”这种模糊指令;他不能品尝,却要保证出锅后的糖醋排骨“刚刚好”。这正是全同态加密的处境:数据被锁在密文盒子里,计算方看不见内容,却要在密文上完成加法和乘法。过去很长一段时间,同态加密方案像一位只认精确克数的“天平厨师”——所有数据必须先取整成整数才能运算,可机器学习里的权重0.7325、梯度1e-4全是小数,一取整就失真。直到2017年,Cheon、Kim、Kim和Song四位研究者端出了一道新菜——CKKS方案。它像一位“手感厨师”,坦然接受“少许”和“大约”:允许解密结果携带一个可控的小误差,用近似换来了浮点数的全同态计算。蒙眼大厨们终于能炒出小数世界的味道了。
CKKS方案是隐私计算工程师的“浮点密文计算利器”,掌握它能让你在隐私保护机器学习、联邦学习聚合等场景中,把小数数据安全地送上密文计算流水线。
可视化演示
展示CKKS同态加密流程管道、重缩放模数链机制及与BFV方案特性对比,理解近似同态加密核心原理。
本节配有交互动效(进入视口后自动加载,约 3KB)。
CKKS同态加密流程 明文经定点编码后加密,密文上直接执行同态运算 同态乘法后维度增长,需重线性化降维 Encode → Encrypt → Eval(c) → Decrypt CKKS支持近似实数运算的全同态加密管道
背景与动机
深夜食堂,一位蒙眼大厨接到点菜——“糖醋排骨,多一分则过,少一分则柴”。他不能看、不能尝,只能凭手感调味。这恰似同态加密的处境:数据锁在密文盒子里,计算方看不见内容,却要在盒子上完成加减乘除。同态加密的概念早在1978年RSA时代就有雏形,2009年Gentry更是证明了全同态加密(FHE)的可能性。但很长一段时间里,主流方案如BFV都构建在整数明文空间上:数据必须取整成整数模t的多项式才能加密,就像菜单上只允许写“二百五十克”,不允许写“少许”。
可现实世界的数据全是小数。机器学习里的权重0.7325、梯度1e-4、医疗指标3.14159……一旦取整,信息当场丢失。BFV这位“天平厨师”面对浮点数时力不从心:要么牺牲精度,要么放弃计算。CKKS团队决定反转视角——既然“少许”无法避免,那就把它写进菜谱。他们允许解密结果携带一个可控的小误差,让近似成为方案的一等公民:
这条近似解密公式,是CKKS整座大厦的地基。天平厨师纠结的那一克,在手感厨师眼里只是“调味区间”里的一次自由发挥——小数世界的全同态计算,由此打开了大门。
- 内积解锁把密文向量c与密钥向量sk做内积,本质是“用钥匙转动密文盒的锁”。
- 模约减对解锁结果取模q,把大整数拉回多项式环的合法范围,相当于把散落一桌的食材收回盘中。
- 近似恢复解锁后得到的是m+e而非m,e来自加密时注入的噪声和运算中的累积误差,CKKS把这个e当作“可控的酌情剂量”。
核心设计思想
蒙眼大厨的手感不是玄学,而是经验积累出的容错区间:同一道菜,咸度误差在±3%内,客人根本尝不出来。CKKS把这种感觉量化成一个关键词——噪声预算。所谓噪声预算,就是允许误差的最大上界:只要解密结果与真实值的偏差不超过这个界,计算结果就可接受。
为什么这个设计是聪明的?因为机器学习本身就在和噪声打交道:数据采集有噪声、梯度估计有噪声、浮点运算有精度损失,模型对微小扰动天然不敏感。CKKS的近似误差只要控制在一个界内,模型预测结果几乎不受影响。这个界就是噪声预算:
噪声既是误差,也是安全垫。CKKS的安全性建立在RLWE(带误差学习)问题的困难性上——正是“往多项式里藏噪声”这件事,让攻击者无法从密文中恢复明文。误差和安全的双重身份,让“手感”不再是不严谨的代名词,而是一套精密的工程哲学。
- 误差衡量用无穷范数取向量中最大的那个误差分量,作为整体噪声水平——就像一锅汤里最咸的那一口决定了整锅的评价。
- 上界约束噪声不能超过B,B由方案参数决定,超过则明文信息被噪声淹没,结果不可用。
- 预算消耗每次乘法运算都会消耗一部分预算,总预算减去消耗后必须大于0,深度L以内的运算结果才可靠。
消息编解码
把小数做成菜之前,先要切配装盘。CKKS的“切配”就是编码:把N/2个复数(浮点向量)装进一个N次多项式。浮点数的天然形态是“小数+指数”,而多项式系数是整数,直接装会丢小数。CKKS的办法是引入缩放因子Δ:把所有浮点数乘以Δ放大成整数,再嵌入多项式系数。Δ的选择直接决定精度上限——Δ越大,保留的小数位越多,但占用的模数空间也越大。
编码过程可以写成:
解密后,解码操作把多项式系数除回Δ,得到带小误差的浮点向量。Δ不仅决定精度,还参与噪声预算的分配:Δ越大,留给噪声的空间越小,能支撑的乘法深度越浅。切好的食材码放进保鲜盒,大厨蒙着眼也知道每块肉是几两——因为盒子上的标签都是整数。
- 消息嵌入把复数向量映射到环元素,让向量运算在密文上变成多项式运算——就像把食材按菜谱切成特定形状,方便后续下锅。
- 缩放放大乘以缩放因子Δ,将小数转化为整数域里的“大数”,保留浮点表示的位数信息。
- 取整落盘四舍五入为整数多项式,从而可以进一步加密——这里的取整损失极小,因为Δ放大了数值,相对误差被压到了千分之一以下。
加密体系
菜配好了,装进带锁保鲜盒。CKKS采用RLWE公钥加密体系:公钥可以公开分发,任何数据方都能用公钥加密自己的数据;私钥只有数据主人持有,解密时才能打开盒子。RLWE困难性保证:攻击者即便拿到公钥和密文,也无法在合理时间内还原明文,因为他无法区分“带噪声的密文”和“真正的随机数”。
加密过程不是简单地把明文藏进多项式,而是要把明文和噪声一起“揉”进密文对中:
保鲜盒锁得严严实实,钥匙一转,里面还是那道菜——只是带着一点“接触空气后的氧化”。这份氧化就是噪声,但只要控制在预算内,菜的滋味丝毫不减。
- 采样临时数加密方随机选一个“一次性用量”v——每加密一次都重新随机,保证同样的明文每次密文都不同。
- 公钥混合用公钥分量包住明文,相当于把食材裹进面糊,外人看不出馅料。
- 噪声注入e₀、e₁是精心采样的随机噪声,让密文看起来像均匀随机数,从根源上保护明文不被猜出。
- 解密抵消持钥方计算c₀ + c₁·s,展开后v·a·s与v·a·s恰好抵消,剩下的就是明文m和累计噪声e。
密文运算
菜装进盒子还能炒吗?这就是同态加密的神奇之处:密文上的加减乘除,对应着明文上的加减乘除。加法很容易:两个密文对逐分量相加,噪声只是做加法,增长温和。难的是乘法。两个二维密文相乘,展开后会出现密钥s的平方项,密文结构从二维变成三维。每乘一次多一维,几层乘法下来,密文维度指数膨胀,彻底无法继续运算。
重线性化就是破解这个难题的“化学方法”——把混合在一起的s²项重新分离回s项,将三维密文压回二维:
重线性化只解决维度膨胀,不改变噪声水平——它像把混在一起的两勺调料重新装回两个瓶子,调料总量一克没多、一克没少。此外,CKKS还支持密钥切换(把密文从一把钥匙换到另一把钥匙)和密文旋转(把向量里的元素循环移位),后者在实现卷积运算时至关重要。
- 密文乘法展开两个二维密文相乘,得到三维“中间密文”——对应菜谱里突然混进了三味调料,一时分不清彼此。
- 密钥配平利用预先生成的求值密钥,把s²项翻译成s项,误差可以忽略。
- 压回二维把翻译结果加回前两维,得到新的二维密文,可以继续参与后续运算。
与BFV对比
后厨有两位风格迥异的大厨:天平厨师BFV和手感厨师CKKS。BFV出身“精确整数世家”,明文空间是模t的整数多项式环,每个系数都是精确整数;CKKS则把明文空间直接定义为复数向量,小数天然有家可归。这个根本差异,决定了它们在加密、运算和误差表现上的全面分歧。
两者的明文空间对比是方案选择的出发点:
从噪声增长看,BFV的明文模t要求噪声必须严格小于t/2,一旦超出就彻底解密错误;CKKS的明文本身是近似量,噪声超出一点只是结果更模糊,不会“崩塌”。因此CKKS能支撑更深的乘法链,更适合神经网络这类多层计算;BFV则稳稳守住精确整数场景——账单结算、投票计数、精确统计,容不得一丝误差的地方,还得请天平厨师出马。
- BFV明文空间整数多项式环,每个系数都是模t的精确整数——好比一把精确到毫克的天平。
- CKKS明文空间N/2维复数向量,小数在这里不需要取整——好比一把带刻度的量杯,“少许”也有刻度。
- 空间后果BFV把小数取整存储,信息当场损失;CKKS把小数放大存储,解密时只带回可控误差。
参数配置
大厨定配方时有三条线要同时拉紧:误差容忍度(缩放因子Δ)、锅的深度(模数q的比特长度)、安全火候(安全强度λ)。三条线互相牵制——Δ占掉q的位宽,留给噪声的空间就变少;q越大能容纳的噪声预算越多,但安全强度要求q不能无限大;λ越高,运算越慢,工业落地就越难。
参数配置的核心是回答一个问题:这串密文能支撑多少层乘法?工程上用噪声预算来估算可支持的计算深度:
工程实践上,CKKS通常构建一条模数链q = q₀·q₁·…·q_L,每做完一层乘法就执行一次模数切换(rescaling),把明文放大因子和噪声比例同步压缩,相当于给预算“续命”。代价是每切换一次,精度位数减少一部分。火候太猛菜就糊,火候太轻不熟——参数配置就是找那条刚好能端上桌的线。
- 分子位宽q的比特数减去初始噪声位数β,得到整个“预算池”里可用的比特数。
- 分母单层每层乘法噪声放大α倍,占用log₂α位预算——这是每一层乘法必须缴纳的“过路费”。
- 取整深度可用预算除以单层消耗,向下取整得到最大可支持乘法层数L。
应用实践
深夜食堂迎来终局之战:多家医院的大厨各自蒙眼炒出半成品,送到中央厨房拼成一道“联合家宴”。数据不出各自的保鲜盒,模型却能吸收所有参与方的养分——这正是CKKS在隐私保护机器学习中的核心价值。横向联邦学习中,各参与方用本地数据训练模型,把梯度加密后上传;服务端在密文域直接聚合,全程看不到任何明文梯度。
安全聚合的数学表达非常简洁——密文上的平均,解密后近似等于明文上的平均:
如今,Microsoft SEAL、OpenFHE、TenSEAL等开源库已把CKKS变成工业级工具,配套的多项式近似激活函数(如用多项式逼近Sigmoid/ReLU)、SIMD打包编码、密文旋转实现卷积等技术已经相当成熟。一桌菜上齐,谁也不知道谁家放了什么秘料,但所有人都尝到了百家饭的味道——这就是隐私计算与CKKS的浪漫。
- 各方加密上传N个参与方各自把本地模型权重用CKKS加密成密文,提交给聚合服务器。
- 密文平均服务端在密文域直接求和并乘以1/N,全程看不到任何明文数值。
- 解密近似授权方解密后得到带小误差的均值,误差来自各密文的噪声累积,但远小于模型精度阈值。
AI 应用场景
横向联邦学习的梯度聚合
阶段:模型聚合阶段
解决的问题:传统联邦学习要求各参与方把明文梯度上传到中心服务器,存在梯度泄露隐私的风险——恶意服务器可以从梯度反推训练数据。CKKS允许每个参与方在本地加密梯度,服务器在密文上直接求平均,解密后才能得到聚合结果,且只被授权方掌握。
具体案例:三家医院合作训练肺炎影像识别模型,每家医院有各自的患者数据不能出院。每轮训练中,三家医院各自计算本地梯度并用CKKS加密上传,中央服务器对三份密文梯度做加权平均后返回,三家医院解密更新本地模型。训练完成后,模型精度与明文训练几乎一致,而任何一方都无法获知其他医院的原始数据。
私有化推理服务
阶段:模型推理阶段
解决的问题:传统云端推理要求用户把明文数据上传给模型服务方,用户隐私完全暴露在服务方手中。CKKS让用户在本地加密输入数据,云端在密文上直接运行模型(权重已预先编码进密文运算流程),返回加密的推理结果,用户用自己的私钥解密。服务方全程看不到用户的输入和输出。
具体案例:某征信公司的信用评分模型部署在云上,用户输入收入、负债等敏感信息时,先用CKKS加密再发送。云端在密文上完成多项式近似的评分计算,返回密文评分,用户解密得到分数。即使云端服务器被攻破,攻击者拿到的也只是无意义的密文。
Python 演示
"""SimCKKS:用最小模型还原CKKS的近似加密与噪声传播思想。演示四个核心机制:1) 浮点向量 -> 整数多项式(缩放编码)2) 加密:注入高斯噪声3) 密文运算:加法逐项相加,乘法逐项乘积并放大噪声4) 近似解码:误差随乘法深度增长但可控"""import random def encode(vec, delta): """把浮点向量放大 delta 倍并取整,得到整数系数列表""" return [round(x * delta) for x in vec] def decode(poly, delta): """把整数多项式缩小 delta 倍,还原浮点向量(带近似误差)""" return [x / delta for x in poly] def encrypt(plain_poly, noise_amp): """加密:向明文多项式混入高斯噪声""" return [x + random.gauss(0, noise_amp) for x in plain_poly] def add(c1, c2): """密文加法:对应位置相加,噪声增长平缓""" return [a + b for a, b in zip(c1, c2)] def mul(c1, c2, delta, noise_amp): """密文乘法:逐项乘积并除以 delta,再注入新噪声""" return [a * b / delta + random.gauss(0, noise_amp) for a, b in zip(c1, c2)] def main(): delta = 1024 # 缩放因子,决定精度与噪声空间 vec = [1.5, 2.25, 0.75] # 原始浮点明文向量 noise_amp = 4.0 # 单次运算注入的噪声幅度 c = encrypt(encode(vec, delta), noise_amp) unit = [1.0, 1.0, 1.0] # 单位向量,明文乘它不改变数值 print("深度 | 解码结果 | 最大误差") for depth in range(1, 7): c = mul(c, encode(unit, delta), delta, noise_amp) dec = decode(c, delta) err = max(abs(dec[i] - vec[i]) for i in range(len(vec))) print(f" {depth} | {str([round(x, 4) for x in dec]):32s}| {err:.4f}") if __name__ == "__main__": main()
return [round(x * delta) for x in vec]缩放编码:把浮点数放大Δ倍并取整,对应CKKS的“切配装盘”。return [x + random.gauss(0, noise_amp) for x in plain_poly]噪声注入:让密文不可区分于随机数,这是安全性的根基。return [a + b for a, b in zip(c1, c2)]密文加法:逐分量相加,运算直接在密文上进行。return [a * b / delta + random.gauss(0, noise_amp) for a, b in zip(c1, c2)]密文乘法:乘积除以Δ抵消缩放,同时注入新噪声模拟噪声增长。err = max(abs(dec[i] - vec[i]) for i in range(len(vec)))误差统计:用最大分量误差衡量当前深度下的结果可靠度。
常见误区
误区“CKKS解密后小数位会变,蒙了一层误差,这么不严谨的加密肯定容易泄密,不适合商用。”
正解误差是设计参数,不是安全漏洞。CKKS的安全性建立在RLWE困难假设上,噪声恰恰是安全根基——攻击者无法区分“带噪声的密文”和“随机数”。解密误差只影响数值精度,不影响机密性,就像保险柜的锁芯里加了润滑剂,只影响开锁顺滑度,丝毫无损锁的安全性。
为何常见:把“数值近似”和“密码学随机性”两件事混为一谈了。前者是精度管理问题,后者才是安全强度问题。
误区“BFV那么老还只能算整数,CKKS既然是改进版,以后统一用CKKS就行,BFV该淘汰了。”
正解CKKS和BFV是不同场景的两把工具。BFV面向精确整数计算(计费、投票、精确统计),CKKS面向浮点近似计算(机器学习推理)。类比厨房:烘焙需要精确到克的天平,熬汤需要随手的汤匙,用汤匙称泡打粉会失败,用天平舀汤又太慢。
为何常见:“改进版”三个字让人误以为新方案在各方面碾压旧方案,实际上它们是井水不犯河水的平行设计。
误区“CKKS的精度靠Δ撑,那我调到10的18次方,小数位想留多少留多少,岂不美哉?”
正解明文多项式要放进模数q的密文空间,Δ直接占用q的位宽。Δ越大,留给噪声的剩余空间越小,能支撑的乘法深度越浅——就像锅已经装满了食材,再也颠不动勺。工程上Δ的选择必须与乘法深度、安全强度三方博弈,而非单方面追求大。
为何常见:只盯着精度收益,忽略了q位宽是有限资源这一硬约束。
误区“乘法后密文从三维压回二维,这么一压,应该也把噪声顺手清掉一半吧?”
正解重线性化只解决维度膨胀问题,不改变噪声水平。它像把混在一起的两勺调料重新装回两个瓶子,调料的总量一克没少。噪声的降低靠的是模数切换(rescaling)和参数设计,不是重线性化。
为何常见:“压缩”一词让人联想到数据压缩中的有损降噪,但密文的“压回二维”压缩的是结构维度,不是信息中的噪声。
面试题
Q1. CKKS方案解决的核心痛点是什么?
- A.密钥生成速度太慢
- B.浮点数难以同态计算← 正确答案
- C.密文体积膨胀严重
- D.密钥分发过程繁琐
答案:B。CKKS的最大贡献是让浮点数可以直接在全同态加密下做近似计算,避免了取整成整数的精度损失。A是工程优化问题,C是所有FHE方案的通病而非CKKS的核心痛点,D与CKKS设计无关。
Q2. 下面哪个方案最适合精确整数运算?
- A.CKKS
- B.Paillier
- C.BFV← 正确答案
- D.RSA
答案:C。BFV的明文空间是整数多项式环,专为精确整数同态计算设计。CKKS适合浮点近似,Paillier只支持加法同态且偏门,RSA不是全同态方案。类比:精确记账要用天平厨师BFV,而不是手感厨师CKKS。
Q3. CKKS中缩放因子Δ的主要作用是什么?
- A.决定密钥的安全强度
- B.确保明文编码为整数← 正确答案
- C.控制噪声增长速率
- D.影响密文的整体维度
答案:B。Δ把浮点数放大成整数后嵌入多项式系数,这是浮点数据能进入整数多项式环的关键。Δ间接影响噪声预算(占用q位宽),但不直接控制噪声增长;它不决定安全强度,也不改变密文维度。
Q4. 密文乘法之后,CKKS密文的结构发生了什么?
- A.从二维密文变为三维密文← 正确答案
- B.从三维密文变为二维密文
- C.维数保持不变仍是二维
- D.乘法后直接变为明文
答案:A。两个二维密文(c₀,c₁)相乘,展开后出现密钥s的平方项,产生三维密文(c₀,c₁,c₂)。这就是“维度膨胀”问题,需要用重线性化压回二维,就像两勺调料混在一起需要重新分瓶。
Q5. 重线性化(Relinearization)解决的问题是?
- A.密文乘法后的噪声消除
- B.密文乘法后的维数膨胀← 正确答案
- C.密文加法后的密文对齐
- D.密文解密时的误差修正
答案:B。重线性化利用求值密钥把s²项翻译回s项,将三维密文压回二维,解决乘法后密文维度指数膨胀的问题。它不改变噪声水平——调料分瓶装回,总量一克没少,后续乘法需要多次重线性化才能维持密文可用。
Q6. BFV方案与CKKS方案的本质区别是?
- A.密钥长度与算法复杂度
- B.明文空间与近似性不同← 正确答案
- C.加密速度与解密速度
- D.是否支持同态加法
答案:B。BFV的明文空间是整数多项式环,要求精确计算;CKKS的明文空间是复数向量,允许近似误差。密钥长度、速度差异是参数选择的派生结果,两者都支持同态加法,因此B才是本质区别——天平厨师与手感厨师的配方逻辑不同。
Q7. CKKS解密得到的结果是?
- A.完全精确的原始明文
- B.带小误差的近似明文← 正确答案
- C.无法恢复的随机噪声
- D.原始明文经过取整
答案:B。CKKS解密公式是m+e,e是累计噪声。只要噪声在预算内,误差就远小于数据本身,近似明文可用。A是BFV的特征,C误解了噪声的作用,D混淆了编码阶段的取整与解密结果。
Q8. CKKS能支持的密文运算包括哪些?
- A.密文与密文相加← 正确答案
- B.密文与密文相乘← 正确答案
- C.密文循环移位← 正确答案
- D.密文精确取模
答案:ABC。CKKS天然支持密文加法和乘法,配合密钥切换还可以实现密文旋转(循环移位),用于SIMD打包和卷积实现。D“精确取模”是整数运算,需要精确明文结构,CKKS的明文是近似量,无法保证取模结果。
Q9. CKKS噪声预算的设计思想包含哪些?
- A.每个乘法深度消耗一定预算← 正确答案
- B.预算耗尽前结果可正常解密← 正确答案
- C.模数切换能压缩相对噪声比例← 正确答案
- D.噪声预算越少加密强度越高
答案:ABC。每层乘法消耗固定比特的噪声预算,预算耗尽前解密结果可用。模数切换把明文放大因子消除的同时压缩噪声占模数的比例,相当于“续命”。D混淆概念:噪声预算反映的是容错空间,与安全强度无关,安全强度由RLWE参数决定。
Q10. CKKS在隐私保护机器学习中通常配合哪些工程手段落地?
- A.多项式近似激活函数← 正确答案
- B.向量打包SIMD编码← 正确答案
- C.密文旋转实现卷积← 正确答案
- D.明文比较直接推理
答案:ABC。CKKS只能做加法和乘法,Sigmoid/ReLU等非线性函数必须用多项式近似(A);SIMD打包把多个数据塞进一个密文提升吞吐(B);卷积通过密文旋转把邻域元素对齐后乘加(C)。D做不到——密文上无法直接做明文比较,比较操作需要多项式近似表达。