Rand Protocol
문서
가이드

암호학

사용되는 기본 요소와 각각이 쓰이는 위치, 프로덕션에서 사용하는 STARK 및 FRI 매개변수, 그리고 개발자가 재현해야 할 수 있는 해시 구성 방식을 설명합니다.

이 페이지는 체인과 상호 운용할 때 적합한 라이브러리를 고르고, 파라미터를 노드가 강제하는 값과 대조하고, id나 커밋먼트를 직접 다시 계산하는 데 사용합니다. 여기에 나온 모든 값은 chain 20(fullnode v0.6.8)에서 코드가 실제로 사용하는 값입니다.

프리미티브와 사용처

프리미티브파라미터용도
Dilithium21,312바이트 공개 키, 2,420바이트 서명; 키 쌍은 32바이트 시드에서 도출검증인의 투표와 블록 제안; faucet 발행; Unbond, Withdraw 및 검증인의 Registration; AdmitValidator의 투표(chain 20); 집계자 액션; RPL 토큰의 Key 발행 권한(TokenMint, SetAuthority); 브리지의 양자 내성 guardian 공동 서명, 일시 정지 키, 그리고 chain 20에서는 교체 시 새 키의 소유 증명(아래 참조)
ML-KEM-7681,184바이트 캡슐화 키, 1,088바이트 암호문노트 엔벨롭의 트랜잭션별 키를 수신자의 주소로 봉인; 호출 입력 엔벨롭을 감사자에게 봉인; 증명 작업을 짝지어진 증명자에게 봉인
ChaCha20-Poly130532바이트 키, 앞에 붙는 무작위 12바이트 논스, 16바이트 태그모든 엔벨롭 구성 요소: 노트 본문, 래핑된 트랜잭션 키, 호출 입력 트랜스크립트; 짝지어진 증명자의 작업과 응답
BLAKE332바이트 출력, 항상 도메인 문자열을 앞에 붙임주소, 트랜잭션 id, 트랜잭션 바인딩과 호출 바인딩, 프로그램 id, 토큰 자산 id, 상태 루트와 그 Merkle 트리, p2p 아이덴티티, 서명 메시지, 브리지 자산 id, 브리지 입금의 블라인딩과 브리지 수수료 노트의 블라인딩
Goldilocks 위의 Poseidon2너비 8, 레이트 4, 용량 4, 패딩 없는 덮어쓰기 스펀지; 메시지 원소는 32비트 워드; 86개의 라운드 상수는 chain-15 컷 이후 노드 소스(poseidon2_constants.rs)에 리터럴 테이블로 들어 있으며, 그 값은 이전에 시드 기반 추출로 얻던 값과 같음증명 내부의 모든 것: 키, 노트 커밋먼트, 널리파이어, 커밋먼트 트리, 프로그램 다이제스트 hc, 입력 커밋먼트 H_IN과 H_PUB, 번들 다이제스트, 인가 커밋먼트
secp256k1 ECDSA + keccak256low-s 서명, Ethereum 방식의 20바이트 guardian 주소, mu = keccak256(keccak256(body))브리지 guardian 증명(attestation). 같은 키가 EVM 컨트랙트, Solana 프로그램, Rand에서 모두 동작함; Rand에서는 모든 증명에 아래의 Dilithium2 쿼럼도 필요
bech32m (BIP-350)사람이 읽을 수 있는 부분 rpl, 32바이트 페이로드, 데이터 문자 52자 + 체크섬 문자 6자 = 62RPL 토큰 자산 id의 텍스트 형식 rpl1…
Plonky3 batch STARKGoldilocks p = 2⁶⁴ − 2³² + 1, hiding FRI, 블로업 8, 폴딩 아리티 8, 쿼리 80회, 작업 증명 20비트모든 번들 증명, 인가 증명, 호출 증명; 번들 증명과 그 인가 증명은 해당 트랜잭션의 바인딩 워드 8개를 공개 입력 세그먼트로 담음

백서의 목표 파라미터는 일부 구현이 실제로 사용하는 값과 다릅니다(예: 백서의 384비트 트랜스크립트 해시와 zkVM의 Poseidon2 트랜스크립트). 이 페이지들은 코드를 기준으로 서술합니다.

브리지의 양자 내성 공동 서명

