Ethereum is a deterministic environment so solidity language does not have a built-in source of entropy that can be used to generate random numbers. When a block is validated, it produces an unguessable hash.
Although the block hash is guaranted to be lower than the block difficulty , the exact number is unknown until the block is validated.
Unfortunately, the block hash of the current block is unavailable until after the block is validated , so we have to use the blockhash from the parent block.
Below snippet shows that we can access the most recent blockhash in our contracts with the block.blockhash(block.number -1) expression :
This function hashes the parent blockhash with a user-generated seed and then takes the integer representation of the bytes. Changing the seed will change the output. This gives a number between 0 & 2^256 that can be used with a modulus to get a smaller range of numbers.
Although the block Hash is guaranteed to be lower than the block Difficulty, the exact number is unknown until the block is validated in the context of POS.
As a simple attack, the random number can be maliciously guessed by an hacker by copying and pasting our random function into their contract and making sure it gets validated in the same block as a transaction that uses our random function.
block.blockhash, or anything associated with blocks to get a random number into your app opens up your code to exploits.
Knowing this flaw, if you need to secure large quantities of ether with a random number, a superior and far more secure way is to implement Chainlink Verifiable Random Function in your smart contract logic.
2022's web3 developers chose off-chain solutions, where a ramdomly verifiable number is generated off-chain and then re-introduced on-chain.
Nevertheless, without cryptographic proof of the impartiality of the off-chain value, the result can be manipulated by the transport layer who introduces back this value on-chain. Moreover, users of any application engeneering this process are forced to believe that the random value is producted impartialy and that it has been re-introduced on-chain without being modified.
To face those potentiel risks, Chainlink VRF offers transparency & cryptographic truth that each result is generated in a fair manner.
In a nutshell, a smart contract ask for a random feature by providing a seed to Chainlink. The said seed is used to generate a random number, who is then sent to the smart contract.
Each oracle uses its own intrinsic secret key when the random number is created. When the result is broadcasted on-chain with a proof, it is verified with the help of the public key of the oracle and the seed of the app.
By relying on largely accepted abilities of signature verification & blockchain proofs, this enabled smart contracts to solely consume random datas that have been verified by the same environment on-chain that executes the contract itself.
To show concrete example, PoolTogether , no-loss lottery on Ethereum, implements VRF to provide warranty to theirs users about the random character of their app.
As a conclusion, I would suggest to use Chainlink VRF to build reliable smart contracts for decentralized apps that rely on unpredictable outcomes such as :
Building blockchains games and NFTs.
Random assignment of duties and ressources in the real world: for example, randomly assigning judges to cases.
Choosing a representative sample for consensus mechanisms.
Shares and comments welcome.