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:
| layer | what runs |
|---|---|
| Signatures | Dilithium2 (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 encryption | ML-KEM-768 key encapsulation plus ChaCha20-Poly1305. Every note on chain is accompanied by an envelope only its owner (and its sender) can open. |
| Hashing | BLAKE3 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. |
| Proofs | A 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 computation | The 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. |
| Consensus | Chained HotStuff BFT: stake-weighted quorums of more than two thirds, round-robin leaders, a three-consecutive-view commit rule. |
| Storage and networking | One 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_v6rules. - 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 id | 21 (rand_chainId) |
| genesis hash | ca76c2766ed6090ac6ba5dad86b724dd5d2b80c0edfaed287cd8b129e663ca9a |
| genesis file | deploy/genesis-chain21.json in the fullnode repository |
| build | fullnode 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 binding | binding_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 marker | testnet true: the genesis declares itself a test network, which is what lets a faucet run beside the bridge |
| validators | 26, each staked at 1,000 RAND, the staking minimum |
| quorum | 18 of 26: strictly more than two thirds of the stake |
| block interval | the default --block-interval-ms 1000; about one block per second |
| block time | a 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 window | proof_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) |
| epochs | 1,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 |
| staking | registrations 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 |
| zkVM | constraint 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 guest | hc_bundle 60af094acfe65d85fdb18fb3d06cf9085dcf28c96e59e87f1ee527226e6e3fce: the 4-in-4-out hidden-asset bundle, version 3, tier 14 |
| auth guest | hc_auth 1e4e347f44cf86750b30a9a4bdf9ec9256efe353d4ff8017451eca7d195639c1: the spend authorisation every bundle carries, tier 10 |
| multisig auth guest | hc_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 |
| gas | a 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 |
| fees | fees.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 state | RPL-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 envelope | envelope_bytes 1860: every note’s envelope is 1,860 bytes and carries an encrypted memo |
| program cap | max_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 cap | max_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 cap | max_block_bytes 19,922,944 (19 MiB; 20 MiB on chains 18 to 20) |
| call envelope cap | max_call_envelope_bytes 65,536 |
| public input per program | max_program_public_words 32,768, fixed at deploy |
| faucet | on, 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 computation | on; 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 |
| tokens | the 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 futures | RPL-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 accounts | on: 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 |
| bridge | on: 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) |
| history | 24 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 aggregation | off (no aggregation section in the genesis; the build refuses to start on a genesis that has one) |
| genesis value | 26,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
- Accounts and addresses: the two kinds of keys, what a
rand1…address is, and why the 54-character address of chain 11 was reverted. - Notes and the commitment tree, Transactions and actions, Fees, Consensus and finality, Supply: the model.
- Cryptography and Proofs: the primitives, the STARK parameters, how a bundle is proved and verified.
- Tokens and Deploy an RPL token: the RPL standard, a token as a registry entry with an
rpl1…id, and creating one from the wallet. - Programs: deploying and calling a confidential program, and what is not possible yet.
- Bridge, Mint and burn, Staking, Running a node.
- Write a program in Rust or C: the complete guide, from designing a program’s inputs and outputs to a sealed-bid auction written in both languages, the proving budget, deploying and checking a call.
- Four example programs: complete applications, each run on the testnet: an anonymous vote over a Keccak allowlist, a proof of liabilities over a SHA-256 sum tree, an off-chain ledger whose state is carried between calls, and a private credit decision from a published model.
- The RISC-V ISA, Deploy a Rust program, Deploy a RISC-V program: building and deploying your own programs with the
rand-guesttoolchain. - The Solana transpiler and The Ethereum transpiler: SPL Token and an ERC-20, translated to RISC-V and matched word for word against the interpreters.
- Running a validator and an aggregator: RAM, CPU and disk for each role, and the measured proving-memory bounds.
- Developers: the repositories, the stack, the zkVM’s milestones, what is specified but not shipped, and how to build, test and contribute.
- JSON-RPC, Command line, Explorer API: the references.
The fullnode repository’s own docs/ directory is the source these pages are checked against, and the papers carry the cryptographic background.