Rand Protocol
Documentation
Start

Introduction

What Rand Protocol is, what runs on the public testnet today, and how to get RAND to build against it.

Read this page to decide what to build against and where to start: the chain’s model in a few paragraphs, the live testnet’s parameters, how to get test RAND, and a map of the rest of the documentation.

What Rand Protocol is

Rand is a post-quantum shielded chain. Its native coin is RAND, and RAND lives in a fully shielded pool: there are no accounts and no balances on chain, only note commitments and nullifiers, and a transfer is a zero-knowledge proof that four notes became four other notes (dummies fill the unused slots), without showing which asset moved. RAND and every token of the chain’s own standard, RPL, share that one pool. The same coin pays for confidential programs: RISC-V programs that run off chain inside a zero-knowledge virtual machine and settle on chain with a proof instead of their inputs.

Every primitive is chosen to hold against a quantum adversary:

layerwhat runs
SignaturesDilithium2 (lattice-based). Validators sign blocks and votes with it; the faucet, the staking actions and the bridge registrations are signed with it. A wallet never signs a transaction: a bundle authorises itself by its proof.
Note encryptionML-KEM-768 key encapsulation plus ChaCha20-Poly1305. Every note on chain is accompanied by an envelope only its owner (and its sender) can open.
HashingBLAKE3 with domain separation for addresses, transaction ids, the state root and everything else outside the proof system; Poseidon2 over the Goldilocks field for notes, nullifiers, the commitment tree and everything inside a proof.
ProofsA Plonky3 batch STARK with hiding FRI (80 queries, blowup 8, 20 proof-of-work bits). Transparent: no trusted setup, no pairing curve, and the assumption is a collision-resistant hash.
Confidential computationThe Rand zkVM, an RV32IM machine proved under that STARK. A program is identified by an in-circuit digest, and the verifier never sees a single instruction word.
ConsensusChained HotStuff BFT: stake-weighted quorums of more than two thirds, round-robin leaders, a three-consecutive-view commit rule.
Storage and networkingOne RocksDB per node with fsynced commits and a startup integrity check; libp2p (TCP, Noise, Yamux, gossipsub, Kademlia, mDNS on LANs).

The reference implementation is randprotocol/fullnode, in Rust: the rand-node binary is the node, the rand binary is the wallet, and the JSON-RPC methods are prefixed rand_. The explorer is randscan.org.

The testnet: chain 21

The public fleet runs chain 21, live since 2026-10-12 10:31 UTC on fullnode v0.8.0. Chains 15 to 20 are retired. Five chains were cut in a fortnight, each for a change that alters every proof or the transaction format:

  • Chain 16 (2026-09-28, fullnode v0.6.1) moved the zkVM to constraint set 7, which blinds what a proof used to reveal about small private inputs, and switched on the hardening_v6 rules.
  • Chain 17 (2026-09-29, v0.6.3) split a transfer’s authorisation from its proof: every bundle carries a second, small proof made with the spend key, so the large one can be made by a machine that holds only a viewing key.
  • Chain 18 (2026-09-29, v0.6.7) meters confidential calls in gas (constraint set 8) and turns on the encrypted memo in every note envelope.
  • Chain 20 (2026-10-01, v0.6.8) binds every proof and every signed message to the genesis hash, adds program state (RPL-2), takes a fee on zUSD bridge mints and burns, and switches on the audit-v6 rules.
  • Chain 21 (2026-10-12, v0.8.0) moves the zkVM to constraint set 9 (Merkle spans in the recursion verifier and a chip for Dilithium2 arithmetic), which changes every verifier key and the proof encoding; burns every transaction’s fee floor instead of paying it to the proposer; adds RPL-3 perpetual futures, M-of-N multisig accounts and a second, private multisig authorisation; and raises the proof cap to 6 MiB. Its rules are the table below.