브리지의 guardian 증명은 secp256k1 ECDSA이며, 양자 공격자는 이를 위조할 수 있습니다. chain 14부터 모든 BridgeAttest(입금과 guardian 집합 교체 모두)는 같은 guardian들이 같은 다이제스트에 대해 생성한 Dilithium2 서명 쿼럼도 함께 담아야 합니다.

M = "rand-bridge-pq-cosign-1" || rand_chain_id (u64 BE) || mu        // 63 bytes, deterministic signing

여기서 mu = keccak256(keccak256(body))는 ECDSA 쿼럼이 서명하는 값입니다. M에 들어 있는 Rand 체인 id는 guardian 키가 재사용되더라도 testnet 공동 서명이 다른 Rand 체인에서 검증되지 않도록 합니다. M은 chain 20에서도 체인 id만 바인딩합니다. 이것은 binding_domain이 genesis 해시 뒤로 옮기지 못한 유일한 서명 메시지인데, 이를 서명하는 guardian 데몬이 다른 저장소에 있기 때문입니다. 같은 체인 id와 같은 guardian 집합을 가진 체인의 사본은 그 입금의 공동 서명을 받아들일 것입니다. guardian 집합 인덱스는 M에 없으므로 공동 서명은 ECDSA 집합 교체 이후에도 유효합니다. 액션의 pq_signatures 필드는 PqSignature { index: u8, signature }의 목록이며, 비용이 적게 드는 검사부터 비싼 검사 순으로 확인합니다. quorum(n) ≤ len ≤ n(PqNoQuorum), 인덱스의 엄격한 증가(PqIndexOrder), 모든 인덱스가 n 미만(PqIndexOutOfRange), 모든 서명이 정확히 2,420바이트(PqBadSignatureLength), 마지막으로 모든 서명이 pq_guardians[index]로 검증됨(PqBadSignature)입니다. PQ 서명자가 ECDSA 서명자와 같을 필요는 없으며, 각 쿼럼은 따로 집계합니다. 이 필드는 트랜잭션 바인딩 안에 있으므로 사본에서 제거하거나 바꿔치기할 수 없습니다.

PQ 집합은 genesis의 bridge.pq_guardians로, chain 20에서는 chain 1519와 마찬가지로 1,312바이트 키 8개이며 genesis ECDSA 집합(guardian 집합 1)과 인덱스가 정렬되어 있습니다(chain 14는 6개였고 집합 0과 정렬). ECDSA guardian 집합 교체는 PQ 집합을 바꾸지 않습니다. chain 14에서는 체인 수명 동안 고정이었으나, chain 15부터 genesis에 브리지의 rules_v2 그룹이 들어 있고, 이에 따라 PQ 쿼럼이 PQ 집합 전체(RotatePqGuardians) 또는 일시 정지 키(RotatePauseKey)를 각각 브리지의 rotation_nonce 아래에서 교체할 수 있습니다. chain 20의 genesis는 bridge.rotation을 추가합니다. 교체는 V2 액션이어야 하며 같은 메시지에 대한 각 새 키 자신의 Dilithium2 서명(소유 증명)을 담아야 하고, 현재 일시 정지 키가 취소하지 않는 한 반영된 지 하루 뒤에 효력이 발생합니다(브리지). rand_getBridgeState는 키를 제공하고, 디코딩된 bridge_attest는 서명한 인덱스인 pq_signers를 나열합니다. 같은 PQ 쿼럼이 브리지의 거버넌스 메시지도 승인하며, 각 메시지는 체인 id와 논스를 담은 고정 빅엔디언 레이아웃입니다. chain 20(genesis binding_domain: 1)에서는 각 도메인의 버전 숫자가 2이고 32바이트 genesis 해시가 도메인과 체인 id 사이에 들어가며, chain 1419는 -1 형식을 사용합니다.

