Verifiable Randomness (VRF)

Verifiable onchain randomness on MegaETH via DrandOracleQuicknet — a preinstalled, stateless BLS12-381 verifier for the public drand quicknet beacon.

MegaETH ships with a preinstalled verifiable random function (VRF) service: DrandOracleQuicknetarrow-up-right, a stateless BLS12-381 signature verifier deployed at a fixed address on each MegaETH network. Any contract can consume it. The randomness itself comes from drandarrow-up-right, a public randomness beacon independently produced by a global network of participants and freely downloadable over HTTP.

At the highest level:

  1. Your app commits to a specific future drand round.

  2. Anyone — user, relayer, keeper, bot — fetches that round's signature from the public api.drand.sh once it's published.

  3. They submit it in a transaction; DrandOracleQuicknet.verifyNormalized(round, sig) checks the BLS pairing onchain and returns a canonical 32-byte random value.

circle-info

For a complete worked example — contract, tests, and an end-to-end shell demo — see the Drand VRF Lotteryarrow-up-right.

What is VRF?

A verifiable random function produces a random value together with a proof of its validity. Given the proof and a public verification key, anyone can independently check three properties:

  • Correctness. The value was produced according to the VRF's public rules — no one can forge it.

  • Uniqueness. For any given input, there is exactly one valid output. The producer cannot choose among alternatives to bias the result.

  • Unpredictability. Before the proof is published, the value is indistinguishable from random.

For onchain use, the property that matters most is public verifiability: the proof is small enough that a smart contract can check it directly, without trusting the producer.

The VRF service on MegaETH

DrandOracleQuicknet is pre-deployed at a known address on each MegaETH network. Treat it the way you'd treat ecrecover — a stateless verification function your contract can call without owning or operating anything.

Source and full ABI: Zodomo/DrandVerifierarrow-up-right.

Addresses

Network

Chain ID

DrandOracleQuicknet

MegaETH Mainnet

4326

0x7a53a6eFA81c426838fcf4824E6e207923969b36

MegaETH Testnet

6343

0x4e1673dcAA38136b5032F27ef93423162aF977Cc

