Random Number Generator in Solidity using keccak256
Random numbers are numbers that occur in a sequence with the following two mandatory conditions:
- The values are uniformly distributed over a set interval.
- One cannot predict future values based on past outputs.
Example: In the below example, we have created a contract with a function that will generate a random number in a specific range. Below is the step by step description of the entire process to be followed.
Step 1: Take the instance of block.timestamp, the msg.sender, and an incrementing nonce.
Step 2: “pack” the inputs and use keccak256() to convert into 256-bit hash.
Step 3: Convert that hash to an uint, and then use modulus (%100) to take only the last 2 digits. This will give us a totally random number between 0 and 99.
Solidity
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.9.0; /// @title A contract for demonstrating random number generation in specific range /// @author Jitendra Kumar /// @notice For now, this contract just show how to generate a random number in specific range using keccak256 contract w3wikiRandom { // Initializing the state variable uint randNonce = 0; // Defining a function to generate // a random number function randMod(uint _modulus) external returns(uint) { // increase nonce randNonce++; return uint(keccak256(abi.encodePacked(block.timestamp,msg.sender,randNonce))) % _modulus; } } |
Output:
Step 4: If you do not want to get the random number in specific range than use the below smart contract which returns a large random number.
Solidity
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.9.0; /// @title A contract for demonstrate random number generation /// @author Jitendra Kumar /// @notice For now, this contract just show how to generate a random number in Solidity using keccak256 contract w3wikiRandom { // Initializing the state variable uint randNonce = 0; // Defining a function to generate // a random number function randMod() external returns(uint) { // increase nonce randNonce++; return uint(keccak256(abi.encodePacked(block.timestamp,msg.sender,randNonce))); } } |
Output:
Note: The alias “now” for block.timestamp was removed in the version 0.7.0 , you can use block.timestamp in place of now for the latest solidity version.
Possible attacks with this approach:
In Ethereum, all nodes are trying to solve the problem and verify the transaction. Once a node verifies it, it broadcasts it to the network.
Suppose we create a DApp where we flip a coin where the head is the winning side. We use the above function to predict heads or tails. If I were running a node, I could publish a transaction only to my own node and not share it. I will run the randMod function or the coin flip function until I win, and will only share the transaction after I have won.
One way to solve this would be to use an oracle to access a random number function from outside the Ethereum blockchain. There are other cryptographic algorithms and third party functions that can be utilized, but they are not safe or should be audited.