Onchain applications increasingly depend on randomness: lotteries, gaming, NFT minting, reward distribution, treasury auctions, and governance experiments. Yet randomness on a blockchain is deceptively difficult. Unlike traditional software, smart contracts cannot simply call a standard library like Math.random() and trust the result. Every node in the network must be able to reproduce the same execution, which makes true randomness both scarce and fragile.
This post outlines the core challenges in generating randomness onchain, the approaches teams use today, and a short Solidity example that highlights the most important sections of a practical implementation.
1. Why Onchain Randomness Is So Difficult
The first problem is architectural: blockchains are deterministic by design. If a contract asks for a random value, every validator or node must eventually agree on the same outcome. That means the random value cannot be generated from a single private source, because it would be impossible to prove or reproduce in a decentralized way without leaking the source.
That creates three major challenges:
- No native private randomness
- A blockchain cannot rely on a local CPU entropy source without breaking consensus.
- Any value that is generated inside a contract is predictable to the network if the inputs are known.
- MEV and manipulation risk
- Miners, validators, or block builders can influence transaction ordering.
- In some cases, they can bias outcomes by choosing when to reveal a transaction or by observing pending state.
- Trust assumptions and liveness
- Some systems rely on a trusted third party to provide randomness.
- Others rely on a decentralized network, but then must accept tradeoffs around latency, cost, or complexity.
These issues are why “randomness” is often the most underestimated piece of an onchain design.
2. The Main Approaches Teams Use Today
A. Commit-Reveal Schemes
One of the oldest patterns is commit-reveal. Participants first commit to a secret number, then later reveal it. The contract checks that the reveal matches the commitment, and the final randomness is derived from all submitted values.
Why it is used:
- Simple to understand.
- Works well for games and multi-party protocols.
- Does not require an external oracle.
Why it fails in practice:
- Users can abort after seeing others reveal.
- Last mover advantage can distort fairness.
- It is vulnerable to griefing and coordination issues.
This approach is useful for certain applications, but it is not enough for high-stakes or production-grade randomness.
B. Verifiable Random Functions (VRFs)
A more robust approach is to use a Verifiable Random Function. A VRF generates a pseudorandom output and a cryptographic proof that anyone can verify. The output is unpredictable until the provider reveals it, but the proof proves the result was generated correctly.
This is the approach used by many modern oracle networks, including Chainlink VRF and similar systems.
Why teams like it:
- Strong cryptographic verifiability.
- Better resistance to manipulation than naive onchain generation.
- Easier to integrate into smart contracts.
Tradeoffs:
- It still depends on an external provider or committee.
- It introduces cost and latency.
- The consumer must trust the provider’s setup and economics.
C. Distributed Randomness Beacons
Another approach is a distributed randomness beacon, where a set of independent participants collectively produce a random value. Systems such as drand use threshold cryptography to produce a public, continuously evolving random stream.
Why it is compelling:
- No single party controls the output.
- Strong decentralization properties.
- Stronger fairness story than one-off oracle-based randomness.
Tradeoffs:
- More infrastructure complexity.
- Not always ideal for application-specific use cases.
- Requires careful handling of liveness and committee participation.
D. Threshold Signatures and MPC-Based Randomness
In some protocols, randomness is produced by a threshold signature or MPC process. Multiple parties contribute partial randomness, and the final output is only reconstructible when enough parties participate.
This is often seen in institutional or permissioned systems, where the security model is more controlled and the participants are known in advance.
3. What “Good” Randomness Usually Means
For most teams, the target is not perfect randomness in a mathematical sense. It is a practical mix of:
- Unpredictability before reveal.
- Bias resistance after generation.
- Verifiability for downstream users.
- Liveness so the system still works even if some participants are offline.
- Cost efficiency enough to be sustainable onchain.
In practice, the best systems balance these properties without pretending to be magic.
4. A Brief Solidity Example: VRF-Based Randomness
Below is a minimal example showing the main sections of a VRF consumer contract. The pattern is the same across many oracle providers:
- Request randomness.
- Receive a callback with the random words.
- Use the result inside the application logic.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
contract FairDraw is VRFConsumerBaseV2 {
VRFCoordinatorV2Interface private immutable COORDINATOR;
uint64 private immutable subscriptionId;
bytes32 private immutable keyHash;
uint256 public requestId;
uint256 public randomValue;
event RandomRequested(uint256 indexed requestId, address requester);
event RandomFulfilled(uint256 indexed requestId, uint256 value);
constructor(address coordinator, uint64 _subscriptionId, bytes32 _keyHash)
VRFConsumerBaseV2(coordinator)
{
COORDINATOR = VRFCoordinatorV2Interface(coordinator);
subscriptionId = _subscriptionId;
keyHash = _keyHash;
}
function requestRandomness() external returns (uint256) {
requestId = COORDINATOR.requestRandomWords(
keyHash,
subscriptionId,
3, // request confirmations
100000, // callback gas limit
1 // number of random words
);
emit RandomRequested(requestId, msg.sender);
return requestId;
}
function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords)
internal
override
{
randomValue = _randomWords[0];
emit RandomFulfilled(_requestId, randomValue);
}
}The important parts are:
- The request step: the contract asks for randomness from a coordinator.
- The callback step: the oracle returns the random words to the contract.
- The application logic: the contract consumes the result as a trusted input for the next state transition.
5. Practical Guidance for Builders
If you are building a real product, the right choice depends on the use case:
- Games and low-stakes applications: commit-reveal may be sufficient, though it is weaker than modern alternatives.
- High-value or user-facing systems: VRF-style solutions are usually the safest default.
- Institutional or permissioned systems: threshold signatures or MPC may offer the right balance of trust and control.
- Public infrastructure: distributed randomness beacons are attractive when decentralization matters more than convenience.
The key lesson is that there is no universally “correct” source of randomness. The best design depends on your threat model, your users, and the level of trust you are willing to place in the infrastructure layer.
Conclusion
Onchain randomness remains one of the hardest problems in blockchain engineering because it sits at the intersection of consensus, cryptography, economics, and user experience. The most widely adopted solutions today are not “magic” sources of randomness; they are carefully designed systems that make unpredictability, verifiability, and bias resistance measurable.
For most teams, the path forward is not to invent a new randomness primitive from scratch, but to choose a proven mechanism that fits the product’s security model and operational constraints.

