Skip to content

Robinhood Chain · zero-knowledge state anchoring

Prove the chain.
Reveal nothing.

Zero knowledge anchoring for Robinhood Chain

Runs entirely in your browser. No wallet, no account, no server.

$Oracleum contractView on explorer →
0x309f85…a73f25
Blocks anchored
55,582blocks
Sum of on-chain anchored windows.
Proofs verified
19
Proofs generated in the lab and re-verified server-side.
Window size
2,048blocks max
Protocol constant, enforced on-chain.

The gap

Robinhood Chain publishes its state to Ethereum. Almost nobody is allowed to argue with it.

Every so often, Robinhood Chain posts a state root to Ethereum: a single hash standing in for the entire state of the chain at that moment. Ethereum stores the hash. It does not check it. Checking is delegated to a challenge window, during which someone is supposed to notice if the root is wrong and say so.

The catch is who someone is. Only a small permissioned set of validators can raise a challenge. If all of them are offline, uninterested, or agreeable, a bad state root is accepted by default and becomes the chain’s history. Nothing about that is unusual, since it is how most chains of this design work, but it means the guarantee you actually get is not “this state is correct”, it is “these particular parties did not object”.

That is a trust assumption wearing a verification costume. Oracleum replaces it with something you can check yourself: a commitment to every contiguous window of blocks, and a proof that the commitment is what it claims to be. You do not need permission to check a proof, and a proof does not care whether anyone was paying attention.

Anchoring

History is cut into windows of at most 2,048 blocks. Each window commits to the state root it began from and the one it ended on.

A window is a block range and two state roots: the root before the first block, and the root after the last. That pair is what makes a window meaningful, because it says “starting here, applying these blocks, you end up there”. A commitment to one root alone would be a snapshot; a commitment to both is a claim about a transition.

Windows must be strictly contiguous. Window n has to begin at the block immediately after window n−1 ended, and its before-root has to equal that window’s after-root. The verifier contract enforces both. This is the part that matters: you cannot anchor the convenient stretches of history and quietly skip the rest, because a skipped stretch leaves a gap the next anchor cannot cross.

ROBINHOOD CHAINwindow n−1blocks 0 to 2,047window nblocks 2,048 to 4,095window n+1must start at 4,096before n−1after n−1 = before nafter nNOTHING ABOVE IS PUBLISHEDcommitcommitC n−1 = v·G + r·Hv from both roots · r randomC n = v·G + r·Hv from both roots · r random+ proof+ proofProofAnchor.anchor(windowStart, windowEnd, commitment, proofHash)reverts unless windowStart == lastAnchoredEnd + 1 and the span is ≤ 2,048 blocks
Windows share an edge rather than leaving one: the root a window ends on is the root the next one starts from, and the contract refuses anything else. The state roots themselves stay above the line. What reaches the chain is a commitment and a proof that the commitment was formed correctly.

Window size

≤ 2,048 blocks

Capped so a single anchor stays cheap to produce and store.

Sequence

Strictly contiguous

start = lastAnchoredEnd + 1, enforced in the contract.

Committed to

Both state roots

Before and after, bound together with the block range.

Zero knowledge

The commitment is a locked box. The proof is a demonstration that you locked it correctly, performed without opening it.

A Pedersen commitment takes the thing you want to hide and a random number, and produces a single point on a curve. The random number is the important half. Because it is fresh every time, the same state roots committed twice produce two completely unrelated-looking commitments, and the commitment on its own tells an observer exactly nothing: not the roots, not their size, not whether two windows are related.

You also cannot lie later. The commitment is built from two curve points whose relationship nobody knows, because the second one is derived by hashing a fixed string onto the curve rather than being chosen. Without that relationship there is no way to find a second pair of values that opens to the same commitment. The box is sealed in both directions: you cannot see in, and the person who sealed it cannot swap the contents.

The proof is the other half. It convinces anyone that you know what is inside and that you built the commitment from the exact block range you claimed, by answering a challenge that only someone holding the real values could answer. The challenge is derived from the statement itself, so there is no verifier to collude with and no interaction to replay. One bit changes anywhere, and the answer stops fitting.

What is published, and what is not

Commitment CPublic
A point on secp256k1. Reveals nothing.
Proof (T, e, s₁, s₂)Public
Checkable by anyone, forever.
Block rangePublic
Bound into the proof’s challenge.
State rootsHidden
Never leave the prover.
Blinding factor rHidden
What makes C reveal nothing.

A hidden value looks like this on the wire: a hidden value is present, committed to, never shown.

On chain

One contract holds the anchor set. It refuses gaps, refuses oversized windows, and emits an event for every anchor it accepts.

ProofAnchor stores, for each accepted window, the block range, the commitment, a hash of the proof, and the address that submitted it. Before it stores anything it checks two things: that the window begins exactly where the last one ended, and that it spans no more than 2,048 blocks. Anything else reverts. The result is that the anchor set is a chain, not a pile. You can walk it end to end and know you have not skipped anything.

Verifying does not require trusting us, running our software, or asking anyone’s permission. Read the Anchored events from the contract, fetch the proof they reference, and check it. If you also hold the state roots, because you run a node or because you read them from Ethereum, you can recompute the commitment and confirm the anchor describes the history you observed.

