Rand is open source. The full node, the explorer, the bridge, the proving research and the wallet clients each live in their own repository on GitHub. Read the code, run the tests, send patches. This page is the map: where each component lives, what it is built with, how far the proof system has come, and where it stops today.
Repositories
| repository | what it holds | language |
|---|---|---|
randprotocol/fullnode | Reference full node and wallet: chained HotStuff BFT, libp2p networking, the shielded RAND note pool, the zkVM proof verifier, JSON-RPC, the rand wallet CLI and the rand-prover delegated prover. | Rust |
randprotocol/randscan.org | Block explorer behind randscan.org: an axum indexer with a REST and WebSocket API over PostgreSQL, and a Next.js frontend. | Rust · TypeScript |
randprotocol/bridge | Guardian bridge for USDT and USDC from Ethereum, Binance Smart Chain, Tron and Solana: the custody contracts, the shared attestation format and its test vectors. | Solidity · Rust |
randprotocol/zkp-circuits | Proof-system walkthroughs (Groth16 vs STARK, shielded pool, ring signatures, mixer), research/, the Rand reference zkVM, recursion/, the recursion VM, the guest toolchain and the two translators, and the CUDA kernels. The fullnode build needs this repository checked out beside it as circuits/. | Rust |
randprotocol/clients | The wallet clients: desktop, web, iOS and Android. | Rust · Swift · Java · JavaScript |
The stack
Rust end to end. Rand is its own chain: a HotStuff BFT node with a libp2p gossip layer, a fully shielded note pool as the ledger, post-quantum signatures and note encryption, and the Rand zkVM for confidential computation, all in the fullnode repository. The proof system itself is the part under active research, below.
| layer | what runs |
|---|---|
| Consensus | Chained HotStuff BFT, stake-weighted quorums, three-chain commit |
| Networking | libp2p: TCP, Noise, Yamux, gossipsub, Kademlia, mDNS on LANs |
| Ledger | Shielded note pool: depth-32 Poseidon2 tree, nullifier set, one 4-in-4-out hidden-asset bundle per transaction (2-in-2-out up to chain 13); since chain 17 a second, tier-10 auth proof beside the bundle proof (split authorisation); since chain 18, 1,860-byte note envelopes with an encrypted memo |
| Tokens | RPL: a token is a ledger registry entry with an rpl1… id, not a contract; it moves as notes in the same pool |
| Staking | Public validator register: bond from a bundle, two-epoch unbonding, 1,000-block epochs; since chain 20 a new validator is admitted by a vote of the set |
| Confidential computation | Rand zkVM: RV32IM under a Plonky3 batch STARK, ZK-hiding FRI, constraint set 9 since chain 21 (set 8 on chains 18 to 20); since chain 18 a call declares a gas limit the circuit enforces and pays per gas and per KiB; since chain 20 a program keeps state in cells and holds value in a vault (RPL-2); since chain 21 an RPL-3 perpetuals engine settles by state proof and a multisig policy can be proved inside the authorisation proof |
| Crypto | Dilithium2 · ML-KEM-768 · Poseidon2 · BLAKE3 · ChaCha20-Poly1305 |
| Storage | One RocksDB per node, fsynced commits, integrity check on startup; optional history pruning (--prune-history 24h), with archive nodes keeping everything |
| Bridge | Guardian-attested locks on four chains, with a Dilithium2 co-signature quorum on every mint; a bridged asset is a note in the same pool |
| Language | Rust throughout; Solidity for the bridge, TypeScript for the explorer |
One relation for every program
The whitepaper’s universal execution relation R_exec exists as code: rand_zkvm, an RV32IM machine proved under a single batch STARK on Plonky3 over the Goldilocks field. It proves that some trace ran program hc to these public outputs on inputs committed to by a salted H_IN, and nothing about the program is ever a parameter of the verifier. Publishing a confidential program means registering a hash, never generating a bespoke circuit.
The proof system is transparent, with no trusted setup and no pairing curve, and its assumption is a collision-resistant hash. Every other component that touches proofs is expected to converge on this crate rather than grow its own. The crate lives in zkp-circuits/research and is vendored into the fullnode at constraint set 8 (circuits aeacf31, fullnode v0.6.7 and v0.6.8). The tables and measurements below describe constraint set 5 (milestone M4.2) unless a line names a later set; they are taken from the fullnode’s docs/zkvm.md, docs/zkvm-milestones.md and docs/confidential.md as of 2026-09-13, and measurements are quoted as measured on an Apple Silicon laptop, not as targets.
Eight tables on named buses, a ninth on demand
One commitment, one FRI opening. Tables never call each other; they exchange facts over named LogUp buses (PROGRAM, PROGRAM_WORD, MEMORY, ALU, POSEIDON2, INPUT_DIGEST, INPUT_READ, KECCAK and the range and nibble lookups) and the verifier checks that every bus balances globally. Every table’s maximum constraint degree is pinned by a test under the cap of 8 that the FRI blowup allows.
| table | kind | role |
|---|---|---|
program | witness | Raw instruction words decoded in-circuit since M3.4, digested by the cpu into hc |
cpu | witness | One row per cycle, plus digest rows that absorb the program into hc and the salted inputs into H_IN |
memory | witness | Registers and RAM in one table, sorted by (space, addr, ts); sub-word access since M2.5 |
alu | witness | Byte-limb arithmetic, shifts, compares; RV32M multiply and divide since M2.6 |
range | preprocessed · 256 rows | Range checks and the powers-of-two lookup |
nibble | preprocessed · 256 rows | 4-bit AND, OR, XOR; a hit is itself a range check on both operands |
poseidon2 | witness | One row per permutation round in 32-row blocks; serves the POSEIDON2 bus and both digests |
input | witness · since M4.1 | One row per private input word; serves INPUT_DIGEST and INPUT_READ, so a read cannot escape the commitment |
keccak | witness · optional | Keccak-f[1600] in 32-row blocks, present only in a proof whose guest called KECCAK (M4.2) |
Three constraint sets have landed since. Set 6 added a mandatory public table for a program’s deploy-time public input, bound to the unsalted digest H_PUB, and an optional sha256 table beside keccak. Set 7 (chain 16) blinds every LogUp terminal on a new BLIND bus and floors every declared table at 2⁷ rows, and adds the length-bound POSEIDON2_LEN syscall. Set 8 (chain 18) adds a GAS column to the cpu table and one public value, the declared GAS_LIMIT.
What a proof reveals
Public: the code hash hc (eight in-circuit digest words), the salted input commitment H_IN (eight words), the gas tier, and eight output words. Since constraint set 6 also H_PUB, the digest of the public input, and since constraint set 8 the declared gas limit. The proof’s header declares the heights of the Keccak and SHA-256 tables, so it shows whether a call hashed and, above the 2⁷ floor, roughly how much.
Hidden: the private inputs (H_IN is salted, so it is hiding as well as binding); every instruction word, because the verifier checks hc and never the program; every register and memory value; every branch taken; the exact cycle count and the exact gas used; and which syscalls ran, apart from what the two hash-table heights show.
The tier is public per proof because a STARK’s size already reveals its trace height; hiding the index would buy nothing. hc is binding, not hiding: see where it stops today.
Measured, at constraint set 5
| FRI | 80 queries · 20 PoW bits · blowup 8 · arity 8 · ZK on; 260-bit conjectured, about 86 proven. The 27-query retune of M2 was reverted by the 2026-09-12 audit |
| Call | private_payment at tier 10: about 7 s to prove, about 1.2 MB of proof at 80 queries (435 KB at 27), down from 21.6 s and 892 KB at M1 |
| Transfer | The 2-in-2-out bundle guest of chains up to 13: 3,811 words, about 9,160 cycles, tier 14; about 100 s to prove, about 1.3 MB of proof. Chain 14’s 4-in-4-out hidden-asset guest is pinned to the same tier: about 100 s, about 1.42 MB |
| Verify | About 16 ms with a warm key; the first verify at a new (tier, heights) key is about 230 ms |
| Block | 4 MiB budget and a 2 MiB proof cap: about three shielded transfers per block at 80 queries |
Apple Silicon laptop, release build. The byte-table split in M2.3 is what moved prove time; the 80-query profile is what moved proof size back up. The verifier key is independent of program content, keyed by tier and the proof-declared program, input and keccak heights, so a node warms one key and reuses it.
Later sets moved the sizes. Under constraint set 7 a tier-10 proof is 1,367,688 bytes at the production profile and a Keccak-carrying tier-10 proof 3,283,898 (measured 2026-09-28). Since chain 17 a transfer carries two proofs: the tier-14 bundle proof, about 1.49 MB, and the tier-10 auth proof, about 1.37 MB and about 7 s to prove. Chain 20’s genesis set a 20 MiB block and a 4 MiB proof cap, chain 21’s a 19 MiB block and a 6 MiB proof cap, and a call may not exceed tier 14.
Three targets, one circuit
Only RISC-V executes natively. Solidity and Solana programs either run on an interpreter guest inside the same relation, with their bytecode as input, or are translated off chain into RISC-V programs whose outputs equal the interpreter’s word for word. The expensive opcodes want dedicated coprocessor tables rather than bit-by-bit simulation.
| target | path | coprocessors |
|---|---|---|
| RISC-V | Native. RV32IM, either hand-assembled through asm.rs or compiled no_std Rust for riscv32im-unknown-none-elf, loaded as a flat binary since M4.1, or built from Rust or C by rand-guest into the image container (Deploy a Rust program) | Poseidon2 (and POSEIDON2_LEN since set 7); Keccak-f[1600] since M4.2; SHA-256 since set 6 |
| Solidity | solc --bin-runtime to EVM bytecode, then either the evm.bin interpreter guest (bytecode as input) or evm2rv, which translates the bytecode to C that rand-guest builds into an RV32IM image with the same outputs (The Ethereum transpiler) | Keccak-256 (table shipped), 256-bit modular arithmetic, ECRECOVER, Merkle-witness syscalls for storage |
| Solana / SVM | an sBPF ELF, run by the sbpf.bin interpreter guest or translated by sbpf2rv into an RV32IM image with the same outputs (The Solana transpiler) | SHA-256, Ed25519 verify, 64-bit multiply |
Milestones
Milestone 1 proved the general-purpose machine. Milestone 3 turned it into a shielded pool: a transfer with in-circuit membership proves under R_exec, and the verifier checks hc without ever seeing a program word. Milestone 4 is compatibility: its loader, input commitment and Keccak table shipped as constraint sets 4 and 5, and the SHA-256 table with set 6. The EVM and sBPF interpreter guests, the rand-guest toolchain and the two translators are built. The ERC-20 transfer has been proved, on a 128 GB machine; the SPL Token proof, at tier 20, has not. Milestone 5 is the recursion VM behind block aggregation, which is built and off on every chain. Constraint sets 7 and 8 followed the September reviews and the gas model.
| id | scope | exit criterion | status |
|---|---|---|---|
| M1 | Five tables, RV32I base ISA, HALT/WRITE_OUTPUT/READ_INPUT, ZK on, tier padding, assembler, emulator | fib, memcpy, bubble_sort, alu_mix and balance_check prove and verify; every cheating test rejects | done. 44 tests; a later review closed five soundness gaps in one wave |
| M1.5 | Viewing keys: a one-in-one-out shielded transfer guest, note envelopes under ML-KEM-768 and ChaCha20-Poly1305, party- and transaction-scoped disclosure, a simulated ledger | A transfer proves at tier 12 and the ledger accepts it; each disclosure scope opens exactly its own rows; a viewing key cannot spend | done. Not vendored into the node |
| M2 | Verifier-key cache, FRI retuned to a 100-bit conjectured target, the byte table split into range and nibble, sub-word loads and stores, the RV32M extension | Delivered narrower than scoped: the flat-binary loader and a firmer READ_INPUT binding were carried forward to M4.1 | done. fib at tier 10: 892 KB to 268 KB proof, 21.6 s to 3.1 s prove, 2.17 s to 16 ms first verify. Constraint set 3, a hard fork |
| M3 | Poseidon2 chip and syscall; NOTE_COMMIT, NULLIFY and MERKLE_VERIFY as guest routines over it; the spent commitment moved off the public output; the program table as witness with hc digested in-circuit | The transfer relation proves under R_exec with membership in-circuit, and verify(hc, proof) never sees a program word | done. Transfer guest: 4,554 instructions, 4,903 cycles, tier 14. The Merkle walk is now a counted loop, so program size no longer scales with tree depth |
| CUDA | GPU prover backend: NTTs and Poseidon2 Merkle commitments as CUDA kernels behind Plonky3’s Dft and Mmcs traits; rand send, call and deploy take --cuda | Every guest proves and verifies through the pure-Rust reference twin and the mock driver; the CPU verifier cannot tell backends apart | done; first run on hardware 2026-09-28. On an NVIDIA H100 the kernels build to PTX for sm_80 and sm_90 and match the CPU and Plonky3 reference. The production re-measurement on a fleet GPU node is still to do. A CUDA call cannot seal an input envelope, because the salt never leaves the prover |
| M4.1 | The flat-binary loader and the first compiled no_std Rust guests for riscv32im-unknown-none-elf; the salted input commitment H_IN with its own input table, so READ_INPUT is a lookup against a committed vector | A guest built by the standard toolchain loads, proves and verifies; two reads of one input index agree and the inputs are bound to H_IN | done. Landed 2026-09-11 as constraint set 4: 26 public values, eight tables, a hard fork |
| M4.2 | A hand-written Keccak-f[1600] coprocessor table and KECCAK syscall, present in a proof only when the guest used it; proof-declared memory height; a verifier key keyed on four components; FRI back to 80 queries after the 2026-09-12 audit | keccak256 proves as a compiled guest, and a proof without the table is byte-identical in shape to one from M4.1 | done. Landed 2026-09-12 as constraint set 5, a hard fork. A Keccak-bearing proof is about 1.9 MB larger, over the default 2 MiB cap. A chain whose genesis raises the cap admits one: chain 13 (8 MiB) took a 3.41 MB Keccak-carrying call on 2026-09-19, and chain 20’s cap was 4 MiB, chain 21’s is 6 MiB |
| M4.3 · M4.4 | EVM and sBPF guest interpreters compiled to RV32IM, with the foreign bytecode as input; a SHA-256 coprocessor table alongside Keccak; then the rand-guest toolchain and the evm2rv and sbpf2rv translators (2026-09-18) | An ERC-20 transfer and an SPL Transfer each prove under R_exec | built; one exit proof made. evm.bin (18,009 words) and sbpf.bin (8,317) run the ERC-20 and SPL Token vectors, and the translated images match them word for word. The ERC-20 transfer proved at tier 18 on a 128 GB droplet on 2026-09-19 (85.0 GB peak, 53.8 min); the SPL Token proof, at tier 20, is extrapolated at about 330 GB and has not been made (proving memory). Neither is callable on chain: a call is capped at tier 14 |
| M5 | The recursion VM (rVM): a 24-instruction Goldilocks-native machine whose programs verify Rand zkVM proofs, one N-generic aggregate program per inner proof shape, a CPU and CUDA backend split, and a self-verifier (M5.1 to M5.4, 2026-09-13 to 2026-09-16) | 50 real production bundle proofs accepted and 50 tampered ones refused at the named step; an rVM proof of the verifier program over one real bundle proof verifies natively (test profile) | built; production proofs need a large machine. Vendored as crates/randprotocol-rvm. Chain-side aggregation is merged and off on every chain (below) |
| set 7 | Every LogUp terminal blinded; every declared table floored at 2⁷ rows; 32-bit range checks on input, public and salt words; the POSEIDON2_LEN syscall; a JALR fix; verifier keys salted from key_derivation_v2 | The fixes of the 2026-09-27 and 28 zkVM reviews that move a verifier key, taken in one cut | done. Fullnode v0.6.1, chain 16 (2026-09-28), a hard fork |
| set 8 | The gas meter: a GAS column in the cpu table and a public GAS_LIMIT, with GAS ≤ GAS_LIMIT proved in-circuit; the run’s exact gas stays private | A call pays for the limit it declares, and every bundle proof declares the same pinned limit | done. Fullnode v0.6.7-rc1, chain 18 (2026-09-29), a hard fork. bundle_gas_limit is 20,479 |
Shielded pool phases
The fullnode’s ledger landed in three phases, each a hard fork (docs/shielded.md §7). S1 replaced the account ledger with a note pool; S3 brought the bridge back as notes and landed first; S2 put staking on top. All three are on main and on the current chain.
The rows below S2 are the v0.5 work. Every row is a hard fork; they were taken together as one fresh chain, chain 14, cut on 2026-09-20 from build b3c594c, and tagged v0.5 the same day after a live zUSD round trip through the deployed source endpoints. Chain 15, live from 2026-09-26 on v0.5.8 and later, carried all of it, with the genesis-gated fixes of audits v4 and v5 switched on: an allowlisted faucet with a per-epoch budget, delayed bond activation, a stake weight cap, genesis-bound registrations, consensus_domain 1, bridge rules v2 and the token registry’s cap, burned registration fee and 2⁶³ note bound. Chain 20, live from 2026-10-01 06:17 UTC on v0.6.8 (c9c9bd3c), a hard fork of chain 19, kept all of it and added the work of the v0.6 releases; chain 21, live since 2026-10-12 10:31 UTC on v0.8.0 (c0878c3f), a hard fork of chain 20, keeps all of that and adds constraint set 9, private multisig, burned fee floors, RPL-3 perps and multisig accounts, listed below.
| id | scope | exit criterion | status |
|---|---|---|---|
| S1 | The pool itself: notes, 2-in-2-out proved bundles, a depth-32 Poseidon2 commitment tree and nullifier set, the rand wallet with a local prover, the redacted RPC | A shielded transfer between wallets, a double-spend race between two validators and a deploy-and-call paid by bundles all pass in the cluster suite | done. Live on the public fleet since chain 6 (2026-09-12) |
| S3 | The bridge as notes: a bridged holding carries the registry’s asset index, an attestation deposits one note the chain computes itself, BridgeBurn is the one two-bundle transaction; sealed envelopes for call inputs, openable by the caller, a per-call key or a named auditor | A bridged asset is minted, spent and burned as a note; a caller can disclose what a program ran on without publishing it, and rand open-call checks the opening against H_IN | done. Landed first. Chains 9 to 13 left the bridge section out of their genesis; every chain since 14 has it. Since chain 14 a burn is one bundle, not two |
| S2 | Staking on the shielded chain: a public validator register, Bond out of a bundle’s burn, Unbond over two epochs, Withdraw into a note at a payout address, epochs of 1,000 blocks that re-derive the set, and a supply audit over register and pool | A fifth validator registers, bonds and proposes from the next epoch; one unbonds out of the set and withdraws into a note its payout wallet spends; both pass in the cluster suite | done. The wallet’s local commitment tree followed on 2026-09-21: a wallet computes its own witnesses and no longer tells its node which leaf it spends |
| RPL | The token standard (docs/tokens.md): a token is a registry entry in the ledger with a 62-character rpl1… bech32m id; creation is permissionless for a registration fee in RAND; the mint authority is fixed at registration as none, a key or the bridge; symbols are not unique; rand token create, mint, set-authority, burn, info, list, and rand_getTokens, rand_getToken, rand_getTokenSupply | A token is registered, minted, sent with rand send --asset and burned as notes in the same pool | running since chain 14 (v0.5). Since chain 20 the registration fee is 1 RAND, burned, the registry holds at most 4,096 tokens, and the genesis lists zUSD at index 1 |
| RPL-2 | Program state (docs/program-state.md): per-program cells (an 8-word key to an 8-word value, in the state root), a public vault per asset, a token minted only by its program, and the Invoke action (Action 33), a call that declares the cells it reads and writes and the notes it pays out; rand program invoke, state, vault, and rand_getProgramCell, rand_getProgramCells, rand_getProgramVault | The ledger applies a transition only if every declared read still holds and the vault covers every payout; a stale read is refused and re-proved | running since chain 20 (v0.6.8). cell_fee 0.01 RAND a created cell; at most 8 reads, 8 writes and 4 payouts an invoke. See Programs |
| hidden-asset bundle | Every transaction carries exactly one 4-in-4-out bundle in place of the 2-in-2-out one: slots 0–1 hold the private asset (dummies on a RAND-only transfer), slots 2–3 are always RAND and pay the fee. The two-bundle token transfer and the two-bundle bridge burn are gone | A transfer of RAND and a transfer of any RPL token publish the identical shape, so the asset that moved is hidden | running since chain 14 (v0.5). Tier 14, about 100 s to prove, about 1.42 MB of proof on chains 14 and 15; hc_bundle 83d3a370… there. Chains 18 to 20 pin bundle guest v3, hc_bundle 60af094a…, about 1.49 MB |
| transaction binding | Every bundle proof is made over, and verified against, H("rand-tx-bind-1", chain_id ‖ tx with proofs blanked), carried in the public-input segment | A copied, unmodified proof resubmitted under a changed destination, validator or memo is refused | running since chain 14 (v0.5). Since chain 20 (binding_domain 1) the preimage is H("rand-tx-bind-2", genesis hash ‖ chain_id ‖ …), and every signed action message carries the genesis hash too, so nothing proved or signed for one chain verifies on another |
| B1–B4 | Bridge hardening (docs/bridge.md §§14–20). B1: a per-backing daily mint cap, and a pause key that can only pause (unpausing needs the PQ quorum). B2: a block 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 clock, so validators need NTP. B3: a Dilithium2 co-signature quorum on every mint. B4: listing a bridged token or a backing after genesis under the PQ guardian quorum, with no chain cut | zUSD, one token with seven backings (USDT and USDC on Ethereum, Binance Smart Chain, Tron and Solana), is registered by transaction, and total_supply == Σ backings.locked holds by construction. The local nine-phase gate (zusd_e2e.rs: four validators, real proofs, faucet to register to deposit to transfer to burn to audit) passed 9 of 9 | running since chain 14 (v0.5). Since chain 20: mint cap 100,000 zUSD a day per backing plus a global 4,000 zUSD per rolling 24 hours (bridge rules v2), guardian set 1 with eight PQ guardians, a 10 bps fee in zUSD on each mint and each burn (bridge.fees), and guardian rotations that need possession and wait 86,400 s (bridge.rotation). zUSD is listed in chain 21’s genesis, as in chain 20’s, with its seven backings and the 100.001999 zUSD locked at the cut |
| audit v3 | The fixes of the third internal audit round, led by a co-founder (2026-09-19; no independent audit has been performed). POOL-1: a faucet Mint carries its note opening (pk, time, r), admission recomputes the commitment, and the minter signs rand-mint-2; genesis alloc notes carry an opening too. RPC-1: rand_getWitness(es) runs at most two tree rebuilds at once and answers -32000 busy after 10 s. OPS-1: all eighteen validator keys rotated, generated off-repo, and no key tracked in the repository | A mint whose commitment opens to more than its amount is refused; no chain-14 key has ever been in the repository | running since chain 14 (v0.5). PRIV-1, the witness request that names the leaf, was closed on 2026-09-21 by the wallet’s own tree |
Releases since v0.5
Every release is a git tag with an entry in the fullnode’s CHANGELOG.md. A release that changes consensus, the wire format or a verifier key ships with a new chain; the others roll onto the live chain one node at a time.
| release | what it brought | chain |
|---|---|---|
| v0.5 to v0.5.8 | RPL tokens, zUSD and the hardened bridge (above); the audit fixes; history pruning; consensus and sync hardening | 14, 15 |
| v0.5.9 | Rescan fixes: faucet mints only from genesis validators, sync back-off, gossip prechecks | 15 |
| v0.5.10 | Address sharing: fingerprints, randpay: links and QR codes; the encrypted memo, first switched on by chain 18 | 15 |
| v0.5.11 | Timelocked genesis vesting for team, investor and partner allocations. Genesis-gated and active on no chain | none |
| v0.6 | The zkVM, rVM and aggregation fixes from the September reviews | 15 |
| v0.6.1 | Constraint set 7: LogUp blinding, a 2⁷ table floor, 32-bit range checks, POSEIDON2_LEN, the JALR fix. Chain 16 was cut with hardening_v6 and bundle guest v2 | 16 |
| v0.6.2 | Delegated proving, phase 1: the rand-prover binary and the wallet’s --prover. A phase-1 prover receives the spend key | 16 |
| v0.6.3, v0.6.4 | Delegated proving, phase 2: split authorisation. The bundle proof no longer takes the spend key, a tier-10 auth proof does, and the transaction id domain becomes rand-txid-3 | 17 |
| v0.6.6, v0.6.7-rc1 | Gas: constraint set 8, a declared gas limit per proof, dynamic gas and byte prices; the memo switched on. v0.6.6 was never cut as tagged | 18 |
| v0.6.7 | Fixes on chain 18 that change no consensus rule: sealed-proof pruning (dormant), the envelope-format pin, viewing-key hygiene, the rVM allocator, GPU-kernel aliasing, ALU test coverage. Tagged before its full workspace suite finished | 18, 19 |
| v0.6.8 | RPL-2: program cells, program vaults and the Invoke action. zUSD bridge fees, both ways. The last audit-v6 fixes: no automatic lock release (CON-4) and a timeout-certificate pacemaker (CH-1); a --public-rpc listener, read limits, reserved validator peers, sync and gossip budgets, the pool’s byte cap, a bound on a proof header’s declared degree (ZKV-4); and genesis-gated rules chain 20 switches on: the genesis-hash binding, testnet, a 1,024-block proof window, gas price ceilings and the paying byte load, admission by vote, the stake-entry cap as a fraction, possession and a delay for bridge rotations. Wallets needed this build to send on chain 20 | 20 |
| v0.7.0, v0.7.1 | Node-only, rolled onto chain 20 one node at a time (2026-10-01 and 2026-10-07). The first releases built by the release workflow from the tag and signed by the release key; the audit v7 addendum (a by-hash fetch gated on an unsigned claimed height, rand_getBlocks pages bounded at 16 MiB of reply, a proving timeout in rand-prover, the prover pool confined to loopback with a syscall filter); --threads, --cpu and the GPU by default on a CUDA build; from v0.7.1 every RandProtocol repository is versioned together | 20 |
| v0.8.0 | Constraint set 9 (rVM phase 4’s Merkle spans and the MODQ chip): every verifier key and the proof encoding change, so the build runs chain 21 onward and refuses chains 18 to 20. Private multisig: an M-of-N Dilithium2 policy proved inside a second auth guest (hc_auth_multisig, tier 18), the chain learning only that the bundle was authorised; the pinned verifier key ships with the release. Genesis-gated sections chain 21 switches on: fees (every bundle’s floor burned, the proposer keeps the tip), perps (RPL-3: one BTC-PERP market on zUSD, settled by tier-18 state proofs), multisig (M-of-N accounts with public balances; the foundation treasury, 2 of 3, 100,000 RAND). Node-only on every chain: compact blocks, a startup checkpoint, a verify cache, the follower’s apply off the consensus loop, scan heads (rand_getScanLeaves). Built but on no chain: the dollar-indexed prover pay (SetRandPrice), tree aggregation. Wallets need this build to send on chain 21 | 21 |
Where it stops today
Deviations from the whitepaper, stated rather than smoothed over. Each is tracked in the crate’s own documentation with the milestone that closes it.
hcis binding but not hiding: it carries no salt, so a guessed program can be confirmed and two deployments of the same program are linkable. What M3.4 removed is the verifier holding the whole program in the clear.- A wallet built before 2026-09-21 asks its node for witnesses, and a witness request names the leaf it is about to spend. A current
randkeeps its own copy of the tree and never asks; the node still servesrand_getWitnessfor older wallets. - Deposits are public at the boundary: a faucet mint, a genesis note and a bridge deposit all carry their amount in the clear (since chain 14 a mint and a genesis note also carry their opening, so the owner key is public too), the same one-hop visibility a transparent-to-shielded deposit has anywhere.
- Zero knowledge is statistical, not perfect. That is the property Plonky3 0.7’s hiding FRI actually provides, and the crate says so.
- The transcript hash is Poseidon2 with development round constants, not the papers’ SHA3-384 / BLAKE3-384. A config swap, not a rewrite.
- At 80 FRI queries a bundle proof was about 1.42 MB on chains 14 and 15 (about 1.3 MB up to chain 13). Since chain 17 a transfer carries about 2.85 MB of proof: the bundle proof, about 1.49 MB, and the auth proof, about 1.37 MB. On a default chain, with 4 MiB blocks and a 2 MiB proof cap, a Keccak-bearing proof exceeds the proof cap outright; chain 20’s genesis set 20 MiB blocks and a 4 MiB proof cap (chains 13 to 16 set 8 MiB); chain 21’s sets 19 MiB blocks and a 6 MiB proof cap, room for the tier-18 multisig auth proof.
- A call proof’s header is not hidden. It declares the tier and the heights of the Keccak and SHA-256 tables, so it shows whether a call hashed. Calls committed on chain 15 before the v0.6 prover floor exposed more: a private table under 2⁷ rows could be read out of the proof. The v0.6 prover floor closed that for new calls, and constraint set 7 with
hardening_v6made it a rule of the chain from chain 16 on. - A call is capped at tier 14, with at most 2¹² Keccak rows (128 permutations) and 2¹³ SHA-256 rows (128 compressions), and under
hardening_v6a program of more than 8,180 words cannot be deployed. The EVM and sBPF interpreter guests and the translated ERC-20 and SPL Token images are all above that. - Whoever holds the witness sees everything. ZK protects the verifier’s view, not the prover’s. Since chain 17 a wallet can hand the bundle proof to a paired
rand-proverwithout handing over the spend key, but that prover still holds the viewing key and sees the notes. The CUDA backend first ran on hardware on 2026-09-28 and has no production measurement yet.
Repository layout
The fullnode’s Cargo workspace, as laid out in its README and its crates/ directory.
| path | what it holds |
|---|---|
crates/randprotocol-core/ | Pure logic, no I/O: crypto, notes and the commitment tree, ledger rules, gas, genesis, the HotStuff state machine |
crates/randprotocol-zkvm/ | The Rand zkVM, vendored from zkp-circuits/research at constraint set 8 (circuits aeacf31; resynced with deploy/sync-zkvm.sh), plus the chain-side proof verifier and its verifier-key cache |
crates/randprotocol-rvm/ | The recursion VM, vendored from zkp-circuits/recursion: a field-native machine whose programs verify Rand zkVM proofs |
crates/bridge-codec/ | The guardian bridge’s wire format and quorum rule, shared byte for byte with the Solidity contracts and the Solana program |
crates/randprotocol-node/ | RocksDB storage, libp2p networking, mempool, block sync, the JSON-RPC server and the rand-node binary |
crates/randprotocol-client/ | The rand wallet binary and the RpcClient library, with no RocksDB or libp2p dependency |
crates/randprotocol-prover/ | The rand-prover binary: a delegated prover that proves bundles for paired wallets |
deploy/ | Testnet genesis files, nodes.env, run scripts, cloud provisioning, cut-over and rebuild scripts. No key is tracked here since the chain-14 preparation |
docs/ | Reference documentation and the design spec |
scripts/ | Local two-validator testnet |
Specified, not yet shipped
These components are described in the papers or the fullnode’s docs but are not running: either absent from the repositories, or built and switched on for no chain. They are listed so the gap between specification and code is legible rather than inferred.
| component | status |
|---|---|
| bridge · guardian | The guardian and relayer daemons that run the attestation format end to end; the contracts, the codec and the fullnode’s receiving half ship, the daemons do not |
| fullnode · aggregation | Block aggregation with the recursion VM: sealing, pruning and sealed-form sync. Built and off on every chain; rand-node refuses a genesis with an aggregation section. It still needs the end-to-end forged-aggregate exercise, and it removes the bundle proof only, not the auth proof. The production rVM proofs need a large machine: under constraint set 7 an aggregate of two took 133 GB, of three 221 GB, and the exit proof more than 256 GB (measured 2026-09-28 and 29; not re-measured under constraint set 8) |
| fullnode · vesting | Timelocked genesis allocations for team, investors and partners (v0.5.11, docs/vesting.md). Genesis-gated: without a vesting section the four vesting actions are refused, and no chain has one. Chain 21’s supply audit, like chain 20’s, reports every vesting counter as zero. Since v0.6.8 a revocable entry is revoked by a threshold of its revokers, and only to the treasury its genesis entry names |
| fullnode · slashing | Slashing and jailing for leader equivocation are built in v0.6.8 behind staking.slashing and off on chains 20 and 21 (neither genesis has it, while all 26 validator keys belong to one operator). Block rewards, the hash-sortition leader beacon and cross-program calls are not built; an append-only nullifier accumulator (incremental_nullifier_root) is built and genesis-gated, on no chain. Persistent per-program state shipped as RPL-2 (above) |
| fullnode · prover pay, tree aggregation | Built in v0.8.0 and genesis-gated, on no chain: the dollar-indexed sealing subsidy paid at a RAND/USD price the validator set votes (SetRandPrice, rand_getRandPrice), the proposer/aggregator fee split (proposer_share_bps, prove_base) and tree-shaped aggregation (aggregation_tree, an aggregate over L·2^d bundles as one rVM tree). All wait on aggregation itself, which chain 21 does not enable |
prover/ | GPU proving daemon: claims batches from the queue, races on submission. The CUDA kernels live in zkp-circuits and first ran on an NVIDIA H100 on 2026-09-28; the market daemon does not exist. rand-prover, which ships, proves for the wallets paired with it and is not a market |
| zkp-circuits · M4.4 exit proof | A proof of an SPL Token transfer (tier 20), extrapolated at about 330 GB. The ERC-20 transfer (tier 18) was proved on a 128 GB droplet on 2026-09-19. Neither can be called on chain 21, which caps a call at tier 14 (the perp state proof is the one tier-18 proof the chain admits, and it is not a call) |
Build and test
Standard Rust workflow in each repository. The fullnode is one Cargo workspace with a pinned toolchain and a cluster test suite that starts real nodes over TCP. Its build needs the circuits repository checked out beside it, in a directory named circuits, at the commit the vendored crates were synced from (aeacf31 for v0.6.7 and v0.6.8, d217252 for v0.8.0). The zkVM is a standalone crate in zkp-circuits with its own toolchain pin and a demo that narrates what a confidential call reveals and what it does not.
The fullnode:
git clone https://github.com/randprotocol/fullnode.git
git clone https://github.com/randprotocol/zkp-circuits.git circuits # the sibling directory must be named circuits
git -C circuits checkout "$(sed -n 's/^circuits: //p' fullnode/crates/randprotocol-zkvm/guests-compiled/PROVENANCE.md)"
cd fullnode
# Rust 1.98.1 is pinned by rust-toolchain.toml; first build pulls RocksDB and Plonky3, 10 to 20 minutes
cargo build --release # target/release/rand-node, target/release/rand, target/release/rand-prover
# All crates; release because STARK proving is slow in debug. One to two hours, mostly proving
cargo test --release
# One machine, two validators
scripts/local-testnet.sh
target/release/rand --rpc http://127.0.0.1:8545 status
The research zkVM, in zkp-circuits/research:
# Toolchain is pinned by rust-toolchain.toml; the first build pulls Plonky3
cargo build --release
# Narrated demo: thirteen proofs, one at production FRI parameters (~6-7 min)
cargo run --release
# Emulator, per-table constraints, cheating provers, ZK, end-to-end, viewing keys, compiled guests (395 tests, ~17 min)
cargo test
The fullnode suite as measured at v0.6.1 on a 16-vCPU machine: core 521 tests, node 373, client 117, the cheating-prover suite 116, the hidden-bundle cheats 21 (75 min), the wallet flow 6 (53 min), the cluster 26 (44 min) and the zUSD end-to-end gate 2 (51 min). The recursion VM’s production proofs are outside it and need the memory listed above.
Running a node covers joining the public testnet with the build; the testnet genesis, bootstrap peers and run scripts ship in the fullnode’s deploy/ directory, and the download page has the short version.
Contribute
The fullnode is licensed under the GNU General Public License v3.0 (GPL-3.0-only); it was Apache-2.0 before. Open issues for bugs and design proposals on the repository the change touches. Pull requests are welcome: run cargo fmt && cargo clippy before submitting and keep changes scoped. The fullnode issues are the place to start.
The architecture, the privacy circuit, the fee-token proof and the post-quantum tradeoff are all documented in the whitepaper on the papers page. The fullnode repository’s own docs/ directory is the source every page in this documentation is checked against.