Skip to content

Repository files navigation

SolanaVrf

SolanaVrf is a Verifiable Random Function (VRF) for Solana. Programs request randomness, an oracle generates it together with a cryptographic proof, and the VRF program verifies that proof onchain before delivering the value to your callback. Randomness that fails verification is rejected and never reaches your program.

The same program and SDK also work inside MagicBlock Ephemeral Rollups, so a Solana program that uses SolanaVrf keeps working when it is delegated to a rollup. No code changes are needed beyond selecting the rollup queue.

Start here: read the MagicBlock Solana VRF docs for the end-to-end integration flow.

Where it runs

Environment Queue constant Notes
Solana (mainnet, devnet, localnet) DEFAULT_QUEUE The primary target. Proof verified by the VRF program on Solana.
Ephemeral Rollups DEFAULT_EPHEMERAL_QUEUE Same program, same proof verification, lower latency for delegated programs.

Security and trust

  • Onchain proof verification: every fulfillment carries an RFC 9381 proof that the VRF program verifies onchain in ProvideRandomness. An invalid proof fails with InvalidProof and the callback is never invoked, so consumers never need to trust the oracle.
  • Audit: 2025-08-06 VRF Program Audit Report by Zenith.
  • Standards-based design: the implementation follows RFC 9381, using Curve25519's Ristretto group and Schnorr-like proof verification.

Examples

Quick integration flow

The MagicBlock VRF quickstart uses a simple request-and-callback pattern: your program requests randomness, names the callback instruction, and then consumes verified randomness in that callback.

  1. Add the SDK with Anchor support:

    ephemeral-vrf-sdk = { version = "0.3.0", features = ["anchor"] }
  2. Import the VRF macro, instruction helper, request params, and callback account metadata:

    use ephemeral_vrf_sdk::anchor::vrf;
    use ephemeral_vrf_sdk::instructions::{create_request_randomness_ix, RequestRandomnessParams};
    use ephemeral_vrf_sdk::types::SerializableAccountMeta;
  3. Request randomness from a normal instruction and point the VRF program at your callback:

    let ix = create_request_randomness_ix(RequestRandomnessParams {
        payer: ctx.accounts.payer.key(),
        oracle_queue: ctx.accounts.oracle_queue.key(),
        callback_program_id: ID,
        callback_discriminator: instruction::CallbackRollDice::DISCRIMINATOR.to_vec(),
        caller_seed: [client_seed; 32],
        accounts_metas: Some(vec![SerializableAccountMeta {
            pubkey: ctx.accounts.player.key(),
            is_signer: false,
            is_writable: true,
        }]),
        ..Default::default()
    });
    
    ctx.accounts.invoke_signed_vrf(&ctx.accounts.payer.to_account_info(), &ix)?;
  4. Add #[vrf] to the request context so invoke_signed_vrf is available, and pick the queue for your execution path: DEFAULT_QUEUE on Solana, DEFAULT_EPHEMERAL_QUEUE when the program is delegated to an Ephemeral Rollup.

    #[vrf]
    #[derive(Accounts)]
    pub struct RollDiceCtx<'info> {
        #[account(mut)]
        pub payer: Signer<'info>,
        #[account(mut)]
        pub player: Account<'info, Player>,
        /// CHECK: Oracle queue
        #[account(mut, address = ephemeral_vrf_sdk::consts::DEFAULT_QUEUE)]
        pub oracle_queue: AccountInfo<'info>,
    }
  5. Consume randomness only in a callback that validates the VRF signer. This signer can only be produced by the VRF program, and the VRF program only signs after the proof has been verified onchain. This is where your app actually uses the random bytes: convert them into a domain value, then update program state.

    pub fn callback_roll_dice(ctx: Context<CallbackRollDiceCtx>, randomness: [u8; 32]) -> Result<()> {
        let roll = ephemeral_vrf_sdk::rnd::random_u8_with_range(&randomness, 1, 6);
        let player = &mut ctx.accounts.player;
    
        player.last_result = roll;
        msg!("VRF dice roll: {}", roll);
    
        Ok(())
    }
    
    #[derive(Accounts)]
    pub struct CallbackRollDiceCtx<'info> {
        #[account(address = ephemeral_vrf_sdk::consts::VRF_PROGRAM_IDENTITY)]
        pub vrf_program_identity: Signer<'info>,
        #[account(mut)]
        pub player: Account<'info, Player>,
    }

Overview

SolanaVrf lets Solana programs request unpredictable, tamper-resistant random values. Each value ships with a proof that is verified onchain, so anyone can confirm it was derived correctly from the oracle's key and the request. The same flow works unchanged for programs delegated to Ephemeral Rollups.

The crate is published as ephemeral-vrf-sdk for historical reasons; it is the SDK for SolanaVrf on both Solana and Ephemeral Rollups.

