基础概念
一、零知识证明(Zero‑Knowledge Proof, ZKP)
核心思想 :证明者(Prover)向验证者(Verifier)证明"我知道某个秘密",但整个过程不泄露秘密本身的任何信息。验证者只能得到"真/假"的结论,无法反推出秘密内容。
通俗类比:你想证明自己知道一个保险箱的密码,但不想把密码说出来。你可以当着对方的面打开保险箱,对方看到门开了就确信你知道密码,但他依然不知道密码是多少。
关键特性:
- 完备性:若陈述为真,诚实的证明者必能通过验证。
- 可靠性:若陈述为假,恶意证明者几乎不可能欺骗成功。
- 零知识性:验证者除了"陈述为真"外,得不到任何额外信息。
典型应用:
- 隐私交易:Zcash、Tornado Cash 用 zk‑SNARK 隐藏交易金额与收发地址,同时让网络验证交易合法性。
- Layer2 扩容:zk‑Rollup 把上千笔交易"打包"成一个零知识证明,主链只验证证明即可,极大提升吞吐量。
- 身份认证:证明"我已成年"或"我是某国公民",无需透露出生日期或身份证号。
- 链上游戏:玩家证明自己拥有某道具或完成某任务,但不暴露具体策略。
主流方案:zk‑SNARK(简洁、需可信初始化)、zk‑STARK(无需可信设置、抗量子)、Bulletproofs(无初始化、适合范围证明)。
二、同态加密(Homomorphic Encryption, HE)
核心思想 :对密文 进行计算,得到的结果解密后与在明文上直接计算的结果完全一致。简单说------"先加密再计算"等价于"先计算再加密"。
通俗类比:把两份钱分别锁进两个魔法箱子,你可以直接在箱子里把两笔钱相加,打开箱子后得到的是总额,而整个过程你根本没看见每张钞票的面值。
关键类型(按支持运算的丰富度):
- 部分同态(PHE):只支持加法或乘法中的一种。如 RSA 加密支持密文乘法。
- Somewhat 同态(SHE):可同时支持有限次数的加法和乘法。
- 全同态(FHE):支持任意次数的加法和乘法,理论上可完成任意复杂计算。
典型应用:
- 隐私计算外包:把加密数据交给云服务器分析,服务器直接对密文运算,返回的加密结果只有你解密后才看得懂。适用于医疗(加密病历分析)、金融(加密风控建模)。
- 链上隐私合约:智能合约处理加密状态变量,合约逻辑在密文上执行,只有授权方能看到最终结果。
- 联合学习:多个机构在不暴露各自原始数据的前提下,协作训练 AI 模型。
主流方案:BFV/BGV(整数全同态)、CKKS(浮点数近似全同态)、TFHE(快速布尔运算)。
三、两者的核心区别
| 维度 | 零知识证明 | 同态加密 |
|---|---|---|
| 保护对象 | "我知道 X"这个事实,但不告诉你 X 是什么 | 数据本身(X)全程加密,但对 X 的运算结果可计算 |
| 计算主体 | 证明者在本地完成计算,只把证明发给验证者 | 计算方(如云服务器)在密文上直接运算 |
| 性能开销 | 证明生成耗时,验证极快(毫秒级) | 密文计算比明文慢 10³~10⁶ 倍,仍在优化 |
| 典型场景 | 验证、审计、扩容(需"自证清白") | 外包计算、多方协作(需"密文计算") |
| 成熟程度 | zk‑SNARK/STARK 已在生产环境大规模使用 | 全同态加密(FHE)尚处于早期实用阶段 |
一句话总结:
- 零知识证明是"我不给你看数据,但我能让你相信我算对了"。
- 同态加密 是"我把数据加密给你,你直接在密文上算,结果解密后跟我明文算的一样"。
在了解了零知识证明(ZKP)的基本概念后,深入探讨**非交互式零知识证明(NIZKP)**是非常自然的下一步。
非交互零知识证明算法
🧠 一、核心原理:如何在没有"对方"时证明?
非交互式零知识证明最大的特点就是:证明者只需要生成一段数据(Proof),任何人都可以独立验证它,而不需要在过程中进行任何交流。
它是如何实现的呢?关键在于用密码学哈希函数 和可信设置"替代"了验证者的角色。
- 菲亚特-沙米尔变换(Fiat-Shamir Heuristic)
这是将交互式协议转化为非交互式的核心"魔法"。
- 交互式痛点:验证者需要随机出题(Challenge)。
- 非交互式解法 :证明者自己生成一个随机数 r,计算出承诺 R,然后把 R 和要证明的公钥(或消息)一起输入到一个哈希函数 H 中。
Challenge = H(R, Public_Info) - 原理:因为哈希函数具有"抗碰撞性"和"雪崩效应",这个 Challenge 看起来就像是一个公正的第三方随机生成的。证明者无法预测哈希结果,因此无法作弊。
- 可信设置(Trusted Setup)与 CRS
很多非交互式证明(特别是 zk-SNARKs)依赖一个公共参考字符串(CRS)。
- 这是一组在系统初始化时生成的公共参数。
- 风险点:如果生成这些参数的"原始私钥"没有被彻底销毁,攻击者就可以伪造证明。
- 解决方案:通常采用"多方安全计算(MPC)",让很多人参与生成参数,只要其中任何一人是诚实的并销毁了自己的随机数,整个系统就是安全的。
🧮 二、主流算法对比
目前工程界最常用的两种非交互式零知识证明算法是 zk-SNARKs 和 zk-STARKs 。它们虽然目标一致,但数学原理截然不同。
特性 zk-SNARKs zk-STARKs
全称 零知识简洁非交互式知识论证 零知识可扩展透明知识论证
核心数学 椭圆曲线、双线性配对 哈希函数、低度检验 (FRI)
可信设置 需要 (需信任初始化过程) 不需要(完全透明,更安全)
抗量子性 弱(量子计算机可破解椭圆曲线) 强(基于哈希,抗量子)
证明大小 极小(约 200 字节,验证快) 较大(约 10KB+,随计算量增长)
典型应用 Zcash, 早期以太坊扩容 StarkNet, 游戏/计算密集型场景
🔢 三、原理示例:Schnorr 签名(非交互式)
为了让你更直观地理解,我们来看一个密码学中非常基础且重要的非交互式零知识证明应用:Schnorr 签名。
场景 :
Alice 想要证明她知道私钥 sk(一个大整数),而对应的公钥是 PK = sk times G(G 是椭圆曲线基点),但她不想泄露 sk。
步骤 1:承诺 (Commitment)
Alice 随机生成一个临时私钥 r,并计算出对应的临时公钥 R:
R = r times G
她把这个 R 发送给 Bob(或者广播出去)。
步骤 2:生成挑战 (Challenge)
在交互式中,Bob 会扔硬币给一个随机数 c。但在非交互式中,Alice 不能自己给自己出题,否则会作弊。
于是,她使用哈希函数,把"公钥 PK"和"临时公钥 R"混合起来生成挑战:
c = Hash(PK, R)
这个 c 是由公开信息决定的,Alice 无法篡改。
步骤 3:构造响应 (Response)
Alice 利用私钥信息计算最终的响应 z:
z = r + c times sk
这里的 z 就是证明的一部分。
步骤 4:验证 (Verification)
Bob(或者任何人)拿到 (R, z) 后,不需要知道 sk,只需要验证以下等式是否成立:
z times G stackrel{?}{=} R + c times PK
- 左边:z times G = (r + c times sk) times G = r times G + c times sk times G
- 右边:R + c times PK = r times G + c times (sk times G)
只要两边相等,就证明了 Alice 确实知道 sk,因为只有知道 sk 才能算出正确的 z。但整个过程中,sk 从未出现过。
💻 四、工程化示例:zk-SNARKs 电路逻辑
在现代区块链应用(如 Zcash 或 zk-Rollup)中,我们通常使用高级语言(如 Circom)来编写"证明逻辑"。
假设我们要证明:"我知道一个秘密输入 x,使得 x^2 + 5 = y,其中 y 是公开的。" 而不泄露 x 是多少。
代码逻辑(Circom 语言示意):
template ProofOfSquare() {
// 1. 定义信号(变量)
signal input secret; // 私有输入,只有证明者知道
signal output result; // 公开输出,大家都能验证
// 2. 定义约束逻辑(电路)
// 我们要证明:result = secret^2 + 5
result <== secret * secret + 5;
// 这里的 <== 符号代表"定义了一个约束关系"
// 证明者必须找到一个 secret 满足这个等式
}
运行流程:
- 编译电路:生成 CRS(公共参考字符串)。
- 生成证明:Alice 输入 secret=3(此时 result=14),运行算法生成 Proof。
- 验证证明 :Bob 拿到 Proof 和公开值 result=14,调用 verify(Proof, 14)。
- 结果返回 True,但他完全不知道 Alice 的 secret 是 3 还是 -3。
📌 总结
非交互式零知识证明通过哈希函数 (如 Fiat-Shamir 变换)将多轮对话压缩为单次证明 ,并利用复杂的数学电路(如多项式承诺)来隐藏秘密。
- 如果你追求极小的证明体积 和极快的验证速度 ,且能接受可信设置,zk-SNARKs 是首选。
- 如果你追求绝对的安全性 (无需信任)、抗量子 ,且不介意证明体积稍大,zk-STARKs 是未来趋势。
很高兴为你详细介绍 BFV(Brakerski/Fan-Vercauteren) 算法。
全同态加密算法fhe
BFV 则是目前工业界最主流的全同态加密(FHE)算法之一。它允许我们在密文上进行无限次的加法和乘法运算(理论上受限于噪声管理),非常适合需要进行精确整数计算的隐私保护场景。
我将从核心原理、数学直觉和代码示例三个维度为你拆解。
🧠 一、核心原理:基于"格"的数学游戏
BFV 算法的安全性基于 RLWE(Ring Learning with Errors,在环上带误差学习) 困难问题。简单来说,它利用了在高维格结构中,寻找最短向量是非常困难的,但验证却是容易的。
它的核心魔法在于**"噪声管理"**。为了保证安全性,加密时必须加入随机噪声。在同态计算过程中,噪声会随着计算(尤其是乘法)不断膨胀。如果噪声太大,解密就会失败。BFV 的巧妙之处在于它如何控制这个噪声。
-
核心流程三步走
-
编码 (Encoding) :
由于计算机处理的是多项式,我们需要把原始数据(比如整数 5)编码成一个多项式 m(x)。BFV 通常使用"整数模"(PlainModulus)来定义这个空间。
-
加密 (Encryption) :
利用公钥(包含随机多项式和噪声)将明文多项式 m(x) 转化为一对密文多项式 (c_0, c_1)。
- 公式直觉:c_0 approx -c_1 cdot s + m + noise
- 其中 s 是私钥,noise 是为了安全加入的随机小数。
-
解密 (Decryption) :
利用私钥 s 去掉掩码,还原出明文。
- 公式直觉:m = c_0 + c_1 cdot s mod q
- 通过除法或取整操作,去掉微小的噪声,得到原始数据。
-
同态运算如何生效?
- 加法 (+) :
两个密文直接对应系数相加。解密后,结果等于两个明文相加。- 噪声变化 :噪声是相加关系,增长较慢。
- 乘法 (times) :
两个密文进行张量积(Tensor Product)。解密后,结果等于两个明文相乘。- 噪声变化 :噪声是相乘关系,增长非常快!
- 重线性化 (Relinearization):乘法会导致密文维度膨胀(变成三维甚至更高)。BFV 引入了"重线性化"技术,利用预先生成的"计算密钥"(Relinearization Keys),将高维密文"压缩"回标准的二维形式,同时控制噪声。
📊 二、BFV 的关键特性
为了让你更精准地使用它,有几个关键点需要注意:
特性 说明
数据类型 整数 (Integer)。它不能直接处理浮点数或小数。
缩放机制 Scale-Invariant (尺度不变)。这是 BFV 与 BGV 的主要区别之一。BFV 不需要像 BGV 那样通过"模切换"来缩放,它通过除法来去除噪声。
SIMD 技术 支持"单指令多数据流"。利用 Chinese Remainder Theorem (CRT) 或 FFT,BFV 可以把一个大多项式看作是多个小整数的数组。例如,一个密文可以同时加密 1024 个整数,并行计算,极大提升了效率。
💻 三、实战示例:使用 Microsoft SEAL 库
Microsoft SEAL 是由微软开发的目前最流行的 FHE 开源库,它原生支持 BFV 方案。
下面是一个 Python 示例(使用 Pyfhel 库,它是 SEAL 的 Python 封装,逻辑更清晰),演示如何使用 BFV 进行密文计算。
场景:计算 (2 + 3) times 4,全程数据加密。
from Pyfhel import Pyfhel, PyPtxt, PyCtxt
- 初始化 BFV 上下文
BFV 用于整数运算,需要指定多项式次数和模数
params = {
'scheme': 'BFV', # 指定方案
'n': 2**14, # 多项式环维度 (决定能加密多少数据)
't': 65537, # 明文模数 (决定明文的取值范围,这里选了一个素数)
'sec': 128, # 安全级别 (128位)
}
创建加密器
HE = Pyfhel()
HE.contextGen(**params)
HE.keyGen() # 生成公私钥
print("BFV 方案已初始化,准备就绪!")
- 加密数据
int1 = 2
int2 = 3
int3 = 4
加密 (变成密文对象)
c1 = HE.encryptInt(int1)
c2 = HE.encryptInt(int2)
c3 = HE.encryptInt(int3)
print(f"明文 {int1} 已加密为密文对象")
- 同态计算 (云端/服务器端)
注意:此时没有任何私钥,只有公钥加密后的数据
执行 (2 + 3) * 4
第一步:密文加法
result_add = c1 + c2 # 此时 result_add 代表密文(5)
第二步:密文乘法 (需要重线性化,Pyfhel 内部自动处理了)
result_mul = result_add * c3 # 此时 result_mul 代表密文(20)
print("云端正在执行密文计算...")
- 解密结果
将计算结果的密文发回给数据拥有者解密
decrypted_result = HE.decryptInt(result_mul) # 解密
print(f"---------------------------------")
print(f"原始计算: ({int1} + {int2}) * {int3}")
print(f"密文计算结果解密后: {decrypted_result}")
print(f"计算正确!")
📝 代码解析
-
参数设置 (contextGen):
- scheme='BFV':明确指定使用 BFV 方案。
- t=65537:这是明文模数。这意味着所有计算都是在模 65537 下进行的。如果你计算的结果超过这个数,会发生溢出(回绕)。
-
同态运算 (+, *):
- 代码层面看起来和普通加减法一样,但底层是在进行复杂的多项式运算。
- 乘法操作 (*) 在 BFV 中非常昂贵,因为它会产生大量的噪声,并且需要执行"重线性化"来保持密文结构。
-
应用场景:
- 这段代码可以被拆分:你(数据拥有者)生成密钥并加密 2 和 3,发送给云端。
- 云端拿着公钥加密的 4(或者你提供加密后的 4),进行计算并返回密文结果。
- 只有你持有私钥,能解密出 20。
📌 总结
BFV 是目前处理精确整数计算的首选全同态加密方案。
- 它擅长什么? 需要精确结果的整数运算,比如统计计数、数据库查询、逻辑电路判断、区块链上的智能合约隐私保护。
- 它的瓶颈? 乘法运算带来的噪声膨胀和巨大的计算开销。
- 如何优化? 利用 SIMD 技术批量处理数据,或者在不需要高精度时使用 CKKS(浮点数近似计算)方案。