Rand Protocol
Participate

Run a Rand node

The reference full node and its wallet are written in Rust and build from source. Two binaries come out: rand-node, the node and operator tools, and rand, a wallet that holds a shielded spend key, talks to any node over JSON-RPC and runs the zkVM prover locally for every transfer and every confidential call. An experimental testnet, chain 21, is live on 26 validators on DigitalOcean droplets. It is not audited and carries no real value. Linux x86_64 binaries of both are attached to the v0.8.0 release, the build the fleet was rolled to.

Build and run locally
bash
# 1. Rust (rustup picks up the pinned 1.98.1 toolchain) and RocksDB's build deps
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
sudo apt install build-essential clang cmake pkg-config libssl-dev   # Linux

# 2. Clone and build (10–20 min the first time)
git clone https://github.com/randprotocol/fullnode.git
cd fullnode
cargo build --release        # target/release/rand-node, target/release/rand

# 3. A two-validator chain on this machine (RPC on 8545 and 8546)
scripts/local-testnet.sh
target/release/rand --rpc http://127.0.0.1:8545 status

# 4. Tests; release because STARK proving is slow in debug (678 tests, about 43 minutes as measured on 2026-09-14)
cargo test --workspace --release
Join the public testnet as an observer
chain 21
# Release v0.8.0 (c0878c3f) runs chain 21, and no earlier release does: chain 21 runs constraint set 9, whose verifier keys and proof encoding nothing older carries. Build it from the tag, or on Linux x86_64
# take the release binaries and check them against the SHA256SUMS published with it
git checkout v0.8.0 && cargo build --release
curl -LO https://github.com/randprotocol/fullnode/releases/download/v0.8.0/rand-node -LO https://github.com/randprotocol/fullnode/releases/download/v0.8.0/rand \
     -LO https://github.com/randprotocol/fullnode/releases/download/v0.8.0/msauth-vk-production.bin# the pinned multisig verifier key: rand-node loads it from beside its binary and refuses to start without it
sha256sum rand-node rand msauth-vk-production.bin   # must print the release's values (SHA256SUMS, signed as SHA256SUMS.sig):
# 324a4ab1029d39e67fc2de36b036341b0f88f13089997d7fe24c596363a58278  rand-node
# e3a38e74ee28743a960fc1c3eb1ac6c538e18dc259411e10afff7f54e268bbf4  rand
# 68facb06c7f321aaf1d4d541acf6b5c0e9d7f17788ed1c9add6c5a8a8f7acd30  msauth-vk-production.bin

# Your node identity: Dilithium2 validator key and p2p peer id in one file. Generate your own
# and keep it outside the checkout; the repository tracks no key any more
rand-node keygen --out node.key.json

# The genesis ships in the repository; every node must hold the identical file.
# init prints its hash, which must match the one below
rand-node init --datadir ./data --genesis deploy/genesis-chain21.json

# Dial the public validators (chain 21 kept chain 14's keys, so its peer ids and IPs).
# Omit --validator: your key is not in the validator set. A validator also needs NTP
rand-node run --datadir ./data --key node.key.json \
    --listen /ip4/0.0.0.0/tcp/30303 --rpc 127.0.0.1:8545 --no-mdns \
    --bootstrap /ip4/164.90.239.200/tcp/30303/p2p/12D3KooWEQEbUwZRgqhDPXhW7vNBmcRcnhUDGUADe81VFdv3ALYe \
    --bootstrap /ip4/165.245.173.74/tcp/30303/p2p/12D3KooWJyc5oDHggAr89e9QrRFBy9Tg8TxXh18yzrb1SM6KKLYw \
    --bootstrap /ip4/188.166.235.187/tcp/30303/p2p/12D3KooWSyX84P1DAbWByLHpRBMLRWD53r3Jj4aqVt6tHoF8B2ZQ

# A wallet is a separate, shielded key. Its rand1… address is about 1.6 KB of text
rand keygen && rand address

# A faucet mint is signed by a validator, so it needs a validator's RPC: it works on the
# local two-validator chain as-is; an observer answers "ask a validator node". On chain 21
# the faucet mints only to the 16 wallets its genesis allowlists, and only from the validators it names
rand faucet                                  # 100 RAND into a note only you can open
rand balance                                 # scans the tree with your key; nobody else can
rand send <rand1 address> 1.5              # asks to confirm, proves (~2 min), waits for the commit
Validators
26
Quorum
18 of 26
Genesis
ca76c2766ed6090ac6ba5dad86b724dd5d2b80c0edfaed287cd8b129e663ca9a
Make a confidential call
rand
# Assemble a built-in guest: pay the surplus over 1000 if four private balances cover it
rand program build --guest private_payment --arg 1000 --out pp.json
rand program deploy pp.json                  # prints the program id (its content hash)

