AI 链上:链上 AI 推理验证协议——从预言机到 ZK-ML 的可验证计算实践
一、黑箱上链:AI 推理结果的可信度困境
链上 AI 应用面临一个根本性矛盾:区块链的确定性执行环境无法原生运行大模型推理,AI 推理必须发生在链下;但链下推理的结果如何让链上合约可信地验证?当前的普遍做法是通过预言机(Oracle)将 AI 推理结果提交到链上,合约直接信任预言机的报告。这本质上是一种"信任转移"——从信任 AI 服务商转移到信任预言机节点。
一个具体的生产场景:去中心化保险协议需要根据卫星图像的 AI 分析结果来判定是否触发理赔。如果预言机提交了虚假的"未受灾"结果,投保人将无法获得应有赔付。又或者,AI 驱动的链上衍生品交易需要模型预测价格走势,如果推理结果被篡改,将直接导致交易策略失效与资金损失。
可验证计算(Verifiable Computation)为这一矛盾提供了技术路径:链下执行 AI 推理,同时生成密码学证明,链上合约验证证明即可确认推理过程的正确性,无需信任任何中间方。本文将深入链上 AI 验证协议的架构设计,剖析从预言机到 ZK-ML 的技术演进,给出生产级实现,并客观分析当前方案的可行边界。
二、信任的梯度:从预言机到零知识证明的验证机制演进
链上 AI 验证方案按信任假设从弱到强可分为四个层次:
graph LR A[预言机信任 Oracle Trust] --> B[多签验证 Multi-sig] B --> C[TEE 远程证明 Remote Attestation] C --> D[ZK-ML 零知识证明] A -->|信任假设: 单一节点| A1[Chainlink Functions / Pyth] B -->|信任假设: N/M 诚实| B1[多预言机共识] C -->|信任假设: 硬件厂商| C1[SGX/TDX Enclave] D -->|信任假设: 数学| D1[ezkl / RISC Zero] style A fill:#ff6b6b,color:#fff style B fill:#ffa502,color:#fff style C fill:#7bed9f,color:#fff style D fill:#70a1ff,color:#fff层次一:预言机提交
最简单的方案——AI 推理节点将结果通过预言机提交到链上,合约直接读取。信任假设完全依赖预言机节点的诚实性。Chainlink Functions 是这一模式的代表,它允许链下计算结果通过去中心化预言机网络提交。
层次二:多预言机共识
多个独立的预言机节点分别执行 AI 推理,对结果进行共识。只有当 N/M 个节点报告一致时,合约才接受结果。这降低了单点故障风险,但增加了推理成本(同一任务执行 N 次),且无法防止所有节点使用同一模型导致的系统性偏差。
层次三:TEE 远程证明
推理节点在可信执行环境(SGX/TDX)中执行模型,生成远程证明(RA),链上验证 RA 签名即可确认推理在 Enclave 内执行。信任假设从"节点诚实"退化为"硬件安全"。
层次四:ZK-ML 零知识证明
将神经网络前向计算编码为算术电路,生成零知识证明 π。链上验证者只需检查 π 即可确认推理正确性,无需信任任何第三方。这是理论上最强的验证方案,但当前性能瓶颈严重。
sequenceDiagram participant User as 用户/合约 participant Prover as ZK 证明生成器 participant Model as AI 模型 participant Verifier as 链上验证合约 User->>Prover: 提交推理请求 (input_x) Prover->>Model: 执行前向推理 f(x) = y Model-->>Prover: 推理结果 y Prover->>Prover: 将 f 编码为算术电路 Prover->>Prover: 生成 ZK 证明 π Note over Prover: π 证明: 我知道 x 使得 f(x) = y<br/>且不泄露 x 的内容 Prover->>Verifier: 提交 (y, π, verification_key) Verifier->>Verifier: 验证 π 是否有效 Verifier-->>User: 验证通过 → 接受 y 为正确推理结果三、生产级链上 AI 验证协议:从多预言机共识到 ZK 证明验证
以下实现一个链上 AI 验证协议,包含多预言机共识机制与 ZK 证明验证合约。
import asyncio import hashlib import time from dataclasses import dataclass, field from enum import Enum from typing import Optional import json class VerificationMethod(Enum): ORACLE = "ORACLE" # 单预言机 MULTI_ORACLE = "MULTI_ORACLE" # 多预言机共识 TEE = "TEE" # TEE 远程证明 ZK_ML = "ZK_ML" # ZK-ML 零知识证明 class VerificationStatus(Enum): PENDING = "PENDING" VERIFIED = "VERIFIED" REJECTED = "REJECTED" DISPUTED = "DISPUTED" # 争议中 @dataclass class AIInferenceResult: """AI 推理结果""" request_id: str model_id: str input_hash: str # 输入数据的哈希(用于验证输入一致性) output: str # 推理输出 confidence: float # 模型置信度 inference_time_ms: int # 推理耗时 node_id: str # 执行推理的节点 ID timestamp: float = field(default_factory=time.time) @dataclass class VerificationProof: """验证证明""" method: VerificationMethod proof_data: bytes # 证明数据(格式因方法而异) public_inputs: dict # 公开输入(不含敏感数据) verification_key: str # 验证密钥标识 @dataclass class OracleNode: """预言机节点""" node_id: str endpoint: str stake: int reputation: float = 1.0 is_active: bool = True class OnChainAIVerificationProtocol: """ 链上 AI 验证协议 支持四种验证方法,按安全需求选择 """ def __init__( self, oracle_nodes: list[OracleNode], consensus_threshold: float = 0.6, # 60% 节点一致即通过 max_dispute_period: int = 3600, # 争议期 1 小时 ): self.oracle_nodes = { n.node_id: n for n in oracle_nodes } self.consensus_threshold = consensus_threshold self.max_dispute_period = max_dispute_period self.verification_results: dict[str, dict] = {} async def request_verified_inference( self, model_id: str, input_data: str, method: VerificationMethod = VerificationMethod.MULTI_ORACLE, ) -> dict: """ 请求经过验证的 AI 推理 根据验证方法执行不同的验证流程 """ request_id = hashlib.sha256( f"{model_id}:{input_data}:{time.time()}".encode() ).hexdigest()[:16] input_hash = hashlib.sha256(input_data.encode()).hexdigest() if method == VerificationMethod.MULTI_ORACLE: return await self._multi_oracle_verify( request_id, model_id, input_data, input_hash ) elif method == VerificationMethod.ZK_ML: return await self._zk_ml_verify( request_id, model_id, input_data, input_hash ) elif method == VerificationMethod.TEE: return await self._tee_verify( request_id, model_id, input_data, input_hash ) else: return await self._single_oracle_verify( request_id, model_id, input_data, input_hash ) async def _multi_oracle_verify( self, request_id: str, model_id: str, input_data: str, input_hash: str, ) -> dict: """ 多预言机共识验证 多个节点独立执行推理,对结果进行共识判定 """ # 选择活跃的预言机节点 active_nodes = [ n for n in self.oracle_nodes.values() if n.is_active ] if len(active_nodes) < 3: return { "request_id": request_id, "status": VerificationStatus.REJECTED.value, "error": "活跃预言机节点不足", } # 并行请求多个节点执行推理 tasks = [ self._call_oracle_node(node, model_id, input_data) for node in active_nodes[:7] # 最多 7 个节点 ] results = await asyncio.gather(*tasks, return_exceptions=True) # 收集成功的推理结果 valid_results: list[AIInferenceResult] = [] for result in results: if isinstance(result, AIInferenceResult): # 验证输入哈希一致性 if result.input_hash == input_hash: valid_results.append(result) if len(valid_results) < 2: return { "request_id": request_id, "status": VerificationStatus.REJECTED.value, "error": "有效推理结果不足", } # 共识判定:统计输出一致性 output_counts: dict[str, int] = {} for r in valid_results: # 对输出进行模糊匹配(允许浮点数微小差异) output_key = self._fuzzy_output_key(r.output) output_counts[output_key] = output_counts.get(output_key, 0) + 1 # 找到共识结果 total_votes = len(valid_results) consensus_output = max(output_counts, key=output_counts.get) consensus_count = output_counts[consensus_output] consensus_ratio = consensus_count / total_votes if consensus_ratio >= self.consensus_threshold: # 共识达成 consensus_result = next( r for r in valid_results if self._fuzzy_output_key(r.output) == consensus_output ) verification = { "request_id": request_id, "status": VerificationStatus.VERIFIED.value, "output": consensus_result.output, "confidence": consensus_result.confidence, "consensus_ratio": round(consensus_ratio, 3), "participating_nodes": len(valid_results), "verification_method": VerificationMethod.MULTI_ORACLE.value, "dispute_deadline": time.time() + self.max_dispute_period, } else: # 未达成共识,进入争议期 verification = { "request_id": request_id, "status": VerificationStatus.DISPUTED.value, "consensus_ratio": round(consensus_ratio, 3), "participating_nodes": len(valid_results), "error": "预言机节点未达成共识", "dispute_deadline": time.time() + self.max_dispute_period, } self.verification_results[request_id] = verification return verification async def _zk_ml_verify( self, request_id: str, model_id: str, input_data: str, input_hash: str, ) -> dict: """ ZK-ML 验证 链下生成 ZK 证明,链上验证 """ # 模拟 ZK 证明生成过程 # 实际生产中调用 ezkl / RISC Zero 等框架 proof = await self._generate_zk_proof(model_id, input_data) if not proof: return { "request_id": request_id, "status": VerificationStatus.REJECTED.value, "error": "ZK 证明生成失败", } # 链上验证 ZK 证明 is_valid = await self._verify_zk_proof_onchain(proof) verification = { "request_id": request_id, "status": ( VerificationStatus.VERIFIED.value if is_valid else VerificationStatus.REJECTED.value ), "output": proof.public_inputs.get("output", ""), "verification_method": VerificationMethod.ZK_ML.value, "proof_size_bytes": len(proof.proof_data), "verification_gas_estimate": 350000, # ZK 验证约 35 万 Gas } self.verification_results[request_id] = verification return verification async def _tee_verify( self, request_id: str, model_id: str, input_data: str, input_hash: str, ) -> dict: """ TEE 远程证明验证 验证推理在可信执行环境中执行 """ # 模拟 TEE 证明生成 tee_result = await self._call_tee_node(model_id, input_data) if not tee_result: return { "request_id": request_id, "status": VerificationStatus.REJECTED.value, "error": "TEE 推理失败", } # 验证远程证明签名 ra_valid = self._verify_remote_attestation(tee_result) verification = { "request_id": request_id, "status": ( VerificationStatus.VERIFIED.value if ra_valid else VerificationStatus.REJECTED.value ), "output": tee_result.get("output", ""), "verification_method": VerificationMethod.TEE.value, "tee_type": tee_result.get("tee_type", "SGX"), "verification_gas_estimate": 80000, # TEE RA 验证约 8 万 Gas } self.verification_results[request_id] = verification return verification async def _single_oracle_verify( self, request_id: str, model_id: str, input_data: str, input_hash: str, ) -> dict: """单预言机验证(最低安全级别)""" node = next( (n for n in self.oracle_nodes.values() if n.is_active), None ) if not node: return { "request_id": request_id, "status": VerificationStatus.REJECTED.value, "error": "无可用预言机节点", } result = await self._call_oracle_node(node, model_id, input_data) if isinstance(result, AIInferenceResult): verification = { "request_id": request_id, "status": VerificationStatus.VERIFIED.value, "output": result.output, "verification_method": VerificationMethod.ORACLE.value, "trusted_node": node.node_id, } else: verification = { "request_id": request_id, "status": VerificationStatus.REJECTED.value, "error": "预言机推理失败", } self.verification_results[request_id] = verification return verification # ============ 辅助方法 ============ async def _call_oracle_node( self, node: OracleNode, model_id: str, input_data: str ) -> Optional[AIInferenceResult]: """调用预言机节点执行推理""" try: # 模拟 HTTP 调用 await asyncio.sleep(0.1) output_hash = hashlib.sha256( f"{model_id}:{input_data}:{node.node_id}".encode() ).hexdigest()[:8] return AIInferenceResult( request_id="", model_id=model_id, input_hash=hashlib.sha256(input_data.encode()).hexdigest(), output=f"result_{output_hash}", confidence=0.92, inference_time_ms=150, node_id=node.node_id, ) except Exception: return None def _fuzzy_output_key(self, output: str) -> str: """对输出进行模糊哈希,允许微小差异""" return output[:6] # 简化:取前 6 字符作为匹配键 async def _generate_zk_proof( self, model_id: str, input_data: str ) -> Optional[VerificationProof]: """模拟 ZK 证明生成""" # 实际生产中调用 ezkl 命令行工具 # ezkl prove --model model.onnx --input input.json --proof-path proof.json await asyncio.sleep(0.5) # 模拟证明生成耗时 return VerificationProof( method=VerificationMethod.ZK_ML, proof_data=b"mock_zk_proof_data_" + hashlib.sha256( f"{model_id}:{input_data}".encode() ).digest(), public_inputs={ "input_hash": hashlib.sha256(input_data.encode()).hexdigest(), "output": f"zk_verified_result_{model_id}", "model_hash": hashlib.sha256(model_id.encode()).hexdigest(), }, verification_key="vk_001", ) async def _verify_zk_proof_onchain( self, proof: VerificationProof ) -> bool: """ 模拟链上 ZK 证明验证 实际生产中调用链上 Verifier 合约 """ # 验证证明数据非空且格式正确 return len(proof.proof_data) > 32 and proof.verification_key != "" async def _call_tee_node( self, model_id: str, input_data: str ) -> Optional[dict]: """模拟 TEE 节点推理""" await asyncio.sleep(0.2) return { "output": f"tee_result_{model_id}", "ra_quote": b"mock_ra_quote", "tee_type": "TDX", "enclave_hash": hashlib.sha256(model_id.encode()).hexdigest(), } def _verify_remote_attestation(self, tee_result: dict) -> bool: """验证 TEE 远程证明签名""" ra_quote = tee_result.get("ra_quote") return ra_quote is not None and len(ra_quote) > 0 # ============ 链上验证合约(Solidity 伪代码转 Python 模拟) ============ class OnChainVerifier: """ 链上验证合约模拟 实际部署为 Solidity 合约 """ def verify_zk_proof( self, proof: bytes, public_inputs: list[int], verification_key: str, ) -> bool: """ 验证 ZK 证明 对应 Solidity 函数: function verifyProof( uint256[8] calldata proof, uint256[] calldata publicInputs ) external view returns (bool) """ # 实际实现调用 Groth16/Plonk 验证器 # 这里简化为格式检查 return len(proof) >= 32 and len(public_inputs) >= 1 def verify_tee_attestation( self, ra_quote: bytes, enclave_hash: str, expected_enclave_hash: str, ) -> bool: """ 验证 TEE 远程证明 检查 Enclave 哈希是否匹配预期值 """ if enclave_hash != expected_enclave_hash: return False # 验证 RA Quote 签名(实际需调用 Intel DCAP 证书链验证) return len(ra_quote) > 0 # ============ 使用示例 ============ async def main(): # 初始化预言机节点 nodes = [ OracleNode(f"oracle_{i}", f"https://oracle-{i}.example.com", 100 * 10**18) for i in range(5) ] protocol = OnChainAIVerificationProtocol( oracle_nodes=nodes, consensus_threshold=0.6, ) # 请求多预言机共识验证 result = await protocol.request_verified_inference( model_id="image-classifier-v2", input_data="satellite_image_flood_area_001", method=VerificationMethod.MULTI_ORACLE, ) print(f"多预言机验证结果: {json.dumps(result, indent=2, ensure_ascii=False)}") # 请求 ZK-ML 验证 zk_result = await protocol.request_verified_inference( model_id="price-predictor-v1", input_data="ETH_price_history_30d", method=VerificationMethod.ZK_ML, ) print(f"ZK-ML 验证结果: {json.dumps(zk_result, indent=2, ensure_ascii=False)}") if __name__ == "__main__": asyncio.run(main())四、可验证计算的现实壁垒:性能、成本与信任的三角约束
链上 AI 验证协议在理论上实现了"无需信任的 AI 推理",但在工程落地中面临三重硬约束:
ZK 证明的生成性能瓶颈
ZK-ML 的核心瓶颈在于证明生成速度。当前 ezkl 框架对一个 MNIST 级别模型(784 输入、2 层全连接)生成 Groth16 证明需要约 10 秒,对 ResNet 级别模型需要数分钟,对 Transformer 级别模型则需要数小时。这意味着 ZK-ML 仅适用于低频、高价值的推理场景(如链上随机数验证、模型指纹存证),无法支撑实时推理需求。
链上验证的 Gas 成本
ZK 证明的链上验证需要执行椭圆曲线配对运算,Gas 消耗约 20-50 万。以 Ethereum 主网 20 Gwei 的 Gas 价格计算,单次验证成本约 0.04-0.1 ETH。即使部署在 L2 上,成本仍不可忽视。TEE 远程证明的验证 Gas 较低(约 5-10 万),但需要额外的证书链验证逻辑。
多预言机共识的扩展性限制
多预言机共识要求 N 个节点独立执行同一推理任务,推理成本线性增长。对于需要 GPU 的大模型推理,5 个节点意味着 5 倍的 GPU 成本。在经济模型上,这些成本最终由请求方承担,可能使链上 AI 推理的价格远高于中心化 API。
信任假设的不可消除性
即使采用 ZK-ML,信任假设并未完全消除——它从"信任预言机节点"转移为"信任电路实现的正确性"。如果将模型编码为算术电路时存在 Bug(如量化精度丢失、激活函数近似错误),ZK 证明只能证明"电路被正确执行",而非"模型被正确执行"。电路审计本身是一个尚未被系统解决的问题。
禁用场景
- 高频实时推理:如链上交易信号生成,ZK 证明的生成延迟不可接受。
- 低成本批量推理:如 Embedding 批量生成,验证成本远超推理本身价值。
- 模型频繁更新:每次模型更新都需要重新生成验证密钥与电路,运维成本极高。
五、总结
链上 AI 验证协议试图用密码学证明解决链下推理的可信度问题,从预言机信任到多签共识、TEE 远程证明、ZK-ML 零知识证明,信任假设逐步弱化,但工程复杂度与性能成本同步上升。多预言机共识在成本与安全性之间取得相对平衡,是目前最可行的生产方案;ZK-ML 提供了理论上最强的验证保证,但受限于证明生成速度与链上验证成本,短期内仅适用于特定场景。链上 AI 验证不是非此即彼的选择,而是根据资产规模、延迟要求与信任需求,在四种验证方法之间进行工程权衡。理解每种方法的信任假设与性能边界,才能在链上 AI 应用的架构设计中做出合理决策。