Chain 19 (2026-10-01 03:43 UTC, v0.6.7) was a re-genesis of chain 18 on the same build and changed no rule. Chain 18 was stopped at height 143,776, and chain 19 was cut from a snapshot at height 141,935. Its genesis differed from chain 18’s only in the chain id, the timestamp, the carried notes and the bridge section: new emitters for the Ethereum, Binance Smart Chain and Tron endpoints, and the sequence counters carried over.

Chain 20 was a hard fork of chain 19 (cut from its state at height 7,258 on 2026-10-01), and chain 21 is a hard fork of chain 20: its genesis carries the bridge state from chain 20’s snapshot at height 814,702 and the balances of the operator’s wallets, and all 26 validators were restarted on chain 21 together on 2026-10-12 at 10:31 UTC, with the same keys, peer ids and bootstrap nodes. A wallet needs v0.8.0 to send on chain 21: constraint set 9 changed every verifier key and the proof encoding, so an older wallet’s proofs do not even decode, and the genesis binding refuses anything proved or signed for another chain.

Each is a fresh chain. RAND balances in the operator’s wallets and the zUSD in circulation were carried into the next genesis, and nothing else was: a program deployed on one chain does not exist on the next, and the eleven tokens registered on chain 20 were not carried. Chain 21 also issued 100,000 RAND to the foundation treasury, a multisig account behind 2 of 3 keys. It is experimental software: not audited, and RAND on it has no value.

Programs on chain 21 keep state as they did on chain 20: RPL-2’s program cells, program vaults and the Invoke action are live, and chain 21 adds RPL-3 perpetual futures and multisig accounts. The four example programs were deployed on chain 20 and have not been redeployed on chain 21 yet.