메시지도메인(chain 14–19 / chain 20)서명자
M_pauserand-bridge-pause-1 / -2genesis의 단일 일시 정지 키(Dilithium2). 일시 정지만 가능하고 해제는 불가능
M_unpauserand-bridge-pq-unpause-1 / -2PQ guardian 쿼럼
M_listrand-bridge-pq-list-1 / -2PQ guardian 쿼럼(ListBacking)
M_registerrand-bridge-pq-register-1 / -2PQ guardian 쿼럼(RegisterBridgedToken)
M_rotate_pqrand-bridge-pq-rotate-pq-1 / -2현재 PQ 집합의 쿼럼(RotatePqGuardians, rules_v2 체인); chain 20에서는 각 새 키도 소유 증명으로서 서명
M_rotate_pauserand-bridge-pq-rotate-pause-1 / -2현재 PQ 집합의 쿼럼(RotatePauseKey, rules_v2 체인); chain 20에서는 새 키도 서명
M_cancelrand-bridge-cancel-rotation-1 / -2, 끝에 kind 바이트가 붙음현재 일시 정지 키(CancelRotation, bridge.rotation이 있는 체인: chain 20)

운영 환경의 STARK

zkVM은 constraint set 8입니다. 필수 테이블 아홉 개(program, cpu, memory, alu, range, nibble, poseidon2, input, public)와, 게스트가 해당 syscall을 호출했을 때만 증명에 포함되는 keccak 및 sha256 테이블이 열일곱 개의 버스로 연결되어 하나의 batch STARK로 증명됩니다. constraint set 7부터 선언된 모든 테이블은 최소 2⁷행을 가지며, 모든 테이블의 LogUp 종단값은 열일곱 번째 버스인 BLIND를 통해 블라인딩됩니다. 증명의 공개 인터페이스는 필드 원소 35개(pv::NUM)입니다. 진입 pc, 티어, 출력 워드 8개, 프로그램 다이제스트 hc(워드 8개), 솔트가 적용된 비공개 입력 커밋먼트 H_IN(8개), 솔트가 없는 공개 세그먼트 다이제스트 H_PUB(8개), 그리고 constraint set 8부터 선언된 가스 한도 GAS_LIMIT입니다.

파라미터운영 값비고
FRI 쿼리80constraint set 3과 4의 27쿼리 조정은 2026-09-12 감사 이후 되돌렸음: 증명된 보안이 약 42비트로 떨어졌기 때문
블로업8 (log_blowup = 3)모든 테이블의 최대 제약 차수가 상한 8 아래로 고정됨
폴딩 아리티8
작업 증명 비트20
건전성3·80 + 20 = 260비트 추정(ethSTARK); proximity gaps 아래에서 증명된 값은 약 86비트
영지식통계적: LDE와 FRI 배치 다항식이 무작위화되므로 같은 실행의 두 증명이 서로 다름constraint set 7부터 선언된 모든 테이블이 최소 2⁷행으로, 증명이 여는 82개 지점보다 많고 LogUp 종단값은 블라인딩됨
티어10, 12, 14, 16, 18, 20증명은 티어를 공개하되 사이클 수는 공개하지 않음; fullnode v0.5.6부터 티어 14를 초과하는 호출 증명은 거부되고(CallTierTooHigh), 번들 증명은 티어 14로, 인가 증명은 티어 10으로 고정됨
증명 상한genesis의 max_proof_bytes: chain 1720에서 4 MiB(4,194,304); chain 1316에서 8 MiB; chain 12처럼 이 값이 없는 genesis에서는 2 MiB(MAX_PROOF_BYTES)2 MiB는 배포된 게스트가 만들 수 있는 해시 테이블 없는 모든 증명보다 크고 keccak을 담은 증명보다 작음; 4 MiB는 둘 다 허용
가스cpu 행당 1; Poseidon2 absorb 행당 3; SHA256 행당 64; KECCAK 행당 192cpu 테이블의 GAS 열에 누적되며 최대 GAS_LIMIT까지 증명됨; 검증자는 gas_max(t, k, s) = (2ᵗ − 1) + 2ᵗ⁻² + 191·(2ᵏ/32) + 63·(2ˢ/64)를 넘는 한도를 거부하며, 이 값은 해시 없는 티어 10 헤더에서 1,279, 티어 14 헤더에서 20,479

