零知识证明与 AI 隐私计算:Web3 的可信推理,从黑盒到可验证

一、AI 推理的可信困境:如何证明模型确实使用了声称的算法
AI 推理服务通常是黑盒——用户提交输入,服务返回输出,但无法验证服务端是否真的使用了声称的模型、是否篡改了推理结果。在金融风控、医疗诊断等高风险场景中,这种不可验证性是致命的:模型提供者可能使用低成本的低精度模型冒充高精度模型,或在推理过程中注入偏见。
零知识证明(ZKP)为 AI 推理提供了可信验证的新范式:模型提供者生成推理过程的 ZK 证明,验证者可以在不接触模型权重和输入数据的情况下,确认推理过程的正确性。这在 Web3 场景中尤为重要——链上 AI 服务的可信度直接关系到用户资产安全。
二、ZK-ML 的技术架构与验证流程
flowchart TB
A[模型提供者] –> B[离线阶段: 电路编译]
B –> C[将模型转换为 ZK 电路]
C –> D[生成验证密钥 VK 和证明密钥 PK]
E[推理请求] –> F[在线阶段: 证明生成]
F –> G[在 ZK 电路中执行推理]
G –> H[生成推理证明 π]
H –> I[输出: 结果 + 证明]
I –> J[验证者]
J –> K[使用 VK 验证证明 π]
K –> L{验证通过?}
L –>|是| M[接受推理结果]
L –>|否| N[拒绝: 推理过程不可信]
subgraph 链上验证
O[智能合约] –> P[调用验证算法]
P –> Q[Gas 消耗取决于电路复杂度]
end
K –> O
ZK-ML 的核心挑战在于"电路化"——将神经网络的浮点运算转换为 ZK 电路中的有限域运算,同时保持数值精度。当前主流方案有 zkCNN(卷积网络)、EZKL(通用模型)等。
三、核心实现:ZK 推理验证合约
// ZKMLVerifier.sol — ZK-ML 推理验证合约
// 设计意图:在链上验证 AI 推理的零知识证明,
// 确保推理过程使用了声明的模型且未被篡改
pragma solidity ^0.8.19;
interface IVerifier {
function verify(
uint256[2] calldata _pA,
uint256[2][2] calldata _pB,
uint256[2] calldata _pC,
uint256[] calldata _pubSignals
) external view returns (bool);
}
contract ZKMLVerifier {
IVerifier public verifier;
bytes32 public modelCommitment; // 模型参数的承诺(Merkle Root)
struct InferenceProof {
address prover;
bytes32 inputHash; // 输入数据的哈希
bytes32 outputHash; // 输出结果的哈希
bytes32 modelCommitment; // 使用的模型承诺
uint256 timestamp;
bool verified;
}
mapping(bytes32 => InferenceProof) public proofs;
bytes32[] public verifiedInferenceIds;
event InferenceVerified(
bytes32 indexed proofId,
address prover,
bytes32 inputHash,
bytes32 outputHash
);
constructor(address _verifier, bytes32 _modelCommitment) {
verifier = IVerifier(_verifier);
modelCommitment = _modelCommitment;
}
// 提交并验证推理证明
// 设计意图:验证者提交 ZK 证明,合约验证证明的正确性,
// 确保推理使用了声明的模型且输入输出未被篡改
function submitAndVerify(
uint256[2] calldata _pA,
uint256[2][2] calldata _pB,
uint256[2] calldata _pC,
uint256[] calldata _pubSignals
) external returns (bytes32) {
// 公共信号包含:输入哈希、输出哈希、模型承诺
require(_pubSignals.length >= 3, "公共信号不足");
bytes32 inputHash = bytes32(_pubSignals[0]);
bytes32 outputHash = bytes32(_pubSignals[1]);
bytes32 usedModelCommitment = bytes32(_pubSignals[2]);
// 验证使用的模型与声明的模型一致
require(
usedModelCommitment == modelCommitment,
"模型承诺不匹配"
);
// 调用 ZK 验证器
bool isValid = verifier.verify(_pA, _pB, _pC, _pubSignals);
require(isValid, "ZK 证明验证失败");
// 生成唯一证明 ID
bytes32 proofId = keccak256(abi.encodePacked(
msg.sender, inputHash, outputHash, block.timestamp
));
proofs[proofId] = InferenceProof({
prover: msg.sender,
inputHash: inputHash,
outputHash: outputHash,
modelCommitment: usedModelCommitment,
timestamp: block.timestamp,
verified: true
});
verifiedInferenceIds.push(proofId);
emit InferenceVerified(proofId, msg.sender, inputHash, outputHash);
return proofId;
}
// 查询推理证明
function getProof(bytes32 _proofId)
external view returns (InferenceProof memory)
{
require(proofs[_proofId].verified, "证明不存在或未验证");
return proofs[_proofId];
}
// 更新模型承诺(仅治理合约可调用)
function updateModelCommitment(bytes32 _newCommitment) external {
// 实际生产中应加入治理投票机制
modelCommitment = _newCommitment;
}
}
# zkml_prover.py — ZK-ML 证明生成器(链下)
# 设计意图:将 AI 推理过程转换为 ZK 电路,生成可验证的推理证明
import hashlib
import json
class ZKMLProver:
"""ZK-ML 证明生成器"""
def __init__(self, model_path: str, circuit_path: str):
self.model_path = model_path
self.circuit_path = circuit_path
self.model_commitment = self._compute_model_commitment()
def _compute_model_commitment(self) -> bytes:
"""计算模型参数的承诺(Merkle Root 的简化版)"""
# 将模型参数序列化后取哈希,作为模型身份的承诺
with open(self.model_path, 'rb') as f:
model_data = f.read()
return hashlib.sha256(model_data).digest()
def generate_proof(self, input_data: list, output_data: list) -> dict:
"""
生成推理证明
设计意图:在 ZK 电路中重放推理过程,生成证明
"""
# 1. 计算输入输出的哈希
input_hash = hashlib.sha256(
json.dumps(input_data).encode()
).digest()
output_hash = hashlib.sha256(
json.dumps(output_data).encode()
).digest()
# 2. 在 ZK 电路中执行推理(伪代码,实际使用 EZKL 或 similar)
# 电路约束:output = model(input) AND model_commitment == declared
proof = self._execute_circuit(input_data, output_data)
# 3. 构造公共信号
pub_signals = [
int.from_bytes(input_hash[:32], 'big'),
int.from_bytes(output_hash[:32], 'big'),
int.from_bytes(self.model_commitment[:32], 'big'),
]
return {
'proof': proof,
'pub_signals': pub_signals,
'input_hash': input_hash.hex(),
'output_hash': output_hash.hex(),
}
def _execute_circuit(self, input_data, output_data) -> dict:
"""在 ZK 电路中执行推理(简化实现)"""
# 实际实现使用 EZKL/Halo2 等框架
# 此处返回模拟的证明数据
return {
'pA': [[0, 0], [0, 0]],
'pB': [[[0, 0], [0, 0]], [[0, 0], [0, 0]]],
'pC': [[0, 0], [0, 0]],
}
四、Trade-offs:ZK-ML 的工程挑战与适用边界
证明生成的计算开销。 生成一个 ZK 证明的计算量是原始推理的 1000—10000 倍。一个 ResNet 推理耗时 10ms,但生成 ZK 证明可能需要 10—100 秒。这意味着 ZK-ML 目前仅适用于低频高价值场景(如链上仲裁、合规审计),不适用于实时推理。
电路化精度损失。 ZK 电路使用有限域运算(通常为 254 位素数域),无法直接表示浮点数。将浮点模型量化为定点数会引入精度损失,可能影响推理结果的准确性。当前最佳实践是使用 8—16 位定点量化,在精度和电路效率间取平衡。
验证的 Gas 成本。 链上验证 ZK 证明需要执行椭圆曲线配对运算,Gas 消耗约 20—50 万。对于高频验证场景,成本不可忽视。优化手段:批量验证(多个证明合并验证)、使用 Groth16 等简洁证明系统(验证 Gas 更低)、将验证逻辑移到 L2。
模型隐私 vs 可验证性的矛盾。 ZK 证明可以隐藏模型权重(仅公开模型承诺),但验证者无法检查模型权重是否合理。如果模型提供者使用了一个有偏见的模型,ZK 证明只能证明"推理过程使用了该模型",无法证明"该模型是公平的"。
五、总结
零知识证明为 AI 推理提供了从"信任服务提供者"到"验证计算过程"的范式转变。落地路径:第一步,选择支持 ZK 电路化的模型架构(如简化的 MLP 或小规模 CNN);第二步,使用 EZKL 等工具将模型转换为 ZK 电路,验证精度损失在可接受范围内;第三步,部署链上验证合约,实现推理结果的可信验证;第四步,优化证明生成效率,探索递归证明和批量验证降低成本。核心原则:ZK-ML 的价值在于可信验证而非隐私保护——在多数场景中,验证推理正确性比隐藏模型权重更重要。