ProofAnchor

Live

Stores anchors, enforces contiguity, emits Anchored.

0xe3459a…54a18b
View on explorer →

$Oracleum

Live

Prover fees and treasury funding.

0x309f85…a73f25
View on explorer →

ProofAnchor is live and its source is publicly verified. $Oracleum is not deployed; its card will fill in automatically the moment NEXT_PUBLIC_TOKEN_ADDRESS is set, and until then this page shows no token address at all rather than a placeholder. See the feed for every anchor written so far.

$Oracleum

Two jobs: it prices the cost of anchoring, and it pays for the windows nobody would otherwise cover.

Prover fees

Submitting an anchor to the verifier contract costs Oracleum. The fee scales with the window size, so anchoring 2,048 blocks costs more than anchoring 64. This prices the on-chain storage an anchor consumes and makes spamming the anchor set expensive.

Treasury funding

Every transfer carries a 3% tax routed to the prover treasury. The treasury reimburses gas for provers who anchor windows nobody else has claimed, so coverage of the chain’s history does not depend on any single operator staying online.

Parameters

$Oracleum launch parameters. Editable in config/token.ts.
ParameterValueNote
Total supply1,000,000,000 OracleumFixed. No mint function after deployment.
Decimals18Standard ERC-20.
Transfer tax3%300 bps on every transfer.
Tax destinationProver treasuryReimburses prover gas. Address published below.
Max window2,048 blocksEnforced by the verifier contract, not by policy.

Prover treasury

Destination for the 3% transfer tax, and the account that reimburses provers for gas on windows nobody else claims. It is a separate account from the one that submits anchors, so funding the treasury never means handing over the key that writes to the contract. It holds nothing until $Oracleum is deployed and starts routing tax to it.

Treasury addressView on explorer →
0x28782D…5D053F

1B supply, 3% transfer tax, set at deployment. The parameters live in config/token.ts; the contract below is what actually enforces them.

$Oracleum contractView on explorer →
0x309f85…a73f25

Roadmap

Tagged honestly. Live means you can use it today; planned means it does not exist.

Phase 01

Scheme

  • Pedersen commitments on secp256k1Live
  • Okamoto NIZK proof of opening, Fiat-ShamirLive
  • Browser proof lab with tamper checkLive
  • Window binding and contiguity rulesLive
Phase 02

Anchor

  • ProofAnchor.sol written and unit-testedLive
  • Verifier deployed to Robinhood Chain mainnetLive
  • First live window anchored from real state rootsLive
  • Public feed of on-chain anchorsLive
  • Contract source verified publiclyLive
Phase 03

Coverage

  • Continuous prover covering every windowIn progress
  • Prover treasury address publishedLive
  • Treasury funded and reimbursing prover gasPlanned
  • Independent re-verification clientsPlanned
  • External review of the schemePlanned
Phase 04

Succinctness

  • Recursive aggregation across windowsPlanned
  • Constant-size proof for the whole historyPlanned
  • On-chain proof verification, not just storagePlanned

FAQ

Questions worth asking

Does Oracleum need permission from Robinhood Chain to do this?

No. Anchoring reads public block data and writes to a contract that anyone can call. Oracleum is not a Robinhood Chain product and is not affiliated with, endorsed by, or operated in coordination with Robinhood. It is an independent verification layer built on top of a public chain.

If the roots are hidden, what exactly is being proved?

That a commitment was formed correctly from a specific block range and a specific pair of state roots, by someone who knew those roots. The proof binds the block numbers and the roots into its challenge, so a proof made for blocks 0 to 2,047 cannot be replayed for any other range. What it does not prove on its own is that the roots match what Robinhood Chain published. That comparison is the verifier’s job, and it needs only the roots they already have.

Why hide the roots at all, if they are public?

Because the same construction has to work for data that is not public: pre-publication state, sequencer-internal roots, and the intermediate roots inside a window. Building the public case on a scheme that also handles the private case means there is one mechanism to audit rather than two.

Why a 3% transfer tax?

Anchoring costs gas, and a window nobody profits from anchoring is a window that stays unanchored. The tax funds a treasury that reimburses provers for covering unclaimed windows, so history gets covered even when no individual has a reason to cover it. The rate is a launch parameter, set in config/token.ts.

Has any of this been audited?

No. The commitment scheme and the proof system are standard constructions, Pedersen commitments and Okamoto’s protocol on secp256k1, both decades old, but this specific implementation has not been reviewed by anyone outside the project. The verifier contract is deployed and its source is publicly verified on Sourcify, which lets you read exactly what is running; that is reproducibility, not an audit. Treat everything here as experimental.

What can I actually check right now?

Three things, in increasing order of effort. The proof lab runs the real scheme in your browser with no server involved: commit to a value, produce a proof, verify it, then flip a single bit and watch verification fail. The feed lists every window anchored on Robinhood Chain so far, each linking to its transaction. And every anchored proof is published as JSON, so you can fetch one, verify it in twenty lines with any secp256k1 library, and check its hash against what the contract recorded. The protocol page has the exact commands.

Something missing? Oracleum has no support desk yet. The code is the documentation.