chain id21 (rand_chainId)
genesis hashca76c2766ed6090ac6ba5dad86b724dd5d2b80c0edfaed287cd8b129e663ca9a
genesis filedeploy/genesis-chain21.json in the fullnode repository
buildfullnode v0.8.0 (tag c0878c3f); a node reports its own build in rand_getVersion. This build refuses chains 18 to 20, and a wallet older than v0.8.0 cannot send on chain 21
genesis bindingbinding_domain 1: every bundle’s proof binding and every signed action message include the genesis hash, so nothing proved or signed for one chain verifies on another
testnet markertestnet true: the genesis declares itself a test network, which is what lets a faucet run beside the bridge
validators26, each staked at 1,000 RAND, the staking minimum
quorum18 of 26: strictly more than two thirds of the stake
block intervalthe default --block-interval-ms 1000; about one block per second
block timea timestamp more than 60 s past its parent’s is invalid, and a validator does not vote for a block more than 15 s ahead of its own clock, so validators run NTP
proof windowproof_window_blocks 1,024: a bundle’s anchor must be one of the last 1,024 block-end roots, and its time no older than that (256 blocks on chains 18 and 19)
epochs1,000 blocks; a new bond waits two extra epochs before it counts (bond_activation_epochs 2, activating at epoch e + 3), unbonded stake releases two epochs later
stakingregistrations are v2 (rand-node register --v2), and a new key registers only after validators holding more than two thirds of the weight vote it in (admission_by_vote); one validator’s weight is capped at 33.33 %; new stake entering at an epoch boundary is capped at 25 % of the active weight (max_stake_entry_bps_per_epoch 2,500); no slashing
zkVMconstraint set 9 (constraint set 8 plus Merkle spans in the recursion verifier and the MODQ chip for Dilithium2 arithmetic; chains 18 to 20 ran set 8), production FRI profile (80 queries)
bundle guesthc_bundle 60af094acfe65d85fdb18fb3d06cf9085dcf28c96e59e87f1ee527226e6e3fce: the 4-in-4-out hidden-asset bundle, version 3, tier 14
auth guesthc_auth 1e4e347f44cf86750b30a9a4bdf9ec9256efe353d4ff8017451eca7d195639c1: the spend authorisation every bundle carries, tier 10
multisig auth guesthc_auth_multisig 9705f8e2f1bc8561848b29cb8efd57c37e3e39788fa58a5f03304d8019668247: an M-of-N Dilithium2 policy (up to 3 of 16) proved as the bundle’s authorisation instead of hc_auth, tier 18; the chain learns only that a multisig authorised the spend. Every validator loads its pinned verifier key, msauth-vk-production.bin, from beside the binary
gasa call declares a gas limit the circuit enforces and pays gas_price for it: 100 units per gas and 800 units per KiB at the floor, both moving per block toward a target of 262,144 gas and 9,961,472 bytes (10,485,760 on chain 20), and never above the ceilings of 10,000 per gas and 80,000 per KiB. Only the bytes the byte price is charged on (a call’s proof and input envelope) count toward the byte load (byte_load: "paying"), so a block of transfers does not raise it. Every bundle declares the pinned limit 20,479 and pays the flat 0.001 RAND
feesfees.burn_base and fees.burn_floor: every transaction’s floor (the 0.001 RAND of a transfer, a deploy’s per-word fee, a call’s gas and bytes at the prices in force, a bridge burn’s fee, an invoke’s cell fee) is burned and counted in rand_getSupply.base_fees_burned; the proposer keeps only the tip above the floor. On chains 18 to 20 the whole fee went to the proposer (Fees)
program stateRPL-2 on: program cells, program vaults and Invoke (Action 33); a created cell costs 0.01 RAND (cell_fee 10,000,000 units); an invoke reads at most 8 cells, writes at most 8 and makes at most 4 payouts (rand_getLimits.program_state)
note envelopeenvelope_bytes 1860: every note’s envelope is 1,860 bytes and carries an encrypted memo
program capmax_program_words 65,535, but under hardening_v6 a deploy that no tier-14 call could hold is refused (ProgramUncallable): 8,180 words for a program with no public segment
proof capmax_proof_bytes 6,291,456 (6 MiB), room for a multisig authorisation proof; it was 4 MiB on chains 18 to 20 and 8 MiB on chains 13 to 16
block capmax_block_bytes 19,922,944 (19 MiB; 20 MiB on chains 18 to 20)
call envelope capmax_call_envelope_bytes 65,536
public input per programmax_program_public_words 32,768, fixed at deploy
fauceton, but only for the 16 wallets on the genesis allowlist (staking.faucet_recipients), and only from the 18 validators the genesis names as minters (staking.faucet_minters): up to 100 RAND per call, 10,000 RAND per epoch in all
confidential computationon; a call proof is capped at tier 14. Programs do not carry over a cut; the example programs say which chain each is deployed on
tokensthe RPL registry is on: registration fee 1 RAND, burned; at most 4,096 tokens; every note value below 2⁶³. zUSD is listed in the genesis at index 1 and was the only token on chain 21 at its cut: the eleven tokens registered on chain 20 were not carried
perpetual futuresRPL-3 on: one market, BTC-PERP, settled in zUSD with 20× leverage, 250 bps maintenance and 5/2 bps taker/maker fees; a position’s proof is capped at tier 18 and a deposit is at least 1 zUSD (rand_getPerps, rand_getLimits.perps)
multisig accountson: M-of-N Dilithium2 accounts with public balances, 1 RAND to create, at most 10 signers (rand_getMultisig); the foundation treasury, 100,000 RAND behind 2 of 3 keys, is the one genesis account
bridgeon: guardian set 1 with eight guardians, eight Dilithium2 PQ guardians, a pause key, emitters for four source chains, a daily mint cap of 100,000 zUSD per backing, and a global cap of 4,000 zUSD per rolling 24 hours across all backings. zUSD has seven backings; its supply is whatever is locked, read live from rand_getTokenSupply. Since chain 20 a fee of 10 bps is taken on each mint and each burn, in zUSD, as a note to a treasury address (bridge.fees): a deposit credits the gross less the fee, and a burn releases amount − fee on the source chain. A rotation of the PQ guardians or the pause key carries each new key’s own signature and takes effect 86,400 s after it is accepted (bridge.rotation)
history24 validators keep 24 hours of blocks (--prune-history 24h) and answer -32010 below that; two archive nodes keep every block, and the public RPC https://rpc.randprotocol.org forwards to an archive
block aggregationoff (no aggregation section in the genesis; the build refuses to start on a genesis that has one)
genesis value26,000 RAND staked in the validator register, 3,938.879078887 RAND in seven deposit notes carried from the operator’s wallets on chain 20, and 100,000 RAND issued to the treasury multisig: 129,938.879078887 RAND before faucet mints (rand_getSupply reports genesis_staked, genesis_deposited and multisig_issued); plus three genesis notes totalling 100.001999 zUSD, matching the zUSD locked on its backings