티어 10에서 keccak이 없는 프로덕션 증명은 1,298,729바이트, 티어 12에서는 1,359,978바이트였으며, 제약 집합 6(Apple Silicon, 릴리스 빌드)에서 측정한 크기입니다. keccak을 포함한 티어 10 증명은 3,198,430바이트로, 기본값인 2 MiB를 넘고 체인 1315의 8 MiB에는 못 미칩니다. 폐기된 2-in-2-out 번들 guest의 티어 14 증명은 체인 8에서 1,321,773바이트, 체인 13에서 1,418,4061,420,423바이트로 측정되었습니다. 체인 14의 4-in-4-out 숨김 자산 번들 guest는 해시 테이블 없이 티어 14를 유지하며, 그 증명은 체인 14에서 1,422,116바이트와 1,423,170바이트로 측정되었습니다(2026-09-20). 체인 15는 같은 guest를 고정했습니다(hc_bundle 변경 없음). 번들 증명은 그곳에서 public_log_height를 4로 선언했으며, 이는 8개 바인딩 워드의 높이입니다. 노드는 검증 키를 만들기 전에 다른 값을 모두 거부했습니다. 2026-09-19에 체인 13에서 만든, keccak을 포함한 ERC-20 approve 호출 증명(티어 16)은 3,412,405바이트입니다. fullnode v0.5.6 이후의 모든 체인은 티어 16의 해당 호출을 거부합니다.

제약 집합 7의 블라인딩 열과 테이블 하한은 해시가 없는 증명에 약 5%를 더합니다. fullnode가 2026-09-28에 측정한 결과, fib는 티어 10에서 1,367,688바이트, 티어 12에서 1,424,299바이트이고, keccak을 포함한 티어 10 증명은 3,283,898바이트, 티어 14 숨김 자산 번들 증명은 1,498,821바이트(guest v1)와 1,497,156바이트(guest v2)입니다. 번들 증명은 그 이후 public_log_height를 7로 선언합니다. 제약 집합 8은 1% 미만을 더합니다. 2026-09-30에 체인 18에서 측정한 결과(Apple Silicon)는 다음과 같습니다. 인증 증명은 1,364,9401,375,371바이트(티어 10), 번들 증명은 1,494,1511,504,260바이트(티어 14, guest v3), 호출 증명은 해시 테이블 없는 티어 14에서 1,498,589바이트, SHA-256 테이블을 쓰는 티어 14에서 1,911,152바이트, Keccak 테이블을 쓰는 티어 12에서 3,346,865바이트입니다. 모두 체인 18~20의 4 MiB 상한 안에 들어갑니다.

검증에는 검증 키가 준비된 상태에서 약 16 ms, (tier, heights) 키를 처음 만들 때 약 230 ms가 걸립니다. test FRI 프로파일(쿼리 16개)은 테스트 스위트용이며 안전하지 않습니다. 체인 20의 제네시스는 production을 고정합니다. fullnode v0.6.8은 제약을 하나도 바꾸지 않습니다. 체인 20은 체인 17~19와 같은 hc_bundle과 hc_auth를 고정합니다.

재현할 수 있는 해시 구성

도메인을 사용하는 BLAKE3: blake3(domain || data). 도메인 문자열 뒤에 구분자는 없습니다.

바인딩 도메인. 체인 20의 제네시스는 binding_domain: 1을 설정합니다(fullnode v0.6.8, audit v6 BIND-1). 이런 체인에서는 체인 id만 바인딩하던 모든 증명 바인딩과 서명된 모든 액션 메시지가 이제 제네시스 해시도 함께 바인딩합니다. 도메인의 버전 번호가 하나 올라가고, 32바이트 제네시스 해시가 원상(preimage)에서 체인 id보다 앞에 놓입니다. 그러면 한 체인을 위해 만든 증명이나 서명은, 재컷(re-cut)처럼 체인 id와 키를 재사용하는 체인을 포함해 다른 어떤 체인에서도 검증되지 않습니다. 바인딩 워드는 증명의 공개 입력이므로 guest와 검증 키는 바뀌지 않았습니다. 표에 두 형태를 모두 실었으며, 체인 14~19는 첫 번째 형태를 바이트 단위로 그대로 사용합니다. 이전부터 이미 제네시스에 바인딩되어 있어 바뀌지 않은 것은 투표와 제안(consensus_domain: 1 이후), v2 Registration, AdmitValidator 투표입니다. 옮기지 않은 것은 브리지의 mint 공동 서명(위)입니다. 체인 20에서 전송하려면 지갑이 v0.6.8이어야 하며, 지갑은 노드가 주장하는 값이 아니라 체인 id로 형태를 결정합니다. rand_getLimits.binding_domain이 이를 보고합니다.

