01
Overview
OBEX v2 is a deterministic protocol built for financial applications on Robinhood Chain. Its design goal is simple to state: wherever protocol behaviour can be a rule instead of a choice, it is a rule. The same valid inputs produce the same valid outcome on every machine that evaluates them.
The protocol separates into four consensus-critical engines:
| Engine | Controls | Status |
|---|---|---|
| α-I Participation | Who is eligible (RAM-hard Proof-of-Effort + ECVRF) | IMPLEMENTED · LIVE |
| α-II Headers | Which blocks are valid (forkless by equalities) | REFERENCE DRAFT |
| α-III Admission | Which transactions execute first (canonical ordering) | SPECIFICATION |
| α-T Tokenomics | How rewards are calculated (proposer-independent) | SPECIFICATION |
Consensus-critical code is Rust with #![forbid(unsafe_code)] across every crate. Encodings are byte-precise: every hash input is length-prefixed per field, so no two distinct inputs can collide by concatenation ambiguity.
02
α-I Participation Engine
α-I makes participation expensive in physical resources instead of only capital. A miner fills a large dataset in RAM where each entry depends on an unpredictable earlier entry, commits the dataset with a Merkle tree, and binds the commitment to their identity and epoch through an RFC 9381 verifiable random function. The proof is expensive to produce and nearly free to check.
Constants
chain tag "OBEX/v2/chain/main" proof version 2 label size 32 bytes hash BLAKE3 (keyed derive mode, one key per domain) vrf ECVRF-RISTRETTO255-SHA512 (RFC 9381) vrf proof 80 bytes vrf output (beta) 64 bytes
Domain separation
Every hash runs in its own BLAKE3 derive-key domain, so values from one context can never be replayed in another:
OBEX/v2/effort/seed dataset seed OBEX/v2/effort/label label chain OBEX/v2/effort/challenge challenge indices OBEX/v2/merkle/leaf Merkle leaves OBEX/v2/merkle/node Merkle interior nodes OBEX/v2/vrf/input VRF input (alpha)
Derivations
H_domain is BLAKE3 in that domain with each field length-prefixed. LE64 and LE16 are little-endian integers. pk is the miner's 32-byte VRF public key.
seed = H_seed(chain_tag, pk, LE64(epoch)) label[0] = H_label(seed, LE64(0)) ante(i) = LE64(label[i-1][0..8]) mod i label[i] = H_label(seed, LE64(i), label[i-1], label[ante(i)]) root = MerkleRoot(label[0..n]) n is a power of two alpha = H_vrf(chain_tag, LE64(epoch), pk, root) beta = ECVRF_prove(sk, alpha).output 64 bytes, unbiasable index_k = LE64(H_challenge(beta, LE16(k))[0..8]) mod n eligible = beta[0..32] < threshold bytewise, big-endian
Why it is RAM-hard
The antecedent index ante(i) is read out of the previous label's own bytes, so it cannot be predicted before the dataset is built. Storing only a fraction of the labels forces recomputation of unpredictable earlier entries on nearly every step, which costs more than keeping the dataset resident. The honest strategy is to hold all of it in memory: 256 MiB at the campaign reference size.
Verification
A verifier holds only the proof. For each of the Q challenges it recomputes index_k from beta, checks the Merkle paths for the challenged label and both of its antecedents against the committed root, and recomputes the label equation from the opened antecedents. The ECVRF proof is verified against alpha, which binds pk, epoch and root. Any tampering fails a Merkle path, the label equation, or the VRF check. Total cost is under a millisecond.
03
Wire Format
A ParticipationProof serializes to a canonical little-endian layout. Decoding rejects trailing bytes, non-power-of-two dataset sizes and out-of-range challenge counts, so a proof has exactly one valid encoding.
| Offset | Size | Type | Field |
|---|---|---|---|
| 0 | 2 | u16 | version (2) |
| 2 | 8 | u64 | epoch |
| 10 | 8 | u64 | n_labels (power of two) |
| 18 | 2 | u16 | challenges Q (1..=4096) |
| 20 | 32 | [u8; 32] | pk (VRF public key) |
| 52 | 32 | [u8; 32] | dataset_root |
| 84 | 80 | [u8; 80] | vrf_proof (RFC 9381) |
| 164 | … | opening × Q | challenge openings, in order |
Each opening is the challenged label followed by a one-byte tag: 0 when the target is label zero (no antecedents), 1 followed by the openings for label i-1 and the data-dependent antecedent otherwise. A label opening is LE64 index, the 32-byte label, LE16 path length, then the Merkle siblings leaf-level first. At the reference size (8,388,608 labels, 16 challenges) a complete proof is 37,428 bytes.
04
Golden Vector
The repository freezes a complete test vector. Any independent implementation must reproduce these values byte for byte from the same inputs. The reference test suite fails if a single byte drifts.
inputs
sk 0x07 repeated 32 times (test key)
epoch 1
n_labels 64
Q 4
expected
pk aaf82404e5f7bfa7352ce093e4aabe82435385d64aa870090a56d1aa36169800
root 043ef22eecbc0e26edd3799858ebfcf1b071eab55752c837f3c7be4724d6cac0
beta 61a62e69345f1b5e7f8633adfaff2fa7dfc9d56755cd40df36df4453442c601f
ad1f8a5868fc1d4ec96ac9e76cb8da05601c46c4599290fe618899b94e160dc6The full vector, including the complete serialized proof, ships in the source download under test-vectors/alpha-i/vector-001.json.
05
Miner Reference
The reference miner is a single static binary. Install it with one command, or build it from the source download on the mining page.
obex-miner keygen [--out obex-identity.json]
Create a miner identity. The secret key IS the identity. Back it up.
obex-miner mine --epoch 1 --mem 256MiB --challenges 16
[--identity obex-identity.json] [--out obex-proof.bin]
Fill the dataset in RAM, commit it, draw the VRF, write the proof.
obex-miner verify obex-proof.bin [--threshold <64 hex>]
Verify any proof file locally.Reference performance · 256 MiB
mine about 10 seconds on a modern CPU verify under 1 millisecond proof 37,428 bytes, self-contained
Downloads and SHA-256 checksums are published on the mining page. The binary embeds no identifiers and phones home to nothing.
06
Mining Campaign · Epoch 1
The live campaign records verified participation ahead of network activation. Rules as currently deployed:
| Ticket | hold at least 500,000 $OBEX in the submitting wallet |
| Ticket check | live on Robinhood Chain at login and at every submission |
| Dataset minimum | 8,388,608 labels (256 MiB) |
| Challenges minimum | 16 |
| Per-wallet cap | 10 accepted proofs per epoch |
| Duplicates | one submission per (wallet, epoch, dataset root) |
| Verification | full cryptographic check at submission, instant verdict |
| Eligibility threshold | every valid proof is eligible in epoch 1 |
| Allocation formula | share = your eligible proofs ÷ all eligible proofs on the record |
| Window closes | Tue, 01 Sep 2026 00:00:00 GMT |
Allocation is pro-rata over the record. At network activation, a fixed epoch 1 mining pool of native OBEX is distributed to the wallets on the record: your share of the pool equals your eligible proofs divided by all eligible proofs, and the per-wallet cap of 10 bounds any single wallet's share by construction. The pool size is announced before activation. The current $OBEX token is the ticket into mining, never the payout, and the record is cryptographically auditable: every accepted proof re-verifies from its bytes alone.
07
Verify It Yourself
Do not take the dashboard's word for it. The source download includes obex-verify, a headless verifier: proof bytes on stdin, one-line JSON verdict on stdout.
cargo build --release -p obex-verify
./target/release/obex-verify < obex-proof.bin
{"valid":true,"eligible":true,"epoch":1,"n_labels":8388608,
"challenges":16,"pk":"…","dataset_root":"…","beta":"…"}Flip one byte anywhere in the proof and the verdict becomes invalid with the failing check named. That asymmetry, expensive to produce and nearly free for anyone to check, is the entire point of the design.
Questions the docs do not answer land first on X and Telegram. The α-II header engine now ships as a reference draft in the source download, spec and tests included. α-III and α-T publish here as they land.
