Back to Hub
Randomness

On-Chain Cryptography
& Randomness

Native, Secure, and Fast — Built Into the Sui Protocol

Move Threshold CryptographyLive Demo

1 / 12
DeterministicGamingAttack

Why Randomness Is Hard on a Blockchain

Blockchains are deterministic state machines — every node must independently arrive at the exact same state after processing the same transactions. This fundamental property makes generating unpredictable randomness impossible natively on most chains.

The Determinism Trap

All nodes run the same code with the same inputs. If you use block.timestamp or blockhash, every node sees the same value. An attacker can pre-compute outcomes before submitting a transaction.

Critical Use Cases

Gaming (loot drops, matchmaking), NFT trait distribution, governance lotteries, DeFi randomized airdrops, on-chain raffles — all require fair, unpredictable, and verifiable outcomes.

Real Attack Vectors

Front-running: MEV bots see your randomness call and act first.
Test-and-abort: Simulate outcomes off-chain, only commit if favorable.
Gas manipulation: Influence transaction ordering to bias results.

2 / 12

Existing Solutions & Their Flaws

Developers have tried many workarounds. Most introduce centralization, cost, or security trade-offs.

ApproachHow It WorksWhy It Fails
Block Hash / TimestampUse blockhash or timestamp as a seedMiners/validators can manipulate block contents and timing. Fully predictable.
Oracle Services (Chainlink VRF)Off-chain oracle generates randomness and delivers it on-chainRequires trusting the oracle operator. Adds latency and cost per request.
Commit-Reveal SchemesUsers commit hashes, then reveal seeds laterComplex UX, requires multiple rounds, users can refuse to reveal.
RANDAOValidators commit to random values that get combinedLast revealer can bias the outcome by choosing to reveal or abort.
Sui's insight: Randomness should be a protocol primitive — not an afterthought, not an external dependency. Validators themselves generate it.
3 / 12

How Sui Delivers Native On-Chain Randomness

Sui embeds randomness directly into the validator protocol. At every epoch, validators run a Distributed Key Generation (DKG) ceremony to create a shared secret that no single validator knows. This secret powers a continuous randomness beacon.

Step 1
DKG
Step 2
Threshold BLS
Step 3
Beacon

Distributed Key Generation (DKG)

At each epoch boundary, validators collaboratively generate a BLS12-381 key pair. The private key is never assembled in one place — each validator holds only a key share. A threshold of shares (e.g., 2/3 of validators) is required to produce a valid signature.

Threshold BLS Signatures

During the epoch, validators use their shares to sign a deterministic message (e.g., the round number). The aggregated signature is random, unpredictable, and verifiable by anyone using the public key. Because it's threshold-based, no single validator can bias it.

Randomness Beacon Parallel

The beacon runs parallel to consensus — it does not block transaction execution. New randomness rounds are produced continuously, and Move contracts can consume fresh values within the same epoch. This means low latency without sacrificing security.

UnpredictableUnbiasableFastNo Oracle NeededVerifiable
4 / 12

Validator Architecture: How It Works Under the Hood

Epoch Setup Phase

1. Validators agree on a new committee.
2. Each validator generates a private key share using verifiable secret sharing (VSS).
3. The public key is published on-chain for verification.
4. If a validator is offline, the threshold still holds as long as enough honest validators participate.

Continuous Generation Phase

1. Each validator signs the current round number with their share.
2. Signatures are aggregated into a single BLS threshold signature.
3. The signature is hashed to produce a randomness output.
4. Any client can verify the output against the public key — no trust needed.

Key insight: Because BLS signatures are unique and deterministic for a given message and key, the output is both unpredictable (before aggregation) and verifiable (after aggregation). This is the cryptographic foundation of Sui's randomness.
// Conceptually: randomness = hash( threshold_bls_sign(epoch, round) )
// No single validator can predict the output without colluding with a threshold of others.
5 / 12

The Move API: Simple & Safe

Sui exposes randomness through a shared Random object that lives at a well-known address. Your contract borrows it, creates a generator, and draws values. The compiler enforces safety rules automatically.