값구성
투명 주소blake3("rand-address" || dilithium2_public_key), base58
트랜잭션 idblake3("rand-txid-3" || bincode(view)). 여기서 view는 번들의 증명 바이트를 blake3(proof)로, 인증 증명을 blake3(auth_proof)로 대체한 트랜잭션이며, auth_commit은 그대로 들어갑니다. 체인 16까지는 도메인이 rand-txid-2였고 인증 필드가 없었습니다
트랜잭션 바인딩체인 14~19에서는 blake3("rand-tx-bind-1" || bincode(chain_id, bundle', action')), 체인 20에서는 blake3("rand-tx-bind-2" || bincode(genesis_hash, chain_id, bundle', action')). 리틀 엔디언 u32 워드 8개이며, '는 bundle.proof, bundle.auth_proof, 그리고 Aggregate의 proof를 빈 벡터로 대체한 것을 뜻합니다. bincode는 고정 폭 리틀 엔디언 정수를 사용합니다. 모든 번들 증명과 인증 증명은 이 워드들에 대해 만들어지고 검증됩니다
호출 바인딩blake3("rand-call-bind-1" || …), 체인 20에서는 제네시스 해시를 앞에 둔 rand-call-bind-2: 트랜잭션 바인딩의 구성에서 Call(또는 Invoke) 자체의 proof까지 비운 것입니다. 체인 20과 같은 hardening_v6 제네시스에서 호출 증명의 공개 세그먼트는 프로그램의 배포 시점 공개 워드 뒤에 이 8개 워드가 이어지는 형태이며, Invoke의 경우 그 뒤에 전이(transition)가 컨텍스트 워드로 추가됩니다
프로그램 idblake3("rand-program" || base_pc as 4 LE bytes || words as 4 LE bytes each)
p2p 신원blake3("rand-p2p-identity" || seed)에서 만든 ed25519 키
브리지 자산 id(백킹별)blake3("rand-bridge-asset" || token_chain as 2 BE bytes || token_address (32 bytes)) — rand_bridgeAssetId가 계산하고 rand_getAssets가 백킹 행마다 출력합니다. 이는 토큰이 아니라 와이어 상의 원본 코인을 식별합니다
RPL 토큰 자산 id, 네이티브blake3("rand-rpl-asset" || bincode(name, symbol, decimals, authority, initial: Option<InitialMint>, salt)), salt는 생성자가 고른 32바이트이며, 16진수와 rpl1… 형태로 표시됩니다
RPL 토큰 자산 id, 브리지blake3("rand-rpl-asset" || bincode(name, symbol, BRIDGE_DECIMALS, salt)) — 브리지된 토큰 하나가 여러 백킹에 걸치므로 (chain, token) 쌍에 대한 해시가 아닙니다
브리지 입금 블라인딩r = blake3("rand-deposit-r-1" || mu), BridgeAttest에 대해 승인(admission)이 받아들이는 유일한 r입니다(그 외에는 WrongDepositBlinding)
브리지 수수료 노트 블라인딩(체인 20)입금의 수수료 노트: r = blake3("rand-bridge-fee-r-1" || mu), 소각의 수수료 노트: r = blake3("rand-bridge-burn-fee-r-1" || txid). 둘 다 리틀 엔디언 워드 8개로 읽습니다. 이 노트에는 봉투(envelope)가 없으며 모든 필드가 공개이고, 소유자는 제네시스의 bridge.fees.recipient입니다
브리지 수신자전체 차폐 주소에 대한 blake3("rand-shielded-recipient" || pk_bytes || kem_ek)
파우셋 Mint 메시지blake3("rand-mint-2" || bincode(chain_id, cm, pk, time, r, envelope, amount)), 체인 20에서는 blake3("rand-mint-3" || bincode(genesis_hash, chain_id, cm, pk, time, r, envelope, amount))
TokenMint, SetAuthority 메시지blake3("rand-rpl-mint-1" or "rand-rpl-authority-1", chain_id || asset_id || nonce || body). mint의 body에는 blake3(bincode(envelope))가 들어갑니다. 체인 20에서는 rand-rpl-mint-2와 rand-rpl-authority-2이며 제네시스 해시가 앞에 옵니다
Registration 메시지체인 20처럼 staking.registration_v2 또는 binding_domain: 1이 설정된 제네시스에서는 blake3("rand-register-2" || bincode(genesis_hash, chain_id, validator, payout))(v1 등록은 거기서 거부됩니다), 그 외에는 blake3("rand-register" || bincode(chain_id, payout))
AdmitValidator 투표(체인 20)blake3("rand-admit-validator-1" || genesis_hash || candidate_address), 투표하는 각 밸리데이터가 서명합니다
Unbond 메시지blake3("rand-unbond" || bincode(chain_id, validator, amount, nonce)), 체인 20에서는 blake3("rand-unbond-2" || bincode(genesis_hash, chain_id, validator, amount, nonce))
Withdraw 메시지blake3("rand-withdraw" || bincode(chain_id, validator, amount, nonce, time, r, envelope)), 체인 20에서는 rand-withdraw-2이며 제네시스 해시가 앞에 옵니다
Merkle 노드(상태 트리)blake3("rand-merkle-node" || left || right)
토큰 레지스트리 리프blake3("rand-token-leaf-1" || bincode(TokenInfo)), 인덱스 순서이며 tokens_root 아래에 있습니다
상태 루트체인 20에서는 inner = blake3("rand-state-8" || tree_root || nullifier_root || validators_root || programs_root || bridge_root || tokens_root || faucet_epoch || faucet_minted_in_epoch || bond_queue_root || gas_price || byte_price || program_state_root)를 감싼 blake3("rand-state-admitted-1" || inner || admitted_root)입니다. 여기서 program_state_root = blake3("rand-program-state-1" || cells_root || vaults_root)(RPL-2)이고, 파우셋 카운터 둘과 실시간 가격 둘은 각각 8바이트 빅 엔디언이며, 래퍼는 승인된 집합(staking.admission_by_vote)을 커밋합니다. 체인 19의 것은 byte_price까지 같은 필드에 대한 blake3("rand-state-7" || …)였습니다(제네시스 staking 섹션은 체인 15~17처럼 rand-state-5 아래에서 tokens_root 뒤에 셋을 덧붙이고, 제네시스 gas.dynamic 섹션은 두 가격을 덧붙이며 도메인을 rand-state-7로 옮깁니다). 체인 14에서는 처음 여섯 필드에 대한 rand-state-4, bridge, tokens, aggregation 섹션이 없는 체인에서는 처음 네 필드에 대한 rand-state-2였습니다(합의)

