验证证据
自己验证证明
校样是标准 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 访客程序的不变性由 Program Key 证明。证明者源代码可在 GitHub 上找到。任何人都可以编译它并比较程序密钥。如果在 SP1 访客程序中进行任何更改,则程序密钥将会更改。
检查姓名证明
当您解析名称 时,API 会在 merkle_proof 字段内返回由 128 个同级哈希值组成的成员资格证明。您可以使用这些兄弟哈希在本地验证域名和目标 shielded 地址之间的映射。
以下是 Python、PHP 和 JavaScript 中的示例,展示了如何验证已解析名称的稀疏 Merkle 树 (SMT) 证明:
- Python
- PHP
- JavaScript
import hashlib
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, 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 target address
current = hashlib.sha256(target_address.encode('utf-8')).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()
<?php
function verifySmtProof($domainName, $targetAddress, $merkleProof, $expectedRoot) {
// 1. Compute key as SHA-256 of lowercase domain name
$keyHash = hash('sha256', strtolower($domainName), true);
// Take first 16 bytes (128 bits) for a depth-128 SMT
$key = substr($keyHash, 0, 16);
// 2. Compute leaf hash as SHA-256 of target address
$current = hash('sha256', $targetAddress, true);
// 3. Hash up the tree using the 128 sibling hashes
for ($i = 0; $i < 128; $i++) {
$sibling = hex2bin($merkleProof[$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)
$bitIdx = 127 - $i;
$bytePos = intdiv($bitIdx, 8);
$bitPos = 7 - ($bitIdx % 8);
$bit = (ord($key[$bytePos]) >> $bitPos) & 1;
if ($bit === 1) {
// Current node is on the right, sibling is on the left
$current = hash('sha256', $sibling . $current, true);
} else {
// Current node is on the left, sibling is on the right
$current = hash('sha256', $current . $sibling, true);
}
}
return bin2hex($current) === strtolower($expectedRoot);
}
const crypto = require('crypto');
function verifySmtProof(domainName, targetAddress, merkleProof, expectedRoot) {
// 1. Compute key as SHA-256 of lowercase domain name
const keyHash = crypto.createHash('sha256').update(domainName.toLowerCase()).digest();
// Take first 16 bytes (128 bits) for a depth-128 SMT
const key = keyHash.subarray(0, 16);
// 2. Compute leaf hash as SHA-256 of target address
let current = crypto.createHash('sha256').update(targetAddress).digest();
// Helper to get bit at index (0-127) from MSB of 16-byte key
const getBit = (bytes, bitIdx) => {
const bytePos = Math.floor(bitIdx / 8);
const bitPos = 7 - (bitIdx % 8);
return (bytes[bytePos] >> bitPos) & 1;
};
// 3. Hash up the tree using the 128 sibling hashes
for (let i = 0; i < 128; i++) {
const sibling = Buffer.from(merkleProof[i], 'hex');
const bitIdx = 127 - i;
const bit = getBit(key, bitIdx);
const hasher = crypto.createHash('sha256');
if (bit === 1) {
// Current node is on the right, sibling is on the left
hasher.update(Buffer.concat([sibling, current]));
} else {
// Current node is on the left, sibling is on the right
hasher.update(Buffer.concat([current, sibling]));
}
current = hasher.digest();
}
return current.toString('hex') === expectedRoot.toLowerCase();
}