use sui::random::{Random, RandomGenerator};

// Entry functions CAN use randomness — they are called directly by users.
// Public functions CANNOT — the compiler rejects them to prevent test-and-abort.

entry fun draw_winner(
    lottery: &mut Lottery,
    rnd: &Random, // Shared randomness object — provided by protocol
    ctx: &mut TxContext
) {
    // 1. Create a generator from the shared randomness
    let mut gen = random::new_generator(rnd, ctx);

    // 2. Generate a random index within the participant range
    let winner_idx = gen.generate_u64_in_range(0, lottery.participants.length());

    // 3. Assign the winner
    lottery.winner = Some(lottery.participants[winner_idx]);
}

Available Generators

generate_u8() / u16 / u32 / u64 / u128 / u256()
generate_u64_in_range(min, max)
generate_bytes(n) — raw byte vector
shuffle(vector<T>) — Fisher-Yates shuffle

Compiler Safety Guards

Randomness-dependent functions must be entry — not public. This prevents attackers from calling them programmatically inside a PTB to test outcomes and abort if unfavorable. The compiler enforces this at build time.

6 / 12

Common Randomness Patterns in Move

// Pattern 1: Shuffle a vector (e.g., card deck, matchmaking queue)
entry fun shuffle_deck(
    game: &mut Game,
    rnd: &Random,
    ctx: &mut TxContext
) {
    let mut gen = random::new_generator(rnd, ctx);
    random::shuffle(&mut gen, &mut game.deck);
}

// Pattern 2: Generate raw bytes (e.g., NFT traits, salt)
entry fun mint_random_nft(
    collection: &mut Collection,
    rnd: &Random,
    ctx: &mut TxContext
) {
    let mut gen = random::new_generator(rnd, ctx);
    let seed = gen.generate_bytes(32);
    let trait_rarity = gen.generate_u64_in_range(1, 100);
    // Use seed and rarity to determine NFT appearance
}

// Pattern 3: Weighted lottery (e.g., weighted airdrop)
entry fun weighted_draw(
    pool: &mut RewardPool,
    rnd: &Random,
    ctx: &mut TxContext
) {
    let mut gen = random::new_generator(rnd, ctx);
    let total_weight = pool.total_weight;
    let roll = gen.generate_u64_in_range(1, total_weight);
    // Binary search or cumulative sum to find winner
}
7 / 12

Built-In Protections Against Common Attacks

Sui's randomness is not just a number generator — it is a defense system designed to neutralize the most common on-chain randomness exploits.

Attack VectorHow It WorksSui's Defense
Front-Running MEVAttacker sees your randomness transaction in the mempool and inserts their own transaction before it to steal the outcome.Randomness is unpredictable at transaction submission time. Even if an attacker sees your tx, they cannot compute the outcome before it executes. The beacon output depends on validator aggregation that happens at execution.
Test-and-AbortAttacker writes a PTB that calls a randomness function, checks the result, and aborts if unfavorable. They retry until they win.Move compiler rejects public functions that depend on randomness. Only entry functions can consume it. Entry functions cannot be called programmatically within a PTB for conditional abort — the compiler enforces this.
Gas ManipulationAttacker manipulates gas price or transaction ordering to land in a specific block where they predicted the randomness.Built-in restrictions prevent attackers from gaming gas budgets to influence randomness outcomes. The beacon runs independently of transaction ordering.
Single Validator BiasA malicious validator tries to influence the randomness by withholding or manipulating their signature share.Threshold cryptography ensures no single validator can influence the output. A minimum quorum (e.g., 2/3 of stake) is required to produce a valid signature. A minority of malicious validators cannot bias the result.
8 / 12

Best Practices for Using Randomness

DO: Isolate Randomness Logic

Keep randomness-dependent code in its own entry function. Do not mix it with state reads that could leak information. The outcome should be committed atomically.

DON'T: Expose Intermediate State