도메인 태그를 사용하는 Poseidon2: H(domain, msg) = sponge_hash([domain, msg...]). 태그가 가장 먼저 흡수되는 워드이고, 각 워드는 Goldilocks 원소이며, 4원소 다이제스트는 8개의 u32 워드로 나뉩니다(각 원소의 하위 절반, 그다음 상위 절반). 도메인 태그:

태그값구성
NK1조회 키(viewing key) nk = H(1, sk)
PK2노트 공개값 pk = H(2, nk)
NF3널리파이어 H(3, nk || cm)
CM4노트 커밋먼트 H(4, pk(8) || from(8) || amount_lo || amount_hi || asset || time || r(8)) — 28 워드
OVK, KEM_SEED5, 6발신 조회 키와 ML-KEM 시드이며, 카운터 모드 와이드 해시 [domain, nk, counter]를 거쳐 생성됩니다
NODE7트리 노드 H(7, left || right)이며, 빈 리프는 모두 0입니다
HC8프로그램 다이제스트입니다. 태그, base_pc, len은 첫 번째 순열의 capacity 레인에 들어가고, 이후 워드는 블록당 네 개씩 흡수됩니다
OUT9전송 게스트의 출력 다이제스트
IN10H_IN: capacity 헤더 [10, n_in, 0], 이어서 4 워드 솔트, 그다음 입력
BUNDLE11폐기된 2-in-2-out 번들의 다이제스트이며 47개의 공개 워드를 대상으로 합니다. 현재 이 게스트를 고정하는 체인은 없습니다
hidden bundle64체인 1416에서 숨김 자산 번들의 다이제스트이며 81 워드를 대상으로 합니다. 앵커, 널리파이어 4개, 커밋먼트 4개, fee, burn_a, burn_r(각 두 워드), burn_asset, time, 그리고 마지막에 taint 워드가 옵니다. 체인 1720(번들 게스트 v3)에서는 89 워드이며, 인가 커밋먼트 c의 여덟 워드가 taint 워드 바로 앞에 놓입니다. 비공개 자산 A는 여기에 포함되지 않습니다. 이 태그는 노드 로컬이며, 벤더링된 태그 1~15와 충돌하지 않도록 떨어져 있습니다
AUTH65인가 커밋먼트 c = H(65, nk || salt)이며 16 워드이고, 번들마다 새로운 256비트 솔트를 사용합니다. 번들 증명이 자신의 다이제스트 안에서, 인가 증명이 여덟 개의 출력 워드로서 공개하며, 번들에 auth_commit으로 실려 전달됩니다(체인 17~20). 64와 마찬가지로 노드 로컬입니다
PUB15H_PUB: 헤더 [15, n_pub, 0], 솔트 없음. 프로그램의 경우 체인 20에서 워드가 배포 시점에 고정되며(최대 32,768개), 모든 호출의 세그먼트는 이 워드들에 호출 바인딩의 여덟 워드가 뒤따르는 형태이고, 호출은 그 세그먼트의 다이제스트에 대해 검사됩니다. 번들 증명과 인가 증명의 경우 세그먼트는 트랜잭션의 여덟 바인딩 워드입니다. max_program_public_words가 없는 제네시스는 빈 세그먼트만 허용합니다

