--- tags: misc --- Improving randomness in Smart Contracts === Nowadays blockchain lottery applications are widely used and common gamblers are fascinated to bet against a number that seems fairly chosen. The problem is that most solutions found in smart-contracts do not always meet the requirements of fairness and are easily manipulated. [This article](https://blog.positive.com/predicting-random-numbers-in-ethereum-smart-contracts-e5358c6b8620) by [@theRaz0r](https://blog.positive.com/@theRaz0r), argues that there are different ways of manipulating the result of a bet and making the PRNG chosen to obtain results in favor. At the end of the article we find a title 'Towards a safe (r) PRNG' that invites us to see different solutions to solve the problem of PRNG in blockchain. One possible solution involves using Bitcoin blocks. The only way to get a Bitcoin block in Ethereum is through an oracle like [BTCRelay](http://btcrelay.org/), but this is an expensive solution implies trusting in the oracle. With the [latest release](https://www.rsk.co/noticia/wasabi-release-v1-0-0/) of RSK blockchain, Wasabi version, we can consult a new native contract that provides us with Bitcoin block headers of the current best chain. This solution is not only decentralized, but also saves the cost of querying an Oracle. The only limitation of this new feature is that you can only request on of the last 4000 blocks headers in the best chain. ### The Challenge The Challenge is to obtain a pseudo-random number that is a fair as possible, and get the number in the same transaction that requires it, so it can be used for low-valued "instant" loteries. > [SDL] Note that under this requirement, we MUST accept that the miner of the block can manipulate the outcome, so for me the requirement of instant value is a no-go. > Therefore I STOP reading and correcting here. ### The solution We are going to use the one of the solutions proposed by the previously named article to choose a bitcoin block and obtain a random number from there. ``` int256 selector = (int256(keccak256(abi.encodePacked(block.timestamp, block.coinbase, block.number)))) % 4000; ``` Well, this is not the best solution to get a number because it has a bias. The maximum block number is 2<sup>256</sup> and 2<sup>256</sup> % 4000 = 3936. That means there are 64 numbers with a little less probability. We are going to improve our selector so that it contemplates this error and obtains an equiprobable result. Then we will use this selector to get two blocks. One of at least 2000 blocks back and another of between 2000 and 4000 blocks back. ``` int256 selector = (int256(keccak256(abi.encodePacked(block.timestamp, block.coinbase, block.number)))) % 2048; ``` Now let's get the two blocks of bitcoin. To do this we will use the native contract interface. After obtaining them we will obtain a hash of the combination of these two, and that will be our random hash. ``` contract IBlockHeaderPrecompiledContract { function getBitcoinHeader(int256 indexBlock) public view returns (bytes memory coinbase); } contract Random { IBlockHeaderPrecompiledContract BitcoinHeader = IBlockHeaderPrecompiledContract(0x0000000000000000000000000000000001000010); function random () public view returns (bytes32) { int256 selector = (int256(keccak256(abi.encodePacked(block.timestamp, block.coinbase, block.number)))) % 2048; bytes memory header1 = BitcoinHeader.getBitcoinHeader(selector); bytes memory header2 = BitcoinHeader.getBitcoinHeader(4000 - selector); return keccak256(abi.encodePacked(header1, header2)); } } ```