HACK ANALYSIS 3 min read

Weak block-based PRNG in Solidity


Weak block-based PRNG in Solidity

The Need for Pseudo-Random Number Generators

Random number generators are used extensively in all kinds of applications such as gambling, deciding winners in games, getting random seeds for test data, etc.
However, generating random numbers on Ethereum is a challenging task due to its deterministic nature and the fact that each time a function is called in a contract, it must get validated by all the other nodes and miners on the network. 
Every algorithm, including Solidity, is incapable of generating true random numbers; therefore, there’s a heavy reliance on the pseudorandom factor. Moreover, each calculation in Solidity costs Gas making it difficult to use complex and long calculations for random number generation.

Insecure Mechanisms to Create Random Numbers in Solidity

Random numbers in solidity can be created using various predefined methods related to the block such as:

  • block.timestamp (now) — Tells us the current block timestamp as seconds since the Unix epoch
  • blockhash(uint blockNumber) — Tells us the hash of the given block, only works for 256 most recent, excluding current, blocks
  • block.difficulty — Tells us the difficulty of the current block
  • block.number — Tells us the current block number
  • block.coinbase — Tells us the address of the miner for the current block

Developers should never rely on values derived from the mined block since they can be easily assigned by the miners while mining the block and confirming the transactions, thus, manipulating the function logic depending on the random number generator.

PRNG Attacks in the Wild (CVE-2018–14715)

Cryptogs, a game of pogs, on the Ethereum blockchain, used blockhash(uint blockNumber)to decide the winner. 
They had no check to see if the blockNumberis too old and The Blockhash function returned 0 when the blockNumber was older than 256 blocks from the current block’s block.number . 
This allowed the attacker to manipulate the logic of the contract, making themselves first in the order and withdrawing all the pogs before other users.

Suggestions and Best Practices

  1. Using oracles (Oraclize) as external sources of randomness. Care should be taken while trusting the Oracle. Multiple Oracles can also be used.
  2. Using Commitment Schemes — A cryptographic primitive that uses a commit-reveal approach can be followed. It also has wide applications in coin flipping, zero-knowledge proofs, and secure computation. Eg: RANDAO.
  3. Chainlink VRF — It is a provably fair and verifiable random number generator (RNG) that enables smart contracts to access random values without compromising security or usability.
  4. The Signidice Algorithm — Suitable for PRNG in applications involving two parties using cryptographic signatures.
  5. Bitcoin Block Hashes — Oracles like BTCRelay can be used which act as a bridge between Ethereum and Bitcoin. Contracts on Ethereum can request future block hashes from the Bitcoin Blockchain as a source of entropy. It should be noted that this approach is not safe against the miner incentive problem and should be implemented with caution.

Our cloud-based Smart Contract security scanner — SoldityScan, detects the use of block variables-based weak pseudo-random number generators. It also allows developers and auditors to publish reports after bug fixing. Signup for a free trial at https://solidityscan.com/signup