hc, H_IN, H_PUB는 단순히 메시지 앞에 접두사를 붙이는 스펀지가 아닙니다. 헤더가 capacity에 들어가므로 cpu 테이블의 다이제스트 행은 순열당 정확히 네 워드를 흡수합니다. 직접 계산하지 말고 벤더링된 크레이트(randprotocol_zkvm::hash::{input_digest, public_digest}, isa::Program::digest)로 재현하십시오.

일반 스펀지는 패딩을 하지 않으므로 첫 블록 안에서는 [a]와 [a, 0]이 같은 해시를 갖습니다. 위의 모든 구성은 고정 길이 메시지를 각자의 태그 아래에서 해시합니다. 길이가 달라질 수 있는 데이터를 위해 제약 집합 7에서 길이 바인딩 스펀지(hash::sponge_hash_len, POSEIDON2_LEN 시스콜)가 추가되었습니다. 이 스펀지는 상태 [0, 0, 0, 0, n, 0, 0, 0]에서 시작하며(n은 워드 수), 최소 한 번은 순열을 수행합니다. 같은 워드에 대한 별개의 해시이며, 체인의 어떤 노트, 널리파이어, 루트, 다이제스트도 이를 사용하지 않습니다.

기억해 둘 두 가지 성질이 있습니다. hc는 바인딩이지만 은닉은 아닙니다(솔트가 없으므로 추측한 프로그램을 확인할 수 있고, 같은 프로그램의 두 배포는 서로 연결될 수 있습니다). 반면 H_IN은 바인딩일 뿐 아니라 은닉이기도 하므로(증명마다 새로운 128비트 솔트), 솔트 보유자가 열어 보이기 전까지는 H_IN을 공개해도 입력에 관해 아무것도 드러나지 않습니다.

키 파생

키출처
Dilithium2 키 쌍(노드)32바이트 시드로부터 결정적으로 생성
libp2p ed25519(노드)blake3("rand-p2p-identity" || seed)
조회 키, pk, ovk, ML-KEM 키 쌍(지갑)위 표에 정리한 대로 지출 키에서 Poseidon2로 파생하며, ML-KEM 쌍은 MlKem768::from_seed(kem_seed)입니다

논문 페이지의 논문들에 보안 논증이 실려 있습니다. 양자 내성 선택, FRI 건전성 계산과 쿼리를 80개로 유지하는 이유, 그리고 트레이스 길이 한계를 다룹니다.

fullnode 커밋 c0878c3f(chain 21) 기준으로 2026-10-12에 마지막으로 검증되었습니다. 코드와 이 페이지의 내용이 다를 경우 코드가 옳습니다. 알려 주시기 바랍니다.