본문으로 건너뛰기

증거 확인

본인 증명 확인하기

교정은 표준 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 주소, 소유자 공개 키, 가격, nonce, SMT 루트 및 SMT(Sparse Merkle Tree)의 경로를 나타내는 128개의 형제 해시를 포함한 도메인 세부 정보를 반환합니다.

  2. 로컬 SMT 증명 검증: 인덱서가 가짜 해결 방법을 반환하는 것을 방지하기 위해 클라이언트는 로컬에서 Merkle 멤버십 증명의 유효성을 검사합니다. 리프 데이터는 다음을 연결하여 구성됩니다. domain_name(UTF-8바이트) + owner_pubkey(16진수에서 32바이트) + target_address(UTF-8바이트) + price(u64 리틀엔디안) + nonce(u64 리틀엔디안). 우리는 이 리프 데이터의 SHA-256 해시를 계산하고 형제 해시를 사용하여 최대 128 레벨까지 SMT를 탐색합니다. 계산된 루트가 인덱서의 smt_root과 일치하면 증명은 암호화적으로 건전합니다.

  3. 최신 루트 동기화 검증: 인덱서의 루트가 블록체인과 동기화되어 있는지 확인하기 위해 currentRoot() 함수(선택기 0xfdab463d)를 사용하여 EVM(Arbitrum) 계약에서 온체인으로 검증된 최신 SMT 루트를 쿼리합니다. 인덱서의 smt_root과 일치하면 인덱서가 완전히 동기화된 것입니다.

  4. 기록 루트 검증(EVM RPC 폴백): 인덱서의 루트가 최신 계약 루트와 일치하지 않는 경우(동기화 지연으로 인해 발생할 수 있음) 계약의 매핑 rootHistory(bytes32)(선택기 0x66dd97ab)을 쿼리하여 인덱서의 루트가 역사적으로 유효한지 확인합니다.

    • 매핑이 0이 아닌 값을 반환하는 경우: 루트는 계약에서 역사적으로 확인되었습니다. 클라이언트는 임시 인덱서 지연에 대한 경고를 받지만 안전하게 진행할 수 있습니다.
    • 매핑이 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