Skip to Content
Native FeaturesVRF Randomness

Native VRF Randomness

TOS provides Verifiable Random Functions (VRF) at the protocol level, enabling secure, unpredictable, and verifiable random numbers at $0.01 per request.

Implementation Status

FeatureStatus
Block VRF proof generationImplemented
vrf_random syscallImplemented
vrf_verify syscallImplemented
vrf_public_key syscallImplemented
Instant randomnessImplemented
Delayed randomness (10 blocks)Implemented

Why VRF?

Block hashes are NOT secure for randomness:

Block N: Player bets → Chooses "High" Block N+1: Miner sees bet → Can manipulate block by reordering transactions until favorable VRF Properties: ✓ Verifiable: Anyone can verify correctness ✓ Unpredictable: Unknown before generation ✓ Unmanipulable: Generator cannot choose output

Cost Comparison

OperationChainlink VRF (BSC)TOS Native
Request random$0.25$0.01
Get result$0.05$0.001
Instant randomN/A$0.005
Batch (10)$2.50$0.08

25x cheaper than Chainlink VRF.

Randomness Types

TypeLatencySecurityUse Case
Instant0 blocksMediumLow-stakes games
Block VRF0 blocksHighMost applications
Delayed10 blocksMaximumHigh-stakes gambling

Syscall Reference

/// Generate VRF random number /// Cost: 10,000 CU pub fn vrf_random(seed: &[u8]) -> Result<VRFOutput, u64>; /// Verify VRF proof /// Cost: 5,000 CU pub fn vrf_verify( public_key: &[u8; 32], input: &[u8; 32], pre_output: &[u8; 32], proof: &[u8; 64], ) -> Result<(), u64>; /// Get current block's VRF public key /// Cost: 100 CU pub fn vrf_public_key() -> Result<[u8; 32], u64>;

VRF Output

pub struct VRFOutput { /// 32-byte random value pub random: [u8; 32], /// Pre-output for verification pub pre_output: [u8; 32], /// Cryptographic proof (64 bytes) pub proof: [u8; 64], }

Examples

Dice Roll

fn roll_dice() -> u8 { let seed = get_block_hash(); let output = vrf_random(&seed).expect("VRF failed"); // Map to 1-6 (output.random[0] % 6) + 1 }

NFT Rarity

fn determine_rarity() -> Rarity { let seed = get_block_hash(); let output = vrf_random(&seed).expect("VRF failed"); let roll = u16::from_le_bytes([ output.random[0], output.random[1], ]) % 10000; match roll { 0..=49 => Rarity::Legendary, // 0.5% 50..=499 => Rarity::Epic, // 4.5% 500..=1999 => Rarity::Rare, // 15% _ => Rarity::Common, // 80% } }

Verified Gambling

fn bet_high_low(choice: u8) { let player = get_tx_sender(); let bet = get_call_value(); // Generate VRF let seed = get_block_hash(); let output = vrf_random(&seed).expect("VRF failed"); // Verify for transparency let pk = vrf_public_key().unwrap(); vrf_verify(&pk, &seed, &output.pre_output, &output.proof) .expect("Verification failed"); // Roll 0-99 let roll = output.random[0] % 100; let player_wins = (roll < 50 && choice == 0) || (roll >= 50 && choice == 1); if player_wins { let payout = bet * 195 / 100; // 1.95x transfer(&player, payout).ok(); } // Log for verification log_u64(roll as u64, choice as u64, bet, 0, 0); }

Security Guarantees

Cryptographic Standard

  • EC-VRF (Elliptic Curve VRF)
  • IETF draft-irtf-cfrg-vrf-15 compliant

Anti-Manipulation

  • Random generated by validator set
  • Single validator cannot predict output
  • Request-response prevents front-running

Verifiability

  • Proof stored on-chain permanently
  • Anyone can verify correctness
  • Mathematical guarantee of fairness

Best Practices

  1. Always use unique seeds - Include contract address or tx data
  2. Verify for high-stakes - Call vrf_verify for transparency
  3. Store proofs - Enable post-hoc auditing
  4. Log results - Let users verify outcomes

See Also

Last updated on