メインコンテンツまでスキップ

証拠の検証

証拠を自分で検証する

プルーフは標準の SP1 圧縮プルーフです。 SP1 SDK を使用して検証します。

use sp1_sdk::{ProverClient, SP1ProofWithPublicValues};

let client = ProverClient::from_env();
let (_, vk) = client.setup(ELF);
let proof = SP1ProofWithPublicValues::load("proof.bin")?;
client.verify(&proof, &vk)?;

検証キーは決定的であり、ゲスト プログラム バイナリから派生します。誰でも再現できます。
ZkEVM SP1 ゲスト プログラムの不変性は、プログラム キーによって証明されます。証明者のソース コードは GitHub で入手できます。誰でもコンパイルしてプログラム キーを比較できます。 SP1 ゲスト プログラムに変更が実行されると、プログラム キーも変更されます。

名前解決の証明を確認する

クライアントが ZCash ドメイン名を解決すると、インデクサー ノードを信頼せずに、絶対的なセキュリティ、同期の有効性、および状態の整合性を保証するために、プロセスが 4 つの論理段階で実行されます。

  1. ドメイン解決クエリ: クライアントは、ZcashNames Resolution Indexer エンドポイント (例: GET /v1.0/resolve/richard.zcash) にリクエストを作成します。インデクサーは、ターゲット ZCash アドレス、所有者の公開キー、価格、ノンス、SMT ルート、およびスパース マークル ツリー (SMT) 内のパスを表す 128 個の兄弟ハッシュを含むドメインの詳細を返します。

  2. ローカル SMT プルーフ検証: インデクサーが偽の解決策を返さないようにするために、クライアントはマークル メンバーシップ証明をローカルで検証します。リーフ データは以下を連結して構築されます。 domain_name (UTF-8 バイト) + owner_pubkey (16 進数からの 32 バイト) + target_address (UTF-8 バイト) + price (u64 リトルエンディアン) + nonce (u64 リトルエンディアン)。 このリーフ データの SHA-256 ハッシュを計算し、兄弟ハッシュを使用して SMT を最大 128 レベルまで走査します。計算されたルートがインデクサーの smt_root と一致する場合、証明は暗号的に健全です。

  3. 最新のルート同期検証: インデクサーのルートがブロックチェーンと同期しているかどうかを確認するには、currentRoot() 関数 (セレクター 0xfdab463d) を使用して、EVM (Arbitrum) コントラクトからオンチェーン上の最新の検証済み SMT ルートをクエリします。インデクサーの smt_root と一致する場合、インデクサーは完全に同期されています。

  4. 履歴ルート検証 (EVM RPC フォールバック): インデクサーのルートが最新のコントラクト ルートと一致しない場合 (同期ラグにより発生する可能性があります)、コントラクトのマッピング rootHistory(bytes32) (セレクター 0x66dd97ab) をクエリして、インデクサーのルートが履歴的に有効かどうかを確認します。

    • マッピングがゼロ以外の値を返した場合: ルートは契約上で歴史的に検証されています。クライアントには、インデクサーの一時的な遅延について警告が表示されますが、安全に続行できます。
    • マッピングが 0 を返す場合: ルートはブロックチェーン上でコミットまたは検証されていません。この解決策は、セキュリティ上の理由から直ちにブロックされます。

ローカル SMT プルーフ コード例

以下に、完全なリーフ ハッシュ レイアウトを使用して解決された名前の SMT 証明を検証する方法を示す Python、PHP、および JavaScript の例を示します。

import hashlib
import struct

def get_bit(key_bytes, bit_idx):
"""
Returns the bit value (0 or 1) at a given index (0 to 127)
from MSB to LSB of the 16-byte key.
"""
byte_pos = bit_idx // 8
bit_pos = 7 - (bit_idx % 8)
return (key_bytes[byte_pos] >> bit_pos) & 1

def verify_smt_proof(domain_name, target_address, owner_pubkey, price, nonce, merkle_proof, expected_root):
# 1. Compute key as SHA-256 of lowercase domain name
key_hash = hashlib.sha256(domain_name.lower().encode('utf-8')).digest()
# Take first 16 bytes (128 bits) for a depth-128 SMT
key = key_hash[:16]

# 2. Compute leaf hash as SHA-256 of concatenated leaf values
domain_buf = domain_name.encode('utf-8')
pubkey_buf = bytes.fromhex(owner_pubkey)
address_buf = target_address.encode('utf-8')
price_buf = struct.pack('<Q', price) # 64-bit unsigned integer in little-endian
nonce_buf = struct.pack('<Q', nonce) # 64-bit unsigned integer in little-endian

leaf_data = domain_buf + pubkey_buf + address_buf + price_buf + nonce_buf
current = hashlib.sha256(leaf_data).digest()

# 3. Hash up the tree using the 128 sibling hashes
# Sibling proof array goes from bottom (closest to leaf, index 0) to top (closest to root, index 127)
for i in range(128):
sibling = bytes.fromhex(merkle_proof[i])

# Level 127 (index 0) corresponds to the bottom-most bit (bit 127)
# Level 0 (index 127) corresponds to the top-most bit (bit 0)
bit_idx = 127 - i
bit = get_bit(key, bit_idx)

if bit == 1:
# Current node is on the right, sibling is on the left
current = hashlib.sha256(sibling + current).digest()
else:
# Current node is on the left, sibling is on the right
current = hashlib.sha256(current + sibling).digest()

return current.hex() == expected_root.lower()

オンチェーンチェックポイント同期検証

インデクサーのルートがコントラクトで検証された最新のルートと一致しない場合は、EVM RPC ノードにクエリを実行して、そのルートが履歴的に有効であるかどうかを確認します。以下は、EVM RPC ノード経由で rootHistory(bytes32) をクエリする Python、PHP、および JavaScript のコード例です。

import requests

def verify_root_on_contract(rpc_url, contract_address, smt_root):
# Selector for rootHistory(bytes32) is 66dd97ab
clean_root = smt_root.replace("0x", "").lower()
data = f"0x66dd97ab{clean_root.zfill(64)}"

payload = {
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": contract_address,
"data": data
},
"latest"
],
"id": 1
}

response = requests.post(rpc_url, json=payload).json()
if "error" in response:
raise Exception(f"EVM RPC Error: {response['error']['message']}")

result = response.get("result", "0x")
if not result or result == "0x":
return False

height = int(result.replace("0x", ""), 16)
return height > 0