SKALE RNG
Each SKALE chain offers a freely accessible Random Number Generator that relies on the inherent randomness of the chain’s consensus mechanism.
Features
-
Provable RNG: The RNG is mathematical provable since it relies on the chain consensus of the chain
-
Fast: Since the SKALE chains consensus is super fast the SKALE RNG inherits that speed.
-
Free of charge: It has no cost for the SKALE developers.
-
Chains: This tool can be used on all SKALE Chains.
Quickstart
-
Import the following npm package:
Terminal window npm i @dirtroad/skale-rng -
Import to your contract the RNG contract from the package:
import "@dirtroad/skale-rng/contracts/RNG.sol"; -
Utilize the function(s) from the RNG contract that suits you better
-
Example:
// SPDX-License-Identifer: MITpragma solidity ^0.8.19;import "@dirtroad/skale-rng/contracts/RNG.sol";contract ExampleRNG is RNG {function getRandomNumber() external returns(uint256){return getRandomNumber();}function getRandomNumberInRange(uint256 minRange, uint256 maxRange) external returns(uint256) {return getNextRandomRange(minRange,maxRange);}}
Theory
Each SKALE Chain includes a built-in random number generator (RNG) that produces a new random number with every block. This RNG is derived from the threshold signature shares of at least 11 out of 16 SKALE nodes supporting the chain.
SKALE chain consensus is asynchronous and leaderless, with blocks signed by a minimum of 11 out of 16 nodes. The signatures are combined in a way that prevents any single node from influencing the final outcome, ensuring the randomness cannot be tampered with or manipulated by any individual entity.
Steps to achieve the random number:
- Signatures for the current block are retrieved.
- The BLAKE3 hash of the signatures is created.
- The resulting hex RNG is presented.
Usage
-
Code to retrieve the random bytes
The code bellow showcases how to use the pre-compiled RNG. It showcases how to access the
getBlockRandom
precompiled at the address0x18
.pragma solidity ^0.8.13;contract A {function getRandom() public view returns (bytes32 addr) {assembly {let freemem := mload(0x40)let start_addr := add(freemem, 0)if iszero(staticcall(gas(), 0x18, 0, 0, start_addr, 32)) {invalid()}addr := mload(freemem)}}} -
Returned random bytes
Running the
getRandom()
function several times returns something similar to the following example. Each different result corresponds to a new block:Terminal window 0:bytes32: addr 0xb01da4532b80108eee3d00d48d6c617869eabfa39acbb58b7fd44e83693315010:bytes32: addr 0x48e4af915a9cf211474c11fec16dd40164a1d6d82dec93a646b4b776261a9fe50:bytes32: addr 0x7d95dd4d341e6bf27ce37e1dc531319daa1dfd75efe4a5f1b1de1f30624251550:bytes32: addr 0x80494d5289618a28ca5ed57803404a4c3b379699d81ae1badf408fb8341c8ef70:bytes32: addr 0xfd66a3c359c1c73f285f881105bb8ef5185cc04d5c8c7360c4386f0673ecc98b0:bytes32: addr 0xb95f1c2be3b13371115b8e6431461a24e960f0bb9881420993528ce68b019f75 -
Converting random bytes into uint256
The random bytes returned by the
getRandom()
function can be handled in different ways depending on the use case. One of the most common cases is generating a simple random uint256.To achieve the random uint256 its only required to cast the random bytes into a uint256:
function getRandomNumber() public view returns (uint256) {return uint256(getRandom());}