Never expose a public function that returns a random value and then lets the caller decide what to do. The compiler blocks this, but design matters too.

DO: Commit Results Immediately

Once randomness is consumed, write the result to on-chain state immediately. Do not hold it in a temporary variable across multiple transactions where it could be observed.

DON'T: Reuse Generators

Always create a fresh RandomGenerator for each randomness operation. Reusing a generator across multiple independent decisions can leak correlation information.

Golden Rule: Randomness should be a terminal operation in your transaction flow. Draw the value, apply it, commit the state. No branching, no conditional logic based on the value within the same PTB.
// GOOD: Randomness is the last step, result is committed immediately
entry fun reveal_nft(nft: &mut NFT, rnd: &Random, ctx: &mut TxContext) {
    let mut gen = random::new_generator(rnd, ctx);
    nft.trait = gen.generate_u64_in_range(1, 100);
    // nft.trait is written immediately — no intermediate exposure
}
9 / 12

Real-World Use Cases on Sui

Gaming

Loot boxes: Random item drops with verifiable rarity.
Matchmaking: Shuffle player queues fairly.
Card games: Shuffle decks without client trust.
Procedural worlds: Seed terrain generation on-chain.

NFTs & Collectibles

Blind mints: Reveal traits after purchase.
Rarity distribution: Weighted trait tables.
Randomized art: Compose layers from a seed.
Airdrops: Fair selection from a whitelist.

DeFi & Governance

Lottery pools: Winner selection without oracle fees.
Randomized drops: Surprise token distributions.
Committee selection: Random validator sub-sampling.
DAO voting: Tie-breaking without bias.

Why Sui Randomness Wins for These

Traditional solutions require oracles (cost + trust), commit-reveal (bad UX), or block hashes (exploitable). Sui provides sub-second latency, zero extra cost, and protocol-level security — making randomness viable for high-frequency use cases like real-time gaming.

10 / 12

How to Test Randomness-Dependent Contracts

Testing randomness is tricky because the output is non-deterministic. Sui Move provides test-only helpers to inject controlled randomness for reproducible tests.

// In tests, you can create a deterministic Random object
#[test]
fun test_draw_winner() {
    let mut ctx = tx_context::dummy();
    let mut lottery = create_lottery(&mut ctx);
    add_participant(&mut lottery, @0xA);
    add_participant(&mut lottery, @0xB);
    add_participant(&mut lottery, @0xC);

    // Create a deterministic Random for testing
    let mut random_state = random::create_for_testing(&mut ctx);
    let rnd = &mut random_state;

    // Call the entry function
    draw_winner(&mut lottery, rnd, &mut ctx);

    // Assert the winner is set (exact value depends on test seed)
    assert!(option::is_some(&lottery.winner), 0);
}

Testing Strategy

1. Use random::create_for_testing() for deterministic seeds.
2. Test boundary conditions (empty lists, single participants).
3. Test that public functions with randomness fail to compile.
4. Use #[expected_failure] for abort paths.

Statistical Testing

For large-scale validation, run your contract thousands of times in tests and verify distribution properties (e.g., chi-squared test on rarity outcomes). This catches biased generators.

11 / 12
SummaryKeyCheck

What to Remember

  • 1
    Sui randomness is native — no external oracle, no trust assumptions, no extra fees. It's built into the protocol layer and available to every Move contract.
  • 2
    DKG + Threshold BLS at the validator level ensures unpredictability and unbiasability by design. No single validator can influence the output.
  • 3
    Move makes it safe — the compiler prevents common randomness exploits like test-and-abort by restricting randomness to entry functions only.
  • 4
    The API is minimal but powerfulnew_generator()generate_*() / shuffle(). Security depends on proper design patterns: isolate, commit, don't expose intermediate state.
  • 5
    Use cases are broad — gaming, NFTs, governance, DeFi lotteries, social matching, and more. Sub-second latency makes it viable for real-time applications.
  • 6
    Test deterministically — use random::create_for_testing() for reproducible unit tests, and validate statistical fairness for production contracts.
Questions?
12 / 12