# Prove locally; only the proof, eight output words and a sealed input transcript go on chain
rand call <program id> --input 400 --input 250 --input 300 --input 75
rand receipt <tx>                            # outputs [1, 0, 25, 0, ...]: the surplus, published as data

# Later, open the transcript and check it against the H_IN the proof published
rand open-call <tx>                          # inputs: [400, 250, 300, 75] — verdict: faithful
The chain sees the program id, the gas tier and the eight output words. It never sees the balances, and because the fee is paid by a shielded bundle it does not learn who called either; outputs are data, and any payment is a bundle the caller makes. Measured on Apple Silicon: proving about 7 s at tier 10, a proof of about 1.2 MB at the 80-query FRI profile, and verification in about 16 ms with a warm verifier key, which a node computes once per tier and reuses across programs.

Requirements

OS
Linux x86_64 or macOS arm64
Rust
1.98.1, pinned by rust-toolchain.toml; rustup installs it
Build deps
C++ compiler, cmake, pkg-config, OpenSSL headers (RocksDB)
First build
10 to 20 minutes: RocksDB and Plonky3 from source
Ports
TCP 30303 inbound on public nodes; RPC on 127.0.0.1:8545
Server
A 1 to 2 vCPU cloud instance runs a testnet validator
Clock
NTP (chrony) on a validator: it withholds its vote from a block more than 15 s ahead of its own clock, so a slow clock silently stops voting
Proving
CPU only today: a shielded transfer takes about two minutes on a laptop (a 7 s authorisation proof and a bundle proof of about 110 s) and about 6 GB of memory; a small call adds about 30 s

Choose a role

  • Observer open to anyone

    The same binary without --validator. Syncs the chain, verifies every certificate and every bundle and call proof, re-executes every block, compares receipts, and serves JSON-RPC. This is what a new key runs on the public testnet.

  • Validator bonded

    Votes and proposes under chained HotStuff. On chain 21, as on chain 20, a new validator is admitted by vote first: validators holding more than two thirds of stake sign an AdmitValidator action for its key. Then it registers the node key (rand-node register --v2), bonds at least 1,000 RAND from a wallet, and enters the set at the third 1,000-block epoch boundary after the bond (chain 18's two-epoch bond delay). Chain 18 started from 26 validators at 1,000 RAND each; more than two thirds of stake, 18 of 26, must be online and voting to commit. Generate your own key: no validator key is kept in the repository any more, and the key files committed for earlier chains are published seeds.

  • Wallet and prover local

    The rand client holds a 256-bit spend key and signs nothing: two proofs are the authorization, a small one made with the spend key and the 4-in-4-out bundle proof. It scans the tree for its own notes, proves both on your machine, the same shape for RAND and for any RPL token, and for a confidential call proves the program too. Only proofs, commitments, nullifiers and sealed envelopes reach the chain.

Not running a node? The same wallet ships as an app for iOS, Android, Chrome and Firefox: Wallets.

Source
randprotocol/fullnode
GPL-3.0-only · the testnet runs v0.8.0, the latest release
Verify

Every node checks everything

A node that syncs re-verifies every certificate, re-executes every block including its proofs, and compares receipts before accepting. At startup it checks its own database, truncates anything inconsistent while keeping its vote-safety state, and refetches the gap from peers.

# Node stopped: hashes, QCs, signatures, proofs, replay
rand-node verify --datadir ./data --mode full
rand-node verify --datadir ./data --repair

Fault tests run on the live testnet

  • ›Stop one of four validators: the chain keeps committing and the node catches up in seconds when it returns.
  • ›Stop two of four: the chain halts without quorum and resumes without a fork when they return.
  • ›Corrupt a node's database: detected at startup, truncated, resynced from peers, byte-identical afterwards.
  • ›Transfers through different nodes: all committed, balances identical everywhere, supply unchanged.
  • ›A dropped peer link is re-established by the redial logic within about 30 seconds.

Not yet implemented

Listed so the gap between the paper and the node is legible rather than inferred.

  • ›Persistent per-program state and cross-program calls
  • ›A compiler in the wallet itself: a program is a built-in assembled guest or an image built with the separate rand-guest toolchain
  • ›Slashing and jailing, block rewards, fee markets, the hash-sortition leader beacon
  • ›A nullifier accumulator, proof pruning after finality, proof batching
  • ›A tier-20 proof of the SPL Token transfer, and the GPU prover market of the paper