ZKML 鏈上推論驗證完整指南:從理論到以太坊智慧合約部署
本文深入分析零知識機器學習(ZKML)的技術原理、鏈上驗證機制與以太坊智慧合約部署實作。涵蓋 EZKL、Noir、Circom 等主流框架的詳細教學,提供完整的 Solidity 驗證合約範例,並探討 ZKML 在 DeFi 風險評估、預言機、遊戲等場景的實際應用。截至2026年第一季度,ZKML技術已從理論走向實際部署,本文為開發者提供從理論到部署的完整技術路徑。
ZKML 鏈上推論驗證完整指南:從理論到以太坊智慧合約部署
執行摘要
零知識機器學習(Zero-Knowledge Machine Learning,ZKML)是區塊鏈與人工智慧交叉領域最具突破性的技術之一。透過 ZKML,AI 模型的推論過程可以被壓縮為密碼學證明,允許任何人在不執行昂貴推論的情況下驗證模型輸出是否正確。截至 2026 年第一季度,ZKML 技術在以太坊生態中的應用已經從理論走向實際部署,Giza、eziroll、Modulus Labs 等項目正在推動這項技術的大規模採用。本文深入分析 ZKML 的技術原理、鏈上驗證機制、提供完整的智慧合約部署範例,並探討這項技術在 DeFi、預言機、遊戲等場景的實際應用。
一、ZKML 技術基礎
1.1 為何需要鏈上 AI 推論驗證
傳統區塊鏈與 AI 的結合面臨核心矛盾:區塊鏈追求確定性與可驗證性,而 AI 模型推論本質上是機率性的且計算成本高昂。在鏈上直接執行 AI 推論面臨以下挑戰:
計算成本問題:即使是輕量級的神經網路,在 EVM 環境中執行的 Gas 成本也可能高達數百萬 Gas,遠超一般交易預算。
隱私保護需求:許多 AI 模型包含商業敏感的權重參數,直接在鏈上公開執行會洩露模型機密。
結果可信度:區塊鏈需要能夠驗證 AI 輸出的正確性,但傳統方式無法在不重新執行昂貴計算的情況下驗證結果。
ZKML 透過將 AI 推論過程轉換為零知識證明,完美解決了這些問題。模型持有者在鏈下執行推論並生成證明,任何人可以透過驗證證明來確認推論結果的正確性,同時無需透露模型權重或執行完整推論。
1.2 ZKML 的工作原理
ZKML 的核心流程包含以下步驟:
ZKML 完整流程圖
─────────────────────────────────────────────────────────────
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 輸入數據 │────▶│ 模型推論 │────▶│ 輸出結果 │
│ (public) │ │ (鏈下執行) │ │ (public) │
└──────────────┘ └──────────────┘ └──────────────┘
│
▼
┌──────────────┐
│ ZK 證明生成 │
│ (SNARK/ │
│ STARK) │
└──────────────┘
│
▼
┌──────────────┐
│ 智慧合約 │
│ 驗證證明 │
└──────────────┘
推論階段:模型持有者接收公開的輸入數據,在本地執行神經網路前向傳播,產生輸出結果。
證明生成階段:使用專門的 ZK 電路框架(如 circom、noir、EZKL)將整個推論過程編譯為零知識證明電路,生成簡潔的密碼學證明。
驗證階段:智慧合約接收輸出結果和對應的 ZK 證明,透過驗證密鑰確認證明的有效性,整個過程只需執行輕量級的配對計算或雜湊運算。
1.3 ZKML 電路設計基礎
理解 ZKML 需要掌握幾個關鍵概念:
定點數算術:神經網路通常使用浮點數運算,但 ZK 電路只能處理整數運算。透過定點數表示法(fixed-point arithmetic),我們可以將浮點數參數轉換為整數進行電路運算。
# 定點數表示法範例
# 假設使用 Q4.28 格式(4 位元整數部分,28 位元小數部分)
FIXED_POINT_SHIFT = 2**28
def float_to_fixed(value: float) -> int:
"""將浮點數轉換為定點數"""
return int(value * FIXED_POINT_SHIFT)
def fixed_to_float(value: int) -> float:
"""將定點數轉換為浮點數"""
return value / FIXED_POINT_SHIFT
# 範例:ReLU 函數的定點數實現
def relu_fixed(x_fixed: int) -> int:
"""ReLU 函數的定點數實現"""
return x_fixed if x_fixed > 0 else 0
# 矩陣乘法範例
def matrix_multiply_fixed(A, B):
"""矩陣乘法的定點數實現"""
rows_A = len(A)
cols_A = len(A[0])
cols_B = len(B[0])
result = [[0] * cols_B for _ in range(rows_A)]
for i in range(rows_A):
for j in range(cols_B):
acc = 0
for k in range(cols_A):
# 乘法後需要右移以恢復小數位置
acc += (A[i][k] * B[k][j]) >> 28
result[i][j] = acc
return result
約束系統:ZK 電路中的約束(constraints)確保計算的正確性。每個運算都需要轉換為代數約束。
// Circom 電路範例:簡化的神經網路層
pragma circom 2.0.0;
include "circomlib/poseidon.circom";
include "circomlib/bitify.circom";
template NeuralNetworkLayer(n_inputs, n_neurons) {
// 公開輸入
signal input inputs[n_inputs];
// 私密權重(模型機密)
signal private input weights[n_inputs][n_neurons];
signal private input biases[n_neurons];
// 公開輸出
signal output outputs[n_neurons];
// 中間變數
signal layer_sum[n_neurons];
for (var i = 0; i < n_neurons; i++) {
// 計算加权和
layer_sum[i] <== inputs[0] * weights[0][i];
for (var j = 1; j < n_inputs; j++) {
layer_sum[i] <== layer_sum[i] + inputs[j] * weights[j][i];
}
// 加上偏置
layer_sum[i] <== layer_sum[i] + biases[i];
// ReLU 激活函數
// 使用選擇器約束實現條件判斷
component relu = ReLU();
relu.in <== layer_sum[i];
outputs[i] <== relu.out;
}
}
template ReLU() {
signal input in;
signal output out;
// 約束:out = max(0, in)
// 當 in >= 0 時,out = in;當 in < 0 時,out = 0
// 這裡需要複雜的範圍證明來判斷符號
// 實際實現中通常使用平滑近似或分段函數
}
template DenseLayer(n_inputs, n_neurons) {
signal input in[n_inputs];
signal private input weights[n_inputs][n_neurons];
signal private input bias[n_neurons];
signal output out[n_neurons];
for (var i = 0; i < n_neurons; i++) {
var sum = 0;
for (var j = 0; j < n_inputs; j++) {
sum += in[j] * weights[j][i];
}
out[i] <-- sum + bias[i];
}
}
二、主流 ZKML 框架對比
2.1 EZKL 框架詳解
EZKL 是目前最流行的 ZKML 框架之一,專門設計用於將 ONNX 格式的神經網路模型轉換為零知識電路。
# EZKL 使用範例:將 ONNX 模型轉換為 ZK 電路
from ezkl import compile_circuit, gen_srs, setup, prove, verify
import ezkl
import numpy as np
class ZKMLModel:
"""ZKML 模型處理類"""
def __init__(self, model_path: str, input_shape: tuple):
"""
初始化 ZKML 模型
Args:
model_path: ONNX 模型檔案路徑
input_shape: 輸入數據形狀
"""
self.model_path = model_path
self.input_shape = input_shape
self.vk = None # 驗證密鑰
self.pk = None # 證明密鑰
def compile_model(self, output_path: str):
"""編譯 ONNX 模型為 EZKL 電路"""
# 讀取 ONNX 模型
circuit = ezkl.from_onnx(self.model_path)
# 設定輸入形狀
input_shape = [1] + list(self.input_shape[1:])
# 生成編譯後的電路
compiled_onnx = ezkl.compile_circuit(
circuit,
input_shape=input_shape,
logrows=17, # 根據模型大小調整
output_path=output_path
)
return compiled_onnx
def setup_circuit(self, compiled_circuit):
"""設置 SRS 和密鑰對"""
# 初始化可信設置(SRS)
srs = gen_srs(
circuit=compiled_circuit,
logrows=17
)
# 生成驗證和證明密鑰
vk, pk = setup(
circuit=compiled_circuit,
srs=srs
)
self.vk = vk
self.pk = pk
return vk, pk
def generate_proof(self, input_data: np.ndarray, settings_path: str):
"""
生成 ZK 證明
Args:
input_data: 輸入數據 (numpy array)
settings_path: 設定檔路徑
"""
# 準備輸入數據
input_data = input_data.flatten()
# 執行模型推論(獲取輸出)
# 實際使用時,這應該與證明生成同時進行
from onnxruntime import InferenceSession
sess = InferenceSession(self.model_path)
output = sess.run(None, {'input': input_data.reshape(self.input_shape)})
# 生成證明
proof = prove(
circuit_witness=input_data,
compiled_circuit=compiled_circuit,
pk=self.pk,
settings_path=settings_path
)
return proof, output
def verify_proof(self, proof, output, settings_path: str):
"""驗證 ZK 證明"""
return verify(
proof=proof,
vk=self.vk,
settings_path=settings_path
)
# 完整使用流程範例
def main():
# 初始化模型
model = ZKMLModel(
model_path="models/linear_regression.onnx",
input_shape=(1, 4)
)
# 編譯模型
compiled = model.compile_model("compiled_onnx.json")
# 設置電路
vk, pk = model.setup_circuit(compiled)
# 準備輸入數據
input_data = np.array([[1.0, 2.0, 3.0, 4.0]], dtype=np.float32)
# 生成證明
proof, output = model.generate_proof(input_data, "settings.json")
# 驗證證明
is_valid = model.verify_proof(proof, output, "settings.json")
print(f"證明驗證結果: {'有效' if is_valid else '無效'}")
print(f"模型輸出: {output}")
if __name__ == "__main__":
main()
2.2 Noir 框架介紹
Noir 是 Aztec Network 開發的零知識證明語言,語法類似 Rust,對開發者友好。
// Noir 語言實現簡單的神經網路層
// 檔案: neural_network.nr
use dep::std;
// 定義神經網路結構
struct NeuralNetwork {
weights: [[Field; 2]; 2],
biases: [Field; 2],
}
// 矩陣乘法
fn matrix_multiply(
input: [Field; 2],
weights: [[Field; 2]; 2]
) -> [Field; 2] {
let mut result = [0; 2];
for i in 0..2 {
let mut sum = 0;
for j in 0..2 {
sum = sum + input[j] * weights[j][i];
}
result[i] = sum;
}
result
}
// ReLU 激活函數
fn relu(x: Field) -> Field {
if x > 0 { x } else { 0 }
}
// 前向傳播
fn forward_pass(
nn: NeuralNetwork,
input: [Field; 2]
) -> [Field; 2] {
// 矩陣乘法
let weighted_sum = matrix_multiply(input, nn.weights);
// 加偏置並應用 ReLU
let mut output = [0; 2];
for i in 0..2 {
output[i] = relu(weighted_sum[i] + nn.biases[i]);
}
output
}
// 主電路
fn main(
// 公開輸入
input: [Field; 2],
// 私密權重(不公開)
weights: [[Field; 2]; 2],
biases: [Field; 2],
// 預期輸出(用於約束)
expected_output: [Field; 2]
) {
let nn = NeuralNetwork { weights, biases };
// 執行前向傳播
let output = forward_pass(nn, input);
// 約束輸出必須匹配預期值
for i in 0..2 {
std::assert::assert_eq(output[i], expected_output[i]);
}
}
2.3 框架特性比較
| 特性 | EZKL | Noir | Circom | Gnark |
|---|---|---|---|---|
| 學習曲線 | 中等 | 低 | 高 | 中等 |
| ONNX 支援 | 原生 | 無 | 無 | 無 |
| 語法風格 | Python | Rust | JavaScript | Go |
| 證明系統 | PLONK | Honk | Groth16 | BN254 |
| 社群活躍度 | 高 | 高 | 中 | 高 |
| 文件完善度 | 中 | 高 | 中 | 高 |
| 適合場景 | ML 模型部署 | 通用電路 | 密碼學電路 | 通用電路 |
三、以太坊智慧合約部署實作
3.1 證明驗證智慧合約
在以太坊上部署 ZKML 驗證智慧合約需要考慮 Gas 成本和安全性。以下是一個完整的 Solidity 驗證合約範例:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
/**
* @title ZKMLVerifier
* @dev ZKML 證明驗證合約
*
* 本合約支援驗證多種 ZK 證明系統的輸出,
* 包括 Groth16、PLONK、STARK 等
*/
contract ZKMLVerifier is Initializable, AccessControlUpgradeable, UUPSUpgradeable {
// 角色定義
bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");
bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE");
// 驗證狀態
mapping(bytes32 => bool) public verifiedProofs;
mapping(address => bool) public authorizedModels;
// 事件定義
event ProofVerified(bytes32 indexed proofId, address indexed model, uint256 timestamp);
event ProofRejected(bytes32 indexed proofId, string reason);
event ModelAuthorized(address indexed model);
event ModelRevoked(address indexed model);
// 結構體:驗證請求
struct VerificationRequest {
bytes32 proofId;
address modelAddress;
bytes publicInputs;
bytes proof;
uint256 timestamp;
bool verified;
}
// 待處理的驗證請求
mapping(bytes32 => VerificationRequest) public pendingVerifications;
bytes32[] public pendingVerificationIds;
/// @custom:oz-upgrades-constructor
function initialize() public initializer {
__AccessControl_init();
__UUPSUpgradeable_init();
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(OPERATOR_ROLE, msg.sender);
_grantRole(UPGRADER_ROLE, msg.sender);
}
/**
* @dev 授權 AI 模型
* @param model 模型地址
*/
function authorizeModel(address model) external onlyRole(DEFAULT_ADMIN_ROLE) {
require(model != address(0), "Invalid model address");
authorizedModels[model] = true;
emit ModelAuthorized(model);
}
/**
* @dev 撤銷模型授權
* @param model 模型地址
*/
function revokeModel(address model) external onlyRole(DEFAULT_ADMIN_ROLE) {
authorizedModels[model] = false;
emit ModelRevoked(model);
}
/**
* @dev 驗證 Groth16 證明
* @param proof Groth16 證明數據
* @param publicInputs 公開輸入
* @param verificationKey 驗證密鑰
* @return 驗證是否成功
*/
function verifyGroth16(
bytes memory proof,
bytes memory publicInputs,
bytes memory verificationKey
) internal view returns (bool) {
// 簡化的 Groth16 驗證邏輯
// 實際實現需要使用配對運算
// 驗證 proof 格式
require(proof.length == 128, "Invalid proof length");
// 解析驗證密鑰
(uint256[2] memory alpha, uint256[2] memory beta, uint256[2] memory gamma,
uint256[2] memory delta, uint256[2][] memory gamma_abc) = _parseVerificationKey(verificationKey);
// 執行配對檢查
// 這是一個簡化的實現
return _pairingCheck(alpha, beta, gamma, delta, gamma_abc, proof, publicInputs);
}
/**
* @dev 驗證 PLONK 證明
* @param proof PLONK 證明數據
* @param publicInputs 公開輸入
* @param verificationKey 驗證密鑰
* @return 驗證是否成功
*/
function verifyPLONK(
bytes memory proof,
bytes memory publicInputs,
bytes memory verificationKey
) internal view returns (bool) {
// PLONK 驗證邏輯
// PLONK 使用 Kate-Zaverucha-Goldberg (KZG) 多項式承諾
require(proof.length >= 64, "Invalid proof length");
// 解析並驗證
return _verifyKZGCommitment(proof, publicInputs, verificationKey);
}
/**
* @dev 提交證明進行驗證
* @param modelAddress 模型地址
* @param publicInputs 公開輸入(編碼後)
* @param proof ZK 證明
* @param proofType 證明類型(0=Groth16, 1=PLONK, 2=STARK)
*/
function submitProof(
address modelAddress,
bytes memory publicInputs,
bytes memory proof,
uint8 proofType
) external returns (bytes32) {
// 驗證模型是否已授權
require(authorizedModels[modelAddress], "Model not authorized");
// 生成唯一證明 ID
bytes32 proofId = keccak256(
abi.encodePacked(modelAddress, publicInputs, proof, block.timestamp)
);
// 儲存驗證請求
pendingVerifications[proofId] = VerificationRequest({
proofId: proofId,
modelAddress: modelAddress,
publicInputs: publicInputs,
proof: proof,
timestamp: block.timestamp,
verified: false
});
pendingVerificationIds.push(proofId);
// 根據證明類型驗證
bool isValid;
if (proofType == 0) {
isValid = verifyGroth16(proof, publicInputs, "");
} else if (proofType == 1) {
isValid = verifyPLONK(proof, publicInputs, "");
} else {
revert("Unsupported proof type");
}
// 更新驗證狀態
pendingVerifications[proofId].verified = isValid;
verifiedProofs[proofId] = isValid;
if (isValid) {
emit ProofVerified(proofId, modelAddress, block.timestamp);
} else {
emit ProofRejected(proofId, "Proof verification failed");
}
return proofId;
}
/**
* @dev 批量驗證多個證明
* @param requests 驗證請求陣列
* @return results 驗證結果陣列
*/
function batchVerify(
VerificationRequest[] memory requests
) external view returns (bool[] memory results) {
results = new bool[](requests.length);
for (uint i = 0; i < requests.length; i++) {
results[i] = verifiedProofs[requests[i].proofId];
}
return results;
}
// 內部輔助函數
function _parseVerificationKey(bytes memory vk) internal pure returns (
uint256[2] memory alpha,
uint256[2] memory beta,
uint256[2] memory gamma,
uint256[2] memory delta,
uint256[2][] memory gamma_abc
) {
// 解析驗證密鑰
// 實際實現需要詳細的 ABI 解碼邏輯
// 這裡僅提供框架
}
function _pairingCheck(
uint256[2] memory alpha,
uint256[2] memory beta,
uint256[2] memory gamma,
uint256[2] memory delta,
uint256[2][] memory gamma_abc,
bytes memory proof,
bytes memory publicInputs
) internal pure returns (bool) {
// 簡化的配對檢查
// 實際需要使用 Precompiled 合約或ライブラリ
// 使用 EVM 的配對檢查預編譯合約
// 0x08 - BN128_ADD
// 0x09 - BN128_MUL
// 0x0a - BN128_PAIRING
return true; // 臨時返回
}
function _verifyKZGCommitment(
bytes memory proof,
bytes memory publicInputs,
bytes memory verificationKey
) internal pure returns (bool) {
// KZG 承諾驗證邏輯
return true; // 臨時返回
}
function _authorizeUpgrade(address newImplementation)
internal override onlyRole(UPGRADER_ROLE) {}
}
3.2 完整應用範例:ZKML 預言機
以下範例展示如何構建一個基於 ZKML 的去中心化預言機:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/**
* @title ZKMLOracle
* @dev 基於 ZKML 的去中心化 AI 預言機
*
* 這個預言機允許 AI 模型運營商提交帶有 ZK 證明的預測結果,
* 用戶可以驗證證明來確認預測的正確性
*/
contract ZKMLOracle is ReentrancyGuard {
// 預言機數據類型
enum DataType {
PRICE_FEED, // 價格數據
CREDIT_SCORE, // 信用評分
RISK_ASSESSMENT, // 風險評估
PREDICTION // 一般預測
}
// 結構體:Oracle 數據請求
struct DataRequest {
bytes32 requestId;
address requester;
DataType dataType;
bytes inputData;
uint256 timestamp;
uint256 expiration;
bool fulfilled;
bytes result;
}
// 結構體:模型提交
struct ModelSubmission {
address modelOperator;
bytes32 modelId;
string modelName;
uint256 stakeAmount;
bool registered;
uint256 totalRequests;
uint256 successfulRequests;
}
// 狀態變數
mapping(bytes32 => DataRequest) public dataRequests;
mapping(address => ModelSubmission) public registeredModels;
mapping(bytes32 => mapping(bytes32 => bool)) public verifiedResults; // requestId => resultHash => verified
IERC20 public paymentToken;
uint256 public requestFee;
uint256 public constant SLASHING_AMOUNT = 1e18; // 處罰金額
uint256 public constant CHALLENGE_PERIOD = 1 hours;
// 事件
event DataRequested(bytes32 indexed requestId, address indexed requester, DataType dataType);
event DataFulfilled(bytes32 indexed requestId, address indexed fulfiller, bytes result);
event ModelRegistered(address indexed model, bytes32 modelId, string name);
event ResultChallenged(bytes32 indexed requestId, address challenger);
constructor(address _paymentToken, uint256 _requestFee) {
paymentToken = IERC20(_paymentToken);
requestFee = _requestFee;
}
/**
* @dev 請求 AI 預言機數據
* @param dataType 數據類型
* @param inputData 輸入數據(編碼後)
* @param expiration 過期時間
* @return requestId 請求 ID
*/
function requestData(
DataType dataType,
bytes calldata inputData,
uint256 expiration
) external nonReentrant returns (bytes32) {
// 支付費用
require(
paymentToken.transferFrom(msg.sender, address(this), requestFee),
"Fee payment failed"
);
// 生成請求 ID
bytes32 requestId = keccak256(
abi.encodePacked(
msg.sender,
dataType,
inputData,
block.timestamp,
block.number
)
);
// 創建請求
dataRequests[requestId] = DataRequest({
requestId: requestId,
requester: msg.sender,
dataType: dataType,
inputData: inputData,
timestamp: block.timestamp,
expiration: expiration,
fulfilled: false,
result: ""
});
emit DataRequested(requestId, msg.sender, dataType);
return requestId;
}
/**
* @dev 模型運營商提交帶有 ZK 證明的結果
* @param requestId 請求 ID
* @param result 預測結果
* @param proof ZK 證明
* @param publicInputs 公開輸入
*/
function fulfillRequest(
bytes32 requestId,
bytes calldata result,
bytes calldata proof,
bytes calldata publicInputs
) external nonReentrant {
DataRequest storage request = dataRequests[requestId];
require(request.requester != address(0), "Request not found");
require(!request.fulfilled, "Already fulfilled");
require(block.timestamp < request.expiration, "Request expired");
// 驗證 ZK 證明
// 在實際實現中,這裡會調用 ZKML 驗證合約
bool proofValid = _verifyZKProof(proof, publicInputs, result);
require(proofValid, "Invalid proof");
// 標記為已完成
request.fulfilled = true;
request.result = result;
// 記錄驗證結果
bytes32 resultHash = keccak256(result);
verifiedResults[requestId][resultHash] = true;
emit DataFulfilled(requestId, msg.sender, result);
}
/**
* @dev 挑戰結果的正確性
* @param requestId 請求 ID
* @param result 爭議的結果
* @param proof 支持挑戰的證明
*/
function challengeResult(
bytes32 requestId,
bytes calldata result,
bytes calldata proof
) external nonReentrant {
DataRequest storage request = dataRequests[requestId];
require(request.fulfilled, "Request not fulfilled");
require(
block.timestamp - request.timestamp < CHALLENGE_PERIOD,
"Challenge period ended"
);
// 驗證挑戰者的證明
// 如果挑戰成功,原始提交者被處罰
bool challengeValid = _verifyZKProof(proof, request.inputData, result);
require(challengeValid, "Invalid challenge");
// 執行處罰邏輯
// 實際實現需要從質押中扣除
emit ResultChallenged(requestId, msg.sender);
}
/**
* @dev 查詢預言機結果
* @param requestId 請求 ID
* @return result 預測結果
*/
function getResult(bytes32 requestId) external view returns (bytes memory) {
DataRequest storage request = dataRequests[requestId];
require(request.fulfilled, "Not fulfilled");
return request.result;
}
// 內部函數
function _verifyZKProof(
bytes memory proof,
bytes memory publicInputs,
bytes memory result
) internal pure returns (bool) {
// ZK 證明驗證邏輯
// 實際實現應該調用專門的驗證合約
// 簡化的驗證邏輯
return proof.length > 0;
}
}
3.3 前端交互範例
// TypeScript: ZKML Oracle 客戶端交互
import { ethers } from 'ethers';
interface OracleRequest {
requestId: string;
dataType: number;
inputData: string;
result?: string;
fulfilled: boolean;
}
interface ZKProof {
proof: string;
publicInputs: string[];
verificationKey: string;
}
class ZKMLOracleClient {
private provider: ethers.providers.JsonRpcProvider;
private oracleContract: ethers.Contract;
private wallet: ethers.Wallet;
constructor(
rpcUrl: string,
privateKey: string,
oracleAddress: string,
oracleAbi: any
) {
this.provider = new ethers.providers.JsonRpcProvider(rpcUrl);
this.wallet = new ethers.Wallet(privateKey, this.provider);
this.oracleContract = new ethers.Contract(
oracleAddress,
oracleAbi,
this.wallet
);
}
/**
* 請求 AI 預言機數據
*/
async requestData(
dataType: number,
inputData: string,
expiration: number = 3600 // 1小時後過期
): Promise<string> {
const tx = await this.oracleContract.requestData(
dataType,
inputData,
Math.floor(Date.now() / 1000) + expiration
);
const receipt = await tx.wait();
// 從事件中提取 requestId
const event = receipt.events?.find((e: any) => e.event === 'DataRequested');
return event?.args?.requestId;
}
/**
* 獲取請求結果
*/
async getResult(requestId: string): Promise<string | null> {
const request = await this.oracleContract.dataRequests(requestId);
if (!request.fulfilled) {
return null;
}
return request.result;
}
/**
* 監聽新請求事件
*/
async watchNewRequests(
callback: (requestId: string, dataType: number) => void
): Promise<ethers.EventListener> {
return this.oracleContract.on(
'DataRequested',
(requestId, dataType) => {
callback(requestId, dataType);
}
);
}
/**
* 監聽結果完成事件
*/
async watchFulfilled(
callback: (requestId: string, result: string) => void
): Promise<ethers.EventListener> {
return this.oracleContract.on(
'DataFulfilled',
(requestId, result) => {
callback(requestId, result);
}
);
}
/**
* 生成 ZK 證明(需要後端支持)
*/
async generateProof(
modelId: string,
inputData: number[]
): Promise<ZKProof> {
// 調用後端 ZKML 服務
const response = await fetch('/api/zkml/prove', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
modelId,
inputData
})
});
return await response.json();
}
/**
* 提交結果(需要先生成證明)
*/
async fulfillRequest(
requestId: string,
result: string,
proof: string,
publicInputs: string[]
): Promise<ethers.providers.TransactionResponse> {
const tx = await this.oracleContract.fulfillRequest(
requestId,
result,
proof,
publicInputs
);
return await tx.wait();
}
}
// 使用範例
async function main() {
const client = new ZKMLOracleClient(
process.env.RPC_URL!,
process.env.PRIVATE_KEY!,
process.env.ORACLE_ADDRESS!,
// Oracle ABI
[
"function requestData(uint8 dataType, bytes calldata inputData, uint256 expiration) returns (bytes32)",
"function fulfillRequest(bytes32 requestId, bytes calldata result, bytes calldata proof, bytes calldata publicInputs)",
"function getResult(bytes32 requestId) view returns (bytes memory)",
"event DataRequested(bytes32 indexed requestId, address indexed requester, uint8 dataType)",
"event DataFulfilled(bytes32 indexed requestId, address indexed fulfiller, bytes result)"
]
);
// 請求價格預測
const requestId = await client.requestData(
0, // PRICE_FEED
ethers.utils.defaultAbiCoder.encode(
['string', 'uint256'],
['ETH/USD', 1800]
)
);
console.log(`請求 ID: ${requestId}`);
// 等待結果
const result = await new Promise<string>((resolve) => {
client.watchFulfilled(async (reqId, result) => {
if (reqId === requestId) {
resolve(result);
}
});
});
console.log(`預測結果: ${result}`);
}
main().catch(console.error);
四、實際應用場景
4.1 DeFi 風險評估
ZKML 在 DeFi 領域最重要的應用之一是信用風險評估。傳統信用評估依賴中心化機構,而 ZKML 允許用戶在不洩露敏感財務數據的情況下,獲得可信的信用評分。
# ZKML 信用評估模型範例
import numpy as np
from dataclasses import dataclass
@dataclass
class CreditScoreInput:
"""信用評估輸入數據"""
wallet_age_days: int # 錢包年齡(天)
total_transaction_count: int # 總交易次數
defi_interaction_count: int # DeFi 交互次數
avg_transaction_size: float # 平均交易規模(ETH)
lending_history_score: float # 借貸歷史評分(0-100)
collateral_ratio: float # 抵押率(0-1)
class ZKMLCreditScorer:
"""ZKML 信用評分器"""
def __init__(self, model_path: str):
self.model = self._load_model(model_path)
def _load_model(self, path):
# 加載預訓練模型
# 這裡使用簡化的權重
return {
'weights': {
'wallet_age': 0.15,
'tx_count': 0.10,
'defi_count': 0.20,
'avg_size': 0.05,
'lending_score': 0.35,
'collateral': 0.15
},
'bias': 20.0
}
def calculate_score(self, input_data: CreditScoreInput) -> float:
"""計算信用評分"""
score = self.model['bias']
score += input_data.wallet_age_days / 365 * self.model['weights']['wallet_age'] * 100
score += min(input_data.total_transaction_count / 1000, 1.0) * self.model['weights']['tx_count'] * 100
score += min(input_data.defi_interaction_count / 100, 1.0) * self.model['weights']['defi_count'] * 100
score += min(input_data.avg_transaction_size / 10, 1.0) * self.model['weights']['avg_size'] * 100
score += input_data.lending_history_score / 100 * self.model['weights']['lending_score'] * 100
score += input_data.collateral_ratio * self.model['weights']['collateral'] * 100
return min(max(score, 0), 100)
def generate_proof(self, input_data: CreditScoreInput) -> tuple:
"""
生成 ZK 證明
Returns:
(proof, public_inputs, output)
"""
# 計算信用評分
score = self.calculate_score(input_data)
# 準備電路輸入(定點數化)
input_array = np.array([
input_data.wallet_age_days,
input_data.total_transaction_count,
input_data.defi_interaction_count,
int(input_data.avg_transaction_size * 1e8),
int(input_data.lending_history_score * 1e8),
int(input_data.collateral_ratio * 1e8)
], dtype=np.uint64)
# 調用 EZKL 生成證明
# proof = ezkl.prove(...)
return (
"0x...", # proof
input_array.tobytes(), # public_inputs
int(score * 1e8) # output (fixed-point)
)
# 使用範例
def main():
scorer = ZKMLCreditScorer("models/credit_scorer.onnx")
# 準備輸入數據
user_input = CreditScoreInput(
wallet_age_days=730, # 2年
total_transaction_count=500,
defi_interaction_count=50,
avg_transaction_size=2.5, # 2.5 ETH
lending_history_score=85, # 85分
collateral_ratio=0.75 # 75% 抵押率
)
# 計算評分
score = scorer.calculate_score(user_input)
print(f"信用評分: {score:.2f}/100")
# 生成 ZK 證明(用於鏈上驗證)
proof, public_inputs, output = scorer.generate_proof(user_input)
print(f"ZK 證明已生成")
print(f"公開輸出: {output}")
if __name__ == "__main__":
main()
4.2 預測市場
ZKML 還可以用於創建可信的預測市場,其中預言機節點可以使用 ML 模型預測事件結果,並通過 ZK 證明其預測是基於正確執行的模型。
預測市場架構
─────────────────────────────────────────────────────────────
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 預測參與者 │────▶│ 預測市場 │────▶│ 結算合約 │
│ │ │ 智慧合約 │ │ │
└──────────────┘ └──────────────┘ └──────────────┘
│
▼
┌──────────────┐
│ ZKML 預言機 │
│ │
│ 1. 收集數據 │
│ 2. ML 預測 │
│ 3. 生成證明 │
│ 4. 提交結果 │
└──────────────┘
4.3 遊戲與 NFT
在區塊鏈遊戲中,ZKML 可以用於生成不可預測但可驗證的遊戲結果(如隨機事件、AI 對手行為),同時確保遊戲邏輯的公平性。
// 遊戲中的 ZKML 隨機數生成
contract ZKMLGameRandomness {
struct RandomRequest {
bytes32 requestId;
address player;
uint256 gameId;
uint256 timestamp;
bytes32 seed;
bool fulfilled;
}
mapping(bytes32 => RandomRequest) public requests;
event RandomnessRequested(bytes32 indexed requestId, address indexed player);
event RandomnessFulfilled(bytes32 indexed requestId, uint256 randomResult);
/**
* @dev 請求遊戲隨機數
* @param gameId 遊戲 ID
* @return requestId 請求 ID
*/
function requestRandomness(uint256 gameId) external returns (bytes32) {
bytes32 requestId = keccak256(
abi.encodePacked(msg.sender, gameId, block.timestamp, block.prevrandao)
);
requests[requestId] = RandomRequest({
requestId: requestId,
player: msg.sender,
gameId: gameId,
timestamp: block.timestamp,
seed: 0,
fulfilled: false
});
emit RandomnessRequested(requestId, msg.sender);
return requestId;
}
/**
* @dev 使用 ZKML 證明提交隨機結果
* @param requestId 請求 ID
* @param randomResult 隨機結果
* @param proof ZK 證明(證明模型正確執行)
*/
function fulfillRandomness(
bytes32 requestId,
uint256 randomResult,
bytes calldata proof
) external {
RandomRequest storage req = requests[requestId];
require(req.player != address(0), "Request not found");
require(!req.fulfilled, "Already fulfilled");
// 驗證 ZK 證明(確保隨機數來自正確的 ML 模型)
// 實際實現需要完整的驗證邏輯
require(_verifyProof(proof, req.seed, randomResult), "Invalid proof");
req.fulfilled = true;
req.seed = bytes32(randomResult);
emit RandomnessFulfilled(requestId, randomResult);
}
function _verifyProof(
bytes memory proof,
bytes32 seed,
uint256 result
) internal pure returns (bool) {
// 簡化的證明驗證
return proof.length > 0;
}
}
五、效能優化與最佳實踐
5.1 Gas 優化策略
ZKML 驗證在以太坊上的主要挑戰是 Gas 成本。以下是關鍵優化策略:
批量驗證:將多個證明合併為單一驗證,降低平均成本。
// 批量驗證優化
function batchVerifyProofs(
bytes[] memory proofs,
bytes[] memory publicInputs
) internal view returns (bool[] memory) {
require(proofs.length == publicInputs.length, "Length mismatch");
bool[] memory results = new bool[](proofs.length);
// 使用 EVM 的批量配對檢查
for (uint i = 0; i < proofs.length; i++) {
results[i] = verifyGroth16(proofs[i], publicInputs[i], "");
}
return results;
}
離線驗證 + 挑戰機制:大部分驗證在鏈下進行,僅在爭議時鏈上驗證。
壓縮證明:使用recursive proof compression 減少鏈上數據量。
5.2 安全考量
質押與處罰:要求模型運營商質押代幣,提交錯誤證明時扣除質押。
挑戰窗口期:提供充足的時間讓任何人挑戰錯誤結果。
多元預言機:使用多個獨立模型運營商,降低單點故障風險。
六、結論與未來展望
ZKML 代表了區塊鏈與人工智慧融合的核心方向。透過將 AI 推論轉化為可驗證的密碼學證明,我們可以在不犧牲去中心化和隱私的情況下,實現可信的鏈上 AI 應用。
截至 2026 年第一季度,ZKML 技術已經從實驗走向初步部署階段。主要進展包括:
協議層面:多個 ZKML 專用協議正在開發,包括 Giza、Modulus Labs、EZKL 等。
應用層面:預言機、借貸、風險評估、遊戲等場景已經開始實際應用。
基礎設施:ZK 證明生成成本持續下降,硬體加速方案逐步成熟。
挑戰依然存在:證明生成時間、驗證 Gas 成本、模型複雜度限制等問題需要進一步解決。但隨著技術進步,ZKML 有望成為區塊鏈 AI 應用的標準組件。
參考資源
- EZKL 官方文檔:https://docs.ezkl.xyz
- Noir 語言文檔:https://noir-lang.org
- Circom 電路框架:https://docs.circom.io
- Giza 協議:https://giza.ai
-以太坊 ZK 證明預編譯合約:EIP-196、EIP-197
相關文章
- ZKML 以太坊深度技術實作完整指南:零知識機器學習應用程式碼範例與工程實踐 — ZKML(Zero-Knowledge Machine Learning)代表著區塊鏈與人工智慧交叉領域最具突破性的技術融合。本指南從工程師視角出發,提供截至2026年第一季度的ZKML技術全景圖,重點涵蓋Circom、Noir、Halo2等主流框架的程式碼範例、ZKML智慧合約部署實務、以及在DeFi、借貸、保險等場景的具體應用實現。我們展示可直接用於生產環境的程式碼架構,幫助開發團隊快速掌握這項前沿技術的工程實作細節。
- ZKML 與以太坊整合深度技術分析:零知識證明在機器學習領域的革命性應用 — 零知識證明與機器學習的結合(ZKML)正在區塊鏈領域引發深刻變革。本文全面分析 ZKML 的技術原理、在以太坊上的實現方式、主要應用場景和未來發展趨勢。從去中心化 AI 市場到隱私保護預測市場,從模型驗證到推理認證,我們提供詳實的技術細節和實踐建議。
- 以太坊 ZKML 應用完整指南:零知識證明與機器學習的融合技術架構與實踐 — ZKML(零知識機器學習)代表了區塊鏈技術與人工智慧交叉領域最具前沿性的創新方向。本文深入分析 ZKML 的技術原理、實現架構、主要協議與項目(ezkl、Giza、Modulus Labs 等),涵蓋去中心化 AI、隱私信用評估、醫療數據分析、遊戲與 NFT 等應用場景,並提供完整的開發實踐指南。
- ZK-SNARKs 與 ZK-STARKs 以太坊實戰應用完整指南:從理論到部署的工程實踐 — 零知識證明技術在以太坊生態系統中的應用已從理論走向大規模實際部署。本文深入探討 ZK-SNARKs 和 ZK-STARKs 兩大主流證明系統在以太坊上的實際應用案例,提供可直接部署的智慧合約程式碼範例,涵蓋隱私交易、身份驗證、批量轉帳、AI 模型推理驗證等完整實作。
- ZKML 零知識機器學習以太坊開發實踐:完整智能合約範例與部署指南 — 零知識機器學習(ZKML)是以太坊生態系統中最具創新性的技術交叉領域之一。本文提供完整的 ZKML 開發實踐指南,包含多個可直接部署的 Solidity 智慧合約範例,涵蓋信用評估、模型知識財產權保護、和去中心化預言機等應用場景。同時提供完整的部署腳本和測試用例,幫助開發者快速掌握這項前沿技術。
延伸閱讀與來源
- Ethereum.org Developers 官方開發者入口與技術文件
- EIPs 以太坊改進提案
這篇文章對您有幫助嗎?
請告訴我們如何改進:
評論
發表評論
注意:由於這是靜態網站,您的評論將儲存在本地瀏覽器中,不會公開顯示。
目前尚無評論,成為第一個發表評論的人吧!