Chuyển tới nội dung chính

Xác minh bằng chứng

Tự mình xác minh bằng chứng

Bằng chứng là bằng chứng nén SP1 tiêu chuẩn. Xác minh chúng bằng SDK SP1:

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)?;

Khóa xác minh có tính xác định, bắt nguồn từ mã nhị phân của chương trình khách. Bất cứ ai cũng có thể sao chép nó.
Tính bất biến của chương trình khách ZkEVM SP1 được chứng minh bằng Khóa chương trình. Mã nguồn chứng minh có sẵn trên GitHub. Bất cứ ai cũng có thể biên dịch nó và so sánh các Khóa chương trình. Khóa chương trình sẽ được thay đổi nếu có bất kỳ thay đổi nào được thực hiện trong chương trình khách SP1.

Kiểm tra bằng chứng phân giải tên

Khi máy khách phân giải tên miền ZCash, quy trình này được thực thi theo bốn giai đoạn logic để đảm bảo tính bảo mật tuyệt đối, tính hợp lệ đồng bộ hóa và tính toàn vẹn trạng thái mà không cần tin cậy vào nút chỉ mục:

  1. Truy vấn phân giải tên miền: Máy khách đưa ra yêu cầu tới điểm cuối của Trình lập chỉ mục độ phân giải ZcashNames (ví dụ: GET /v1.0/resolve/richard.zcash). Trình lập chỉ mục trả về các chi tiết tên miền bao gồm địa chỉ ZCash đích, khóa chung của chủ sở hữu, giá, số không, gốc SMT và 128 giá trị băm anh em đại diện cho đường dẫn trong Cây Merkle thưa thớt (SMT).

  2. Xác minh bằng chứng SMT cục bộ: Để ngăn người lập chỉ mục trả về độ phân giải giả, khách hàng sẽ xác thực bằng chứng thành viên Merkle cục bộ. Dữ liệu lá được xây dựng bằng cách nối: domain_name (UTF-8 byte) + owner_pubkey (32 byte từ hệ thập lục phân) + target_address (UTF-8 byte) + price (u64 little-endian) + nonce (u64 little-endian). Chúng tôi tính toán hàm băm SHA-256 của dữ liệu lá này và duyệt SMT lên tới 128 cấp bằng cách sử dụng các hàm băm anh em. Nếu gốc được tính khớp với smt_root của người lập chỉ mục thì bằng chứng là hợp lý về mặt mật mã.

  3. Xác thực đồng bộ hóa gốc mới nhất: Để kiểm tra xem gốc của người lập chỉ mục có đồng bộ hóa với chuỗi khối hay không, chúng tôi truy vấn gốc SMT được xác thực mới nhất trên chuỗi từ hợp đồng EVM (Arbitrum) bằng cách sử dụng hàm currentRoot() (bộ chọn 0xfdab463d). Nếu nó khớp với smt_root của người lập chỉ mục thì người lập chỉ mục đã được đồng bộ hóa hoàn toàn.

  4. Xác thực gốc lịch sử (dự phòng EVM RPC): Nếu gốc của trình lập chỉ mục không khớp với gốc hợp đồng mới nhất (có thể xảy ra do độ trễ đồng bộ hóa), chúng tôi sẽ truy vấn ánh xạ của hợp đồng rootHistory(bytes32) (bộ chọn 0x66dd97ab) để xác minh xem gốc của trình lập chỉ mục có hợp lệ về mặt lịch sử hay không:

    • Nếu ánh xạ trả về giá trị khác 0: Gốc đã được xác minh lịch sử trên hợp đồng. Khách hàng được cảnh báo về độ trễ của bộ chỉ mục tạm thời nhưng có thể tiếp tục một cách an toàn.
    • Nếu ánh xạ trả về 0: Root chưa bao giờ được xác nhận hoặc xác thực trên blockchain. Độ phân giải bị chặn ngay lập tức vì lý do bảo mật.

Ví dụ về mã chứng minh SMT cục bộ

Dưới đây là các ví dụ bằng Python, PHP và JavaScript cho biết cách xác minh bằng chứng SMT về tên đã được phân giải bằng cách sử dụng bố cục hàm băm lá đầy đủ:

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()

Xác minh đồng bộ hóa điểm kiểm tra trên chuỗi

Nếu gốc của người lập chỉ mục không khớp với gốc mới nhất được xác thực trên hợp đồng, chúng tôi sẽ kiểm tra xem nó có hợp lệ về mặt lịch sử hay không bằng cách truy vấn nút EVM RPC. Dưới đây là các ví dụ về mã trong truy vấn Python, PHP và JavaScript rootHistory(bytes32) thông qua nút EVM RPC:

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