RNG vs. VRF — The Importance Of True Randomness In Applications
Random Number Generation (RNG) is an important part of applications that require non-deterministic results. This includes encryption systems and gambling software. In this systems, a random number is needed to provide a result that cannot be based on finality, but probability. Encryption algorithms use salt, as a way to add a random element. For gaming, like lotteries or slot machines, random numbers are required so the results cannot be rigged in practice.
The random number is generated within the scope and context of the function in the application from which it was created. It can be used by other applications, but once again the number is coming from that one application. The number cannot be verified as truly random, other than what the application provides. At this point it becomes acceptable as random because that is the expectation.
Casinos have some form of validation and certification of randomness. They use a pseudo random number generator, which is basically created using a seed number with the RNG algorithm. Third party companies are hired by casinos to test the software, like that used in slot machines or where a teller is not required. It can be rigged if the system is under their control.
In the case of gaming software used in online gambling, that may not usually be the case. There is no authority that verifies the numbers are generated randomly. Users just trust the system works, but have no actual way to verify that numbers are being generated randomly.
Writing Random Functions
One way to create randomness is to begin with a seed number. It can be any number of course, and there are creative ways to select it. We can look at a clock and use the first number we see. Let us say that we will use 3 as that seed number.
X = 3
Now we can create an equation that uses a multiplier z, an increment of i which is how much we want to increment the number by, and a modulus m, and n = 1 … infinity. This creates a linear relationship of the form:
We can then set the following conditions:
- m > 0 : must be a positive number greater than 0
- 0 < z < m : the multiplier is positive but less than the modulus
- 0 ≤ i < m : the increment is non-negative but less than the modulus
- 0 ≤ X < m : the seed is non-negative but less than the modulus
Creating your own RNG is difficult and prone to errors. This is like trying to roll your own encryption algorithm. When pushed to a production system it can have problems later on. Unless you have an advanced degree or are very good in devising algorithms, avoid that because there is an easier way.
We can use library modules that contain functions that have RNG available. They are most likely pseudo RNG, but they can generate a non-determined result without having to create one. Developers can then use these functions for their own applications.
Basic RNG
In Javascript (JS) you can use the Math.random() method to return a random number from 0 (inclusive) up to but not including 1 (exclusive). The following code will generate a random number that is > 0 but < 1.
let x = Math.random();>x
0.12872161410107563
This is a simple function for generating a random number. This can be used to add an element of randomness to a result. For example:
let y = Math.floor((Math.random() * 100) + 1);>y
85
In the function, we assign a variable y a random generated value between 1 and 100. The function returns the result 85.
Simple random generation works fine. When the stakes are higher, RNG will require more validation and verification. That is why independent companies do the testing for applications that use RNG.
Enter VRF
The blockchain era introduces us to VRF (Verifiable Random Function) for random number generation. What makes it different from traditional RNG is that it uses a decentralized network of nodes to verify that a number is indeed randomly generated.
The verifiers operate in a blockchain network, where they must agree on the random number using a consensus mechanism. VRF can be used by oracles, which feed information to smart contract platforms like that used in the Ethereum network (good example of an oracle is Chainlink). A gaming platform can use VRF numbers that feed into a smart contract used in a gaming application.
In the case of Chainlink, a proof of random generation is created. The proof is published and verified on-chain by verifiers. This ensures that the result cannot be tampered or modified, assuring its randomness. We present a quick introduction to VRF in the following example, but not a thorough breakdown on how it works (consult the Chainlink documentation for more).
Here is an example Solidity code (from Chainlink) that implements VRF (this can be tested with a subscription ID and on the Rinkeby testnet which requires test ETH tokens):
// SPDX-License-Identifier: MIT
// An example of a consumer contract that relies on a subscription for funding.pragma solidity ^0.8.7;import "@chainlink/contracts/src/v0.8/interfaces/LinkTokenInterface.sol";
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";contract VRFv2Consumer is VRFConsumerBaseV2 {
VRFCoordinatorV2Interface COORDINATOR;
LinkTokenInterface LINKTOKEN;// Your subscription ID.
uint64 s_subscriptionId;// Rinkeby coordinator. For other networks,
// see https://docs.chain.link/docs/vrf-contracts/#configurations
address vrfCoordinator = 0x6168499c0cFfCaCD319c818142124B7A15E857ab;// Rinkeby LINK token contract. For other networks,
// see https://docs.chain.link/docs/vrf-contracts/#configurations
address link = 0x01BE23585060835E02B77ef475b0Cc51aA1e0709;// The gas lane to use, which specifies the maximum gas price to bump to.
// For a list of available gas lanes on each network,
// see https://docs.chain.link/docs/vrf-contracts/#configurations
bytes32 keyHash = 0xd89b2bf150e3b9e13446986e571fb9cab24b13cea0a43ea20a6049a85cc807cc;// Depends on the number of requested values that you want sent to the
// fulfillRandomWords() function. Storing each word costs about 20,000 gas,
// so 100,000 is a safe default for this example contract. Test and adjust
// this limit based on the network that you select, the size of the request,
// and the processing of the callback request in the fulfillRandomWords()
// function. uint32 callbackGasLimit = 100000;// The default is 3, but you can set this higher.
uint16 requestConfirmations = 3;// For this example, retrieve 2 random values in one request.
// Cannot exceed VRFCoordinatorV2.MAX_NUM_WORDS.
uint32 numWords = 2; uint256[] public s_randomWords;
uint256 public s_requestId;
address s_owner;constructor(uint64 subscriptionId) VRFConsumerBaseV2(vrfCoordinator) {
COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator);
LINKTOKEN = LinkTokenInterface(link);
s_owner = msg.sender;
s_subscriptionId = subscriptionId;
}// Assumes the subscription is funded sufficiently.
function requestRandomWords() external onlyOwner {
// Will revert if subscription is not set and funded.
s_requestId = COORDINATOR.requestRandomWords(
keyHash,
s_subscriptionId,
requestConfirmations,
callbackGasLimit,
numWords
);
}
function fulfillRandomWords(
uint256, /* requestId */
uint256[] memory randomWords
) internal override {
s_randomWords = randomWords;
}modifier onlyOwner() {
require(msg.sender == s_owner);
_;
}
}
If you are going to run this code, when you deploy it you must enter your subscription ID from Chainlink.
Use the requestRandomWords() function to get random values from VRF and then receive those values and store them in the s_randomWords array.
Note: After deploying this test contract, you may want to clean up your subscription ID from Chainlink. Follow the instructions on their VRF page.
Synopsis
There is now a way to verify RNG outside of a function, without a trusted third party to validate. Using VRF uses a decentralized network of nodes called verifiers to validate the random number and verify it on a blockchain. The results are mathematically verifiable and then recorded for the public to see.
Verifiers who test the result are also not part of the same organization or do not have any affiliation with each other, so their results should be independent from one another by design. This is ideal for automated systems, that require the use of random numbers which can be verified from outside of the system in a trustless environment.
The thing is true randomness is really important. This can be generated based on physical events that occur in nature. This can be tied to producing the result for more accuracy and precision. Take for example the weather as a truly random event. Whatever numbers you can derive from the phenomenon can generate the element for randomness. There are other things that randomness can be based on, but at least it is not pseudo generated.