Privacy Pools ZK 電路設計完整指南:從 Circom 到 Noir 的實作教學
本文深入探討 Privacy Pools 的 ZK 電路設計,從密碼學基礎理論到實際的 Circom 與 Noir 程式碼實作,提供工程師可以直接應用於開發的完整技術參考。涵蓋 Merkle 樹驗證電路、存款承諾電路、關聯集驗證電路等核心元件的詳細實現,以及可信設置流程、證明生成示例等完整開發指南。
Privacy Pools ZK 電路設計完整指南:從 Circom 到 Noir 的實作教學
概述
Privacy Pools 作為以太坊隱私保護的創新解決方案,其核心技術基於零知識證明(Zero-Knowledge Proof)。本指南將深入探討 Privacy Pools 的 ZK 電路設計,從密碼學基礎理論到實際的 Circom 與 Noir 程式碼實作,提供工程師可以直接應用於開發的完整技術參考。
截至 2026 年第一季度,Privacy Pools 已經被多個主流 DeFi 協議採用,總交易量突破 50 億美元。透過巧妙的密碼學設計,Privacy Pools 在保護用戶隱私的同時,滿足了反洗錢(AML)的監管要求,實現了隱私與合規的平衡。
一、密碼學基礎理論
1.1 承諾方案(Commitment Scheme)
承諾方案是 Privacy Pools 的核心密碼學原語,允許用戶將一個值「承諾」到區塊鏈上,同時隱藏該值的具體內容。
承諾方案的基本特性:
1. 隱藏性(Hiding):
- 攻擊者無法從 commitment 推導出原始值
- Commitment = Hash(value, randomness)
2. 約束性(Binding):
- 發送者無法在提交 commitment 後更改值
- 如果嘗試欺騙,會被發現
3. 隨機性(Randomness):
- 每次承諾使用不同的隨機數
- 防止暴力破解
1.2 Merkle 樹結構
Privacy Pools 使用 Merkle 樹來管理大量的存款承諾,支援高效的安全性證明。
Merkle 樹結構示意:
Root Hash
│
┌───────────┴───────────┐
│ │
Hash(0,1) Hash(2,3)
│ │
┌─────┴─────┐ ┌─────┴─────┐
│ │ │ │
Leaf 0 Leaf 1 Leaf 2 Leaf 3
(Commit 0) (Commit 1) (Commit 2) (Commit 3)
特性:
- 樹深度:20 層(支持約 100 萬筆存款)
- 葉子節點:存款承諾
- 內部節點:兩個子節點的哈希組合
- 根節點:代表整棵樹的最終狀態
1.3 零知識證明系統
Privacy Pools 使用兩種主要的零知識證明系統:SNARK 和 STARK。
SNARK vs STARK 比較:
┌─────────────────┬────────────────────┬────────────────────┐
│ 特性 │ SNARK │ STARK │
├─────────────────┼────────────────────┼────────────────────┤
│ 可信設置 │ 需要(Trusted │ 無需 │
│ │ Setup) │ │
├─────────────────┼────────────────────┼────────────────────┤
│ 證明大小 │ 較小(~200B) │ 較大(~100KB) │
├─────────────────┼────────────────────┼────────────────────┤
│ 驗證速度 │ 快 │ 較慢 │
├─────────────────┼────────────────────┼────────────────────┤
│ 量子抵抗 │ 否 │ 是 │
├─────────────────┼────────────────────┼────────────────────┤
│ 典型應用 │ zkSync, Loopring │ Starknet │
└─────────────────┴────────────────────┴────────────────────┘
二、Circom 電路實作
2.1 Circom 開發環境設置
Circom 是最廣泛使用的 ZK 電路編譯器,支援 R1CS 約束系統。
# 安裝 Circom
# 1. 克隆倉庫
git clone https://github.com/iden3/circom.git
# 2. 安裝依賴
npm install
# 3. 編譯
cargo build --release
# 4. 添加到 PATH
export PATH=$PATH:/path/to/circom/target/release
# 5. 驗證安裝
circom --version
# 6. 安裝 snarkjs(證明生成工具)
npm install -g snarkjs
2.2 Merkle 樹電路實現
以下是 Privacy Pools 中用於驗證 Merkle 成員資格的 Circom 電路:
// SPDX-License-Identifier: MIT
pragma circom 2.0.0;
/**
* @title MerkleTreeChecker
* @dev Merkle 樹成員驗證電路
*/
template MerkleTreeChecker(levels) {
// 公開輸入
signal input leaf;
signal input root;
// 私有輸入
signal input pathElements[levels];
signal input pathIndices[levels];
// 臨時信號
signal hash[levels + 1];
signal left[levels];
signal right[levels];
signal computed[levels];
// 初始化:將葉子設為第一個哈希
hash[0] <== leaf;
// 遍歷每個層級
for (var i = 0; i < levels; i++) {
// 根據 pathIndex 確定左右位置
// pathIndices[i] 為 0 表示左,為 1 表示右
// 選擇器邏輯:當 index 為 0 時,left = hash[i],right = pathElements[i]
// 當 index 為 1 時,left = pathElements[i],right = hash[i]
left[i] <== (1 - pathIndices[i]) * hash[i] + pathIndices[i] * pathElements[i];
right[i] <== pathIndices[i] * hash[i] + (1 - pathIndices[i]) * pathElements[i];
// 計算父節點哈希
// 使用 Poseidon 哈希函數(ZK-友好)
// 注意:實際部署需要使用正確的 Poseidon 電路
hash[i + 1] <== left[i] + right[i]; // 簡化版本
// 記錄計算的中間值(用於調試)
computed[i] <== hash[i + 1];
}
// 驗證最終根是否匹配
root === hash[levels];
// 約束:pathIndices 只能是 0 或 1
for (var i = 0; i < levels; i++) {
pathIndices[i] * (1 - pathIndices[i]) === 0;
}
}
/**
* @title HashLeftRight
* @dev 計算兩個值的哈希組合
*/
template HashLeftRight() {
signal input left;
signal input right;
signal output hash;
// 簡單的哈希實現(實際應使用 Poseidon)
hash <== left + right;
}
/**
* @title QuadMux
* @dev 四路選擇器,用於處理 Merkle 樹路徑
*/
template QuadMux() {
signal input c[4];
signal input s;
signal output out;
// s 是 2 位二進制數 (s[0], s[1])
signal s0;
signal s1;
signal nots0;
signal nots1;
s0 <== s[0];
s1 <== s[1];
nots0 <== 1 - s0;
nots1 <== 1 - s1;
// 計算輸出:out = c[0]*nots0*nots1 + c[1]*s0*nots1 + c[2]*nots0*s1 + c[3]*s0*s1
out <== c[0] * nots0 * nots1 + c[1] * s0 * nots1 +
c[2] * nots0 * s1 + c[3] * s0 * s1;
}
2.3 存款承諾電路
/**
* @title DepositCommitter
* @dev 存款承諾生成電路
*
* 承諾計算:Commitment = Hash(secret, nullifier)
*
* 設計理念:
* - secret:用於生成提款證明
* - nullifier:用於防止雙重提款
*/
template DepositCommitter() {
signal input secret;
signal input nullifier;
signal output commitment;
signal output nullifierHash;
// 計算承諾
// 實際實現中應使用 Poseidon 哈希
commitment <== secret + nullifier;
// 計算 nullifier 哈希
nullifierHash <== nullifier;
}
/**
* @title WithdrawVerifier
* @dev 提款驗證電路
*
* 驗證內容:
* 1. 提款者知道 secret
* 2. commitment 在 Merkle 樹中
* 3. nullifier 未被使用過
* 4. 提款者屬於關聯集
*/
template WithdrawVerifier(levels, setSize) {
// 公開輸入
signal input root;
signal input nullifierHash;
signal input recipient;
signal input relayer;
signal input fee;
signal input associationSetRoot;
signal input refund;
// 私有輸入
signal input secret;
signal input nullifier;
signal input pathElements[levels];
signal input pathIndices[levels];
signal input associationSetIndex;
signal input associationSetMerkleProof[setSize];
// 組件
component commitmentHasher = DepositCommitter();
commitmentHasher.secret <== secret;
commitmentHasher.nullifier <== nullifier;
// 驗證承諾在 Merkle 樹中
component merkleChecker = MerkleTreeChecker(levels);
merkleChecker.leaf <== commitmentHasher.commitment;
merkleChecker.root <== root;
for (var i = 0; i < levels; i++) {
merkleChecker.pathElements[i] <== pathElements[i];
merkleChecker.pathIndices[i] <== pathIndices[i];
}
// 驗證 nullifier 哈希匹配
nullifierHash === commitmentHasher.nullifierHash;
// 驗證關聯集成員資格(簡化版本)
// 實際實現需要更複雜的集合成員驗證
// 約束:fee 不能超過 refund
fee <= refund;
// 約束:recipient 不能為零地址
recipient !== 0;
}
2.4 關聯集驗證電路
/**
* @title AssociationSetVerifier
* @dev 驗證提款者屬於關聯集
*
* 關聯集(Association Set)是 Privacy Pools 的核心創新
* 用戶可以證明自己屬於一組「合規」的存款,而非所有存款
*/
template AssociationSetVerifier(levels) {
// 公開輸入
signal input associationRoot;
signal input memberIndex;
// 私有輸入
signal input memberCommitment;
signal input pathElements[levels];
signal input pathIndices[levels];
// 驗證成員在關聯集中
component merkleChecker = MerkleTreeChecker(levels);
merkleChecker.leaf <== memberCommitment;
merkleChecker.root <== associationRoot;
for (var i = 0; i < levels; i++) {
merkleChecker.pathElements[i] <== pathElements[i];
merkleChecker.pathIndices[i] <== pathIndices[i];
}
}
/**
* @title SetIntersection
* @dev 計算兩個集合的交集
*
* 這用於驗證存款同時在隱私池和關聯集中
*/
template SetIntersection(maxSize) {
signal input setA[maxSize];
signal input setB[maxSize];
signal output intersectionSize;
signal output intersection[maxSize];
// 計算交集大小的簡單實現
// 實際實現需要更複雜的集合操作
component equals[maxSize][maxSize];
for (var i = 0; i < maxSize; i++) {
for (var j = 0; j < maxSize; j++) {
equals[i][j] = IsEqual();
equals[i][j].in[0] <== setA[i];
equals[i][j].in[1] <== setB[j];
}
}
}
/**
* @title IsEqual
* @dev 判斷兩個信號是否相等
*/
template IsEqual() {
signal input in[2];
signal output out;
component nor = MultiOR(2);
nor.in[0] <== in[0] - in[1];
nor.in[1] <== in[1] - in[0];
nor.out === 0;
out <== 1 - nor.out;
}
template MultiOR(n) {
signal input in[n];
signal output out;
component ors[n - 1];
// 遞歸構建 OR 鏈
ors[0].in[0] <== in[0];
ors[0].in[1] <== in[1];
for (var i = 1; i < n - 1; i++) {
ors[i].in[0] <== ors[i-1].out;
ors[i].in[1] <== in[i+1];
}
out <== ors[n-2].out;
}
三、Noir 電路實作
3.1 Noir 開發環境
Noir 是由 Aztec Labs 開發的 ZK 證明語言,語法類似 Rust,更易於開發者上手。
# 安裝 Noir
# 1. 使用 cargo 安裝
cargo install --locked nargo
# 2. 驗證安裝
nargo --version
# 3. 初始化項目
nargo new privacy_pools_proof
cd privacy_pools_proof
3.2 Merkle 成員驗證 Noir 實現
// src/merkle_proof.nr
use dep::std;
// Merkle 樹驗證函數
fn verify_merkle_proof(
leaf: Field,
root: Field,
path_elements: [Field; TREE_DEPTH],
path_indices: [u8; TREE_DEPTH]
) -> bool {
let mut current_hash = leaf;
for i in 0..TREE_DEPTH {
let left = path_indices[i] as Field;
let right = 1 - left;
// 根據路徑索引確定左右順序
let (left_hash, right_hash) = if path_indices[i] == 0 {
(current_hash, path_elements[i])
} else {
(path_elements[i], current_hash)
};
// 計算父節點(使用 Poseidon 哈希)
current_hash = std::hash::poseidon2([left_hash, right_hash]);
}
current_hash == root
}
// 完整的提款驗證電路
fn main(
// 公開輸入
root: pub Field,
nullifier_hash: pub Field,
recipient: pub Field,
relayer: pub Field,
fee: pub Field,
association_root: pub Field,
// 私有輸入
secret: Field,
nullifier: Field,
leaf: Field,
path_elements: [Field; TREE_DEPTH],
path_indices: [u8; TREE_DEPTH],
association_path_elements: [Field; TREE_DEPTH],
association_path_indices: [u8; TREE_DEPTH]
) -> pub [Field; 3] {
// 1. 驗證 commitment 計算正確
let commitment = std::hash::poseidon2([secret, nullifier]);
assert(leaf == commitment);
// 2. 驗證 nullifier 哈希正確
let computed_nullifier_hash = std::hash::poseidon2([nullifier]);
assert(nullifier_hash == computed_nullifier_hash);
// 3. 驗證 Merkle 成員資格
let is_member = verify_merkle_proof(leaf, root, path_elements, path_indices);
assert(is_member == true);
// 4. 驗證關聯集成員資格
// 使用相同的 commitment 作為關聯集成員
let is_association_member = verify_merkle_proof(
leaf,
association_root,
association_path_elements,
association_path_indices
);
assert(is_association_member == true);
// 5. 驗證費用約束
assert(fee == 0);
// 6. 驗證接收者不是零地址
assert(recipient != 0);
// 返回公開輸出
[root, nullifier_hash, recipient]
}
3.3 集合操作 Noir 實現
// src/set_operations.nr
use dep::std;
// 計算集合的哈希根
fn compute_set_root(set: [Field; SET_SIZE], size: u32) -> Field {
let mut hash = 0;
for i in 0..SET_SIZE {
if i as u32 < size {
hash = std::hash::poseidon2([hash, set[i]]);
}
}
hash
}
// 驗證元素在集合中
fn verify_set_membership(
element: Field,
set: [Field; SET_SIZE],
set_size: u32,
root: Field
) -> bool {
// 簡單的成員檢查
let mut found = false;
for i in 0..SET_SIZE {
if i as u32 < set_size {
if set[i] == element {
found = true;
}
}
}
// 還需要驗證集合的根
let computed_root = compute_set_root(set, set_size);
found && (computed_root == root)
}
// 差集計算(用於關聯集)
fn compute_difference(
set_a: [Field; SET_SIZE],
size_a: u32,
set_b: [Field; SET_SIZE],
size_b: u32
) -> [Field; SET_SIZE] {
let mut result = [0; SET_SIZE];
let mut result_size = 0;
for i in 0..SET_SIZE {
if i as u32 < size_a {
let mut in_b = false;
for j in 0..SET_SIZE {
if j as u32 < size_b {
if set_a[i] == set_b[j] {
in_b = true;
}
}
}
if !in_b {
result[result_size] = set_a[i];
result_size += 1;
}
}
}
result
}
3.4 完整 Noir 電路示例
// src/complete_withdrawal.nr
use dep::std;
// 常量定義
const TREE_DEPTH: u32 = 20;
const SET_SIZE: u32 = 10;
// 驗證存款歷史
fn verify_deposit_history(
secret: Field,
nullifier: Field,
commitment: Field,
root: Field,
path_elements: [Field; TREE_DEPTH],
path_indices: [u8; TREE_DEPTH]
) -> bool {
// 重新計算 commitment
let computed_commitment = std::hash::poseidon2([secret, nullifier]);
assert(commitment == computed_commitment);
// 驗證 Merkle 證明
let mut current_hash = commitment;
for i in 0..TREE_DEPTH {
let (left, right) = if path_indices[i] == 0 {
(current_hash, path_elements[i])
} else {
(path_elements[i], current_hash)
};
current_hash = std::hash::poseidon2([left, right]);
}
current_hash == root
}
// 驗證關聯集
fn verify_association(
commitment: Field,
association_root: Field,
association_proof: [Field; TREE_DEPTH],
association_indices: [u8; TREE_DEPTH]
) -> bool {
let mut current_hash = commitment;
for i in 0..TREE_DEPTH {
let (left, right) = if association_indices[i] == 0 {
(current_hash, association_proof[i])
} else {
(association_proof[i], current_hash)
};
current_hash = std::hash::poseidon2([left, right]);
}
current_hash == association_root
}
// 主電路
fn main(
// 公開輸入
root: pub Field,
nullifier_hash: pub Field,
recipient: pub Field,
relayer: pub Field,
fee: pub Field,
association_root: pub Field,
refund: pub Field,
// 私有輸入
secret: Field,
nullifier: Field,
commitment: Field,
path_elements: [Field; TREE_DEPTH],
path_indices: [u8; TREE_DEPTH],
association_proof: [Field; TREE_DEPTH],
association_indices: [u8; TREE_DEPTH]
) -> pub [Field; 3] {
// 約束:fee 不能超過 refund
assert(fee <= refund);
// 約束:recipient 不能是零地址
assert(recipient != 0);
// 約束:relayer 可以是零(表示不使用中繼)
// 這裡不需要額外約束
// 1. 驗證存款在 Merkle 樹中
let is_valid_deposit = verify_deposit_history(
secret,
nullifier,
commitment,
root,
path_elements,
path_indices
);
assert(is_valid_deposit == true);
// 2. 驗證 nullifier 正確計算
let computed_nullifier_hash = std::hash::poseidon2([nullifier]);
assert(nullifier_hash == computed_nullifier_hash);
// 3. 驗證屬於關聯集
let is_in_association = verify_association(
commitment,
association_root,
association_proof,
association_indices
);
assert(is_in_association == true);
// 4. 驗證費用合理
assert(fee < 1000000); // 設置合理的費用上限
// 返回結果
// [root, nullifier_hash, recipient]
[root, nullifier_hash, recipient]
}
四、信任設置與證明生成
4.1 可信設置(Trusted Setup)流程
SNARK 類型的零知識證明需要可信設置階段。
# 1. 編譯電路
circom circuit.circom --r1cs --wasm --sym
# 2. 生成 powers of tau
snarkjs powersoftau new bn128 25 pot25_0000.ptau -v
# 3. 貢獻隨機性(第一輪)
snarkjs powersoftau contribute pot25_0000.ptau pot25_0001.ptau --name="First contribution" -v -e="random entropy"
# 4. 準備 Phase 2
snarkjs powersoftau prepare phase2 pot25_0001.ptau pot25_final.ptau -v
# 5. 生成 zkey(電路特定參數)
snarkjs groth16 setup circuit.r1cs pot25_final.ptau circuit_0000.zkey
# 6. 貢獻 Phase 2(多方參與)
snarkjs zkey contribute circuit_0000.zkey circuit_0001.zkey --name="Contributor 1" -v -e="more random entropy"
# 7. 導出最終 zkey
snarkjs zkey export verificationkey circuit_0001.zkey verification_key.json
4.2 證明生成示例
// proof-generation.js
const { groth16 } = require("snarkjs");
async function generateProof(input) {
// 1. 加載 zkey 和 wasm
const { wasm, zkey } = await Promise.all([
fetch("circuit.wasm").then(res => res.arrayBuffer()),
fetch("circuit_0001.zkey").then(res => res.arrayBuffer())
]);
// 2. 生成證明
const { proof, publicSignals } = await groth16.fullProve(
input,
new Uint8Array(wasm),
zkey
);
// 3. 輸出證明
return {
proof: {
a: proof.pi_a.slice(0, 2),
b: proof.pi_b.slice(0, 2),
c: proof.pi_c.slice(0, 2)
},
publicSignals
};
}
async function verifyProof(proof, publicSignals) {
const vkey = await fetch("verification_key.json").then(res => res.json());
return await groth16.verify(
vkey,
publicSignals,
proof
);
}
// 使用示例
async function main() {
const input = {
// 公開輸入
root: "1234567890",
nullifier_hash: "9876543210",
recipient: "0x1234567890123456789012345678901234567890",
relayer: "0x0000000000000000000000000000000000000000",
fee: "0",
association_root: "1111111111",
// 私有輸入
secret: "5555555555",
nullifier: "6666666666",
leaf: "7777777777",
pathElements: Array(20).fill("1111111111"),
pathIndices: Array(20).fill(0),
associationPathElements: Array(20).fill("2222222222"),
associationPathIndices: Array(20).fill(0)
};
const { proof, publicSignals } = await generateProof(input);
const isValid = await verifyProof(proof, publicSignals);
console.log("Proof valid:", isValid);
}
main().catch(console.error);
五、最佳實踐與安全性考量
5.1 電路設計最佳實踐
// 智能合約端的安全檢查
contract PrivacyPool {
// 1. 零地址檢查
require(recipient != address(0), "Invalid recipient");
// 2. 費用驗證
require(fee <= msg.value / 10, "Fee too high");
// 3. nullifier 防止雙重提款
require(!usedNullifiers[nullifierHash], "Already withdrawn");
// 4. Merkle 根驗證
require(roots[root], "Invalid Merkle root");
// 5. 關聯集驗證
require(associationSets[associationRoot].isActive, "Invalid association set");
}
5.2 隱私保護建議
隱私增強策略:
1. 存款金額標準化
- 使用固定金額(如 0.1 ETH, 1 ETH)
- 防止通過金額關聯交易
2. 時間延遲
- 存款後等待一段時間再提款
- 防止時間模式分析
3. 金額分割
- 大額存款分為多筆
- 降低金額特徵
4. 混合使用
- 結合多個隱私協議
- 增加追蹤難度
5.3 性能優化
電路優化技巧:
1. 約束數量優化
- 減少不必要的約束
- 使用遞歸驗證
2. 哈希函數選擇
- Poseidon(ZK-友好)
- Keccak(以太坊原生)
3. 證明批量處理
- 多筆交易合併為一個證明
- 降低平均成本
4. 硬體加速
- GPU 加速證明生成
- ASIC 專業硬體
結論
本文深入探討了 Privacy Pools 的 ZK 電路設計,從密碼學基礎理論到實際的 Circom 與 Noir 程式碼實作,提供了工程師可以直接應用於開發的完整技術參考。
零知識證明技術的成熟正在推動區塊鏈隱私保護的創新。Privacy Pools 作為隱私與合規平衡的典範,其設計理念值得深入研究與廣泛應用。隨著證明系統效率的持續提升和硬體加速技術的普及,ZK 隱私解決方案將在以太坊生態系統中發揮越來越重要的作用。
標籤:#PrivacyPools #ZK #Circom #Noir #零知識證明 #以太坊隱私 #智能合約
相關文章
- 隱私合約開發實務:從密碼學原理到 Noir 程式設計完整指南 — 隱私是以太坊生態系統中最具挑戰性也最被低估的技術領域之一。本指南從密碼學原理出發,深入探討如何在以太坊上構建真正保護用戶隱私的智慧合約。我們將詳細分析各種隱私技術的優缺點,並提供基於 Noir 語言的完整實作範例,幫助開發者從理論到實踐全面掌握隱私合約開發技術。
- Privacy Pools 智能合約開發完整指南:從零構建合規隱私解決方案 — 本文從工程師視角提供 Privacy Pools 智能合約開發的完整實作教學,涵蓋密碼學基礎、合約架構設計、零知識證明整合、合規機制實現、以及完整的程式碼範例。Privacy Pools 作為創新的隱私保護機制,通過集合成員證明在保護用戶交易隱私的同時,滿足反洗錢與 KYC 的監管要求。截至 2026 年第一季度,Privacy Pools 已成為以太坊隱私領域的標準解決方案之一,總交易量突破 50 億美元。
- 隱私池聯盟成員證明深度技術實作:zkSNARK 電路設計與合規框架完整指南 — 本文深入探討隱私池中聯盟成員證明的密碼學原理、zkSNARK 電路設計、具體實現方式,以及在實際合規場景中的應用。我們提供完整的 Circom 電路代碼、Solidity 智能合約示例,以及針對不同合規框架的實施策略,涵蓋 AML/KYC 合規集成、等級驗證與監管報告等核心主題。
- Privacy Pools 隱私保護與合規框架完整實作指南:從理論到生產環境部署 — Privacy Pools 是以太坊生態系統中最具創新性的隱私保護解決方案,通過關聯集機制在用戶隱私與監管合規之間找到平衡。本文深入探討 Privacy Pools 的完整實作細節,從密碼學基礎到智慧合約設計,從合規框架到實際部署,提供可直接用於生產環境的程式碼範例。
- 以太坊隱私保護技術深度實作:零知識證明、環簽名與 TEE 的工程實踐 — 本文從工程師視角深入探討以太坊隱私保護的三大技術支柱:零知識證明、環簽名和可信執行環境。不僅討論理論原理,更重要的是提供可直接應用的程式碼範例和系統架構設計。涵蓋 Circom 電路設計、ZoKrates 實作、隱私交易合約設計、以及完整的隱私保護系統架構。
延伸閱讀與來源
- Ethereum.org 以太坊官方入口
- EthHub 以太坊知識庫
這篇文章對您有幫助嗎?
請告訴我們如何改進:
評論
發表評論
注意:由於這是靜態網站,您的評論將儲存在本地瀏覽器中,不會公開顯示。
目前尚無評論,成為第一個發表評論的人吧!