API

  • Consts – Program constants.
  • Error – Custom program errors.
  • Instruction – Declared instructions.
  • SDK – Program instruction builders.
  • State – Program state definitions.
  • DelegateOracleQueue – Delegate an Oracle queue to the delegation program.

Instructions

Errors

Common errors include:

  • Unauthorized – The authority is not authorized to perform the operation.
  • RandomnessRequestNotFound – The requested randomness was not found.
  • InvalidProof – The provided VRF proof is invalid.
  • InvalidCallbackAccounts - Invalid executable account in the callback

See SolanaVrfError for the full error list.

State

  • Oracle – Oracle data structure.
  • Oracles – Collection of oracles.
  • Queue – Oracle queue for randomness requests.

What is a VRF?

A Verifiable Random Function (VRF) is a cryptographic primitive that maps inputs to verifiable pseudorandom outputs. The key properties of a VRF are:

  1. Uniqueness: For a given input and private key, there is exactly one valid output.
  2. Verifiability: Anyone with the public key can verify that an output was correctly computed from the input without learning the private key.
  3. Pseudorandomness: The output appears random to anyone who doesn't know the private key.

In SolanaVrf, oracles use VRFs to generate random values that are verified onchain by the VRF program, ensuring that the randomness is both unpredictable and tamper-resistant.

VRF Implementation

This repository contains an implementation of a Verifiable Random Function (VRF) based on Curve25519 elliptic curve cryptography, using HKDF (HMAC-based Key Derivation Function) for key derivation and SHA-512 as the hash function. The VRF is designed to allow a party to prove that they know a random value derived from a secret key, with the proof being verifiable by any third party.

Key Features

  • Curve25519-based VRF: The VRF is implemented using the Ristretto group of Curve25519, offering high security and efficiency.
  • Key Generation: The secret and public keys are derived using HKDF, ensuring secure key generation from an initial keypair.
  • VRF Computation: The VRF output is computed by hashing the input to a point and applying scalar multiplication. The proof consists of commitments and a response that is verified through a Schnorr-like signature scheme.
  • Proof Verification: The verification function checks two Schnorr-like relations, ensuring the integrity and validity of the VRF proof.

Cryptographic Primitives

  • Curve25519: The cryptographic foundation of the VRF, offering a secure elliptic curve with efficient computation and strong security guarantees.

    • Ristretto group: Provides non-malleability and robustness in scalar operations.
    • Scalar multiplication: Used to generate public keys and VRF outputs.
  • SHA-512: A strong hash function used throughout the protocol, including in the key derivation and challenge generation.

  • HKDF: A key derivation function that is based on HMAC and used for securely generating secret keys from initial entropy sources.

  • Schnorr-like Signature Scheme: Used for generating and verifying the VRF proof, ensuring that the output is verifiably bound to the input and secret key.

Approach

The VRF implementation follows the structure laid out in RFC 9381, consisting of the following steps:

  1. Key Generation: A key pair is derived from a given keypair using HKDF to generate a secret key (sk) and a corresponding public key (pk), which is a scalar multiple of the base point on Curve25519.

  2. VRF Computation:

    • The input is hashed to a point using the hash_to_point function.
    • The output of the VRF is computed by multiplying the secret key (sk) with the hashed point.
    • A nonce (k) is derived, and commitments are computed for both the base point and the hashed point.
    • A challenge value is generated by combining various elements (output, commitments, etc.) and hashing them. The final response (s) is computed using the standard Schnorr signature response formula.
  3. VRF Proof Verification:

    • The verifier recomputes the challenge and checks two Schnorr-like relations:
      • Base point check: s * G == commitment_base + c * pk
      • Hashed point check: s * h == commitment_hash + c * output
    • If both checks pass, the proof is valid.

Soundness

The security of the VRF relies on the hardness of the Discrete Logarithm Problem (DLP) in elliptic curve cryptography. The implementation ensures that:

  1. Correctness: The VRF proof is guaranteed to be correct if the two Schnorr-style checks hold.
  2. Unforgeability: An adversary cannot generate a valid proof without knowledge of the secret key.
  3. Binding: The output is bound to the input, ensuring that the same input always produces the same output and proof.
  4. Non-malleability: The proof cannot be altered or manipulated without invalidating the verification.

Get started

Compile your program:

cargo build-sbf

Run unit and integration tests:

cargo test-sbf --features test-sbf

Run the oracle service:

RUST_LOG=info cargo run --bin vrf-oracle

Oracle CLI

CLI for managing oracles. See all available commands with:

cargo run --bin vrf-cli -- --help

Example usage

See the integration test program for a minimal program-level example, or the MagicBlock Engine examples repository for full app integrations.

About

Verifiable Random Function (VRF) implementation for Solana

Resources

Stars

18 stars

Watchers

2 watching

Forks

Releases

Contributors

Languages