The bootstrap nodes (deploy/nodes.env):

/ip4/164.90.239.200/tcp/30303/p2p/12D3KooWEQEbUwZRgqhDPXhW7vNBmcRcnhUDGUADe81VFdv3ALYe
/ip4/165.245.173.74/tcp/30303/p2p/12D3KooWJyc5oDHggAr89e9QrRFBy9Tg8TxXh18yzrb1SM6KKLYw
/ip4/188.166.235.187/tcp/30303/p2p/12D3KooWSyX84P1DAbWByLHpRBMLRWD53r3Jj4aqVt6tHoF8B2ZQ

Chain 21 runs on the validator keys chains 14 to 20 used, so these peer ids have not changed since the chain-14 key rotation.

The explorer at randscan.org indexes chain 21 and serves a REST API at https://randscan.org/api/v1 (Explorer API). The full node’s JSON-RPC binds to 127.0.0.1:8545 by default; run a node (Running a node), use one you trust, or use the public endpoint https://rpc.randprotocol.org (rand --rpc https://rpc.randprotocol.org …). The public endpoint serves everything a wallet needs, including its first sync and sending transactions, under a limit of 1,200 reads and 6 sends a minute per address. It does not serve the faucet.

Getting RAND from the faucet

The faucet is a transaction type: a validator mints one note of a public amount to a shielded address, and the note is only openable by the address holder. On chain 21, as on chain 20, it pays only the 16 addresses on the genesis allowlist: a mint to any other address is refused with the faucet may not mint to this recipient (not in staking.faucet_recipients), so a wallet not on it gets test RAND by being sent some. Any of the three paths below asks a validator node for a mint; observers answer faucet mints are signed by validators; ask a validator node, and the public RPC endpoint does not forward rand_mint at all.

With the rand wallet, pointed at a validator’s RPC:

rand keygen                    # writes wallet.key.json; refuses to overwrite
rand address                   # the rand1… address on stdout (about 1,665 characters), its fingerprint on stderr
rand faucet                    # an allowlisted wallet: 100 RAND into a note only it can open
rand balance                   # scans the tree with this key; prints 100 RAND

rand faucet [ADDRESS] --amount <RAND> mints to another address or a smaller amount; 100 RAND is both the default and the cap per call. Over JSON-RPC the same request is rand_mint:

curl -s http://127.0.0.1:8545 -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"rand_mint","params":["rand1…", "100000000000"]}'

The result is the mint transaction’s hash; poll rand_getTransaction until it returns a block. Amounts are strings of units, and 1 RAND is 10⁹ units. The wallet apps have the same faucet as one tap; send from them with Rand Wallet v0.8.1 (v0.8.0 was the first release for chain 21) (which wallet sends on chain 21). The faucet page on this site takes waitlist requests for devnet grants.

A mint’s amount is public on chain: the one-hop visibility any transparent-to-shielded deposit has. What the note is worth to whom afterwards is hidden like every other note.

Where to go next

The fullnode repository’s own docs/ directory is the source these pages are checked against, and the papers carry the cryptographic background.

Last verified against fullnode commit c0878c3f (chain 21) on 2026-10-12.