What it is (and isn't)

  • A regular Solidity contract at the address above — not an EVM precompile. You interact with it like any other contract via normal CALL / STATICCALL.

  • Completely stateless. Every call is a pure verification against hardcoded drand parameters (group public key, period, genesis, scheme). It has no owner, no upgrade path, no pause, and no storage that tracks anything per-caller.

  • Identical on every MegaETH network. Same source, same configuration (drand quicknet: 3-second period, G1 signatures). Only the deployed address changes per network.

Underlying protocol

The verifier speaks drand quicknet (bls-unchained-g1-rfc9380), a drand subnet that signs a new round every three seconds. Each beacon is a 48-byte compressed G1 BLS12-381 signature over sha256(uint64 round, big-endian) under a fixed threshold-BLS group public key. The verifier checks each signature with a pairing check through EIP-2537 BLS12-381 precompiles — which MegaETH supports natively.

For the protocol spec and security model, see the drand developer docsarrow-up-right.

What is drand?

drand is a public randomness beacon produced by the "League of Entropy" — a coalition of independent organizations (Cloudflare, Protocol Labs, EPFL, universities, and more).

Every few seconds, drand participants each sign a predetermined message (derived from the round number) with their BLS key share. Once enough shares arrive, anyone can combine them into a single valid BLS signature under the group public key. That signature is the beacon. Hashing it yields a 32-byte random value.

This gives three properties that matter for onchain randomness:

  • Publicly verifiable. Anyone with the group public key can check any beacon.

  • Unpredictable. The output is unknown until enough honest participants sign — no single party can predict it.

  • Unbiasable. BLS signatures are deterministic; even a threshold majority cannot cherry-pick among outputs, only decide whether to produce one.

drand has multiple networks. MegaETH's DrandOracleQuicknet targets the quicknet scheme specifically — the 3-second unchained subnet with G1 signatures. Details on protocol variants are in the drand protocol specificationarrow-up-right.

How to use DrandOracleQuicknet

Source, full ABI, and test vectors live at Zodomo/DrandVerifierarrow-up-right — start there if you need anything beyond the summary below.

API surface

Function
Purpose

PERIOD_SECONDS() → uint64

Returns 3 — the drand quicknet period.

GENESIS_TIMESTAMP() → uint64

Returns 1692803367 — the Unix timestamp of round 1.

roundMessageHash(uint64 round) → bytes32

The 32-byte digest drand signs for a given round. Useful for offchain proof construction.

verify(uint64 round, bytes sig) → bool

Runs the pairing check. Reverts on malformed signature bytes.

safeVerify(uint64 round, bytes sig) → bool

Same, but returns false instead of reverting on malformed input.

verifyAPI(string json) → bool

Accepts a raw api.drand.sh JSON payload and verifies it. Convenient, costs extra gas for JSON parsing.

verifyNormalized(uint64 round, bytes sig) → (bool, bytes32, bytes32)

Verifies and, if valid, returns (true, normalizedRoundHash, chainScopedHash). Encoding-invariant — the correct choice when you derive randomness from the signature.

circle-check

Minimal pattern

Under 50 lines, and the only external dependency is the address constant.

Fetching the beacon offchain

The drand API is public, unauthenticated, and served by multiple independent relays. Any of the paths below work — the JSON shape is identical.

The drand quicknet chain hash 52db9ba7…0c84e971 is fixed — don't change it.

Timing

drand quicknet publishes a new beacon every 3 seconds, deterministically. Round N becomes signable at GENESIS_TIMESTAMP + (N - 1) * 3 seconds (Unix), where GENESIS_TIMESTAMP = 1692803367. This cadence is fixed — there is no faster round under quicknet, so 3 s is the irreducible unit of VRF latency.

A single VRF cycle walks through four stages:

Stage
Happens at
Typical wait

Commit tx included

t₀ — your dapp picks revealRound

one MegaETH mini-block (~10 ms)

Round produced

t₁ = GENESIS + (revealRound − 1)·3 s

1–2 drand periods (3–6 s from t₀)

Beacon live on API

t₂ ≈ t₁ + <1 s

threshold BLS aggregation latency

Reveal tx included

t₃ — submitter sends reveal(sig)

one MegaETH mini-block (~10 ms)

Minimum realistic VRF time

With revealRound = currentRound + 2 (the default in the Drand VRF Lotteryarrow-up-right), end-to-end is ~4–7 s from commit to settled randomness. The wide range comes from where in a 3-second round your commit tx lands: commit just before a round boundary and you wait nearly 3 s (one period); commit just after and you wait nearly 6 s (two periods).

circle-exclamation

For apps that don't need low latency (weekly draws, cross-epoch reveals, cooldown periods) set revealRound further out to buy larger safety margins, at a direct 3-seconds-per-round cost.

Worked example

The Drand VRF Lotteryarrow-up-right is a complete Foundry project — src/DrandLottery.sol, test suite, deploy scripts, and an ./script/demo.sh that drives the full lifecycle end-to-end against a real MegaETH network. Clone it if you want something you can run immediately.

Security caveats

DrandOracleQuicknet answers exactly one question: "is this a valid drand beacon for this round?". Everything else — when to consume it, which round to use, how to lock application inputs — is your contract's responsibility. Get these three things right and you're safe; get any one wrong and the cryptography cannot save you.

The caveats below cover integration-level concerns — what your consuming contract must do to make drand randomness safe to use. For protocol-level concerns that sit below our layer — drand's threshold-honesty assumption, front-running by malicious drand nodes, DoS and liveness bounds, DKG assumptions — see drand's own Security Modelarrow-up-right. Your contract inherits those assumptions by consuming drand; they are not things DrandOracleQuicknet can enforce.

1. Commit to a future round and lock every outcome-relevant input at commit time

triangle-exclamation

drand beacons are public. If you pick the current round, or leave any outcome-relevant input mutable after commit, the submitter can read the beacon offchain and only proceed when the result favors them. Three concrete rules your commit logic must enforce:

  • Derive revealRound from block.timestamp + safety margin. Use currentRound + MIN_FUTURE_ROUNDS with MIN_FUTURE_ROUNDS ≥ 2 on MegaETH (larger on slower chains — see Timing).

  • Make failure loud with an explicit require. Inside commit, after computing revealRound, assert:

    Without this check, a stale or adversarial block.timestamp (miner drift, reorg, arithmetic edge case) can silently produce a revealRound that drand has already signed — the tx succeeds, no revert, but an attacker watching api.drand.sh has already seen the outcome. The require turns a silent security break into a visible revert.

  • Pin an exact round, not "≥ committedRound". Reject any reveal whose round argument doesn't match the stored revealRound exactly; otherwise the submitter gets to pick among several already-produced rounds.

And freeze application state — entrant set, stakes, tier choices, any outcome-relevant input — in the same commit transaction. An input that can still move after commit gives the submitter adaptivity even if the round itself is properly pinned.

2. Own the state the verifier doesn't

triangle-exclamation

Three things your contract must do that the verifier will not:

  • Freshness: require block.timestamp >= publish_time(revealRound) in reveal so a premature submission cannot succeed by accident.

  • Replay: flip a settled / consumed storage flag before the external verify call (checks-effects-interactions), so the same beacon cannot be consumed twice.

  • Encoding: use verifyNormalized. The same valid G1 point can be encoded as 48 bytes (compressed) or 96 bytes (uncompressed); if you hash raw signature bytes yourself, the submitter gets to choose between two different random values. verifyNormalized hashes the canonical uncompressed point so both encodings produce the same output.

3. Handle drand stalls explicitly

circle-exclamation

Add an expiry or fallback path so the game can resolve if the beacon never arrives. For example, a cancel-and-refund function gated by block.timestamp >= publishTime + STALL_WINDOW, or retry against a later round. See the DoS scenariosarrow-up-right in drand's security model for how long such stalls can plausibly last.

References

Last updated