Rock Paper Scissors

First Flight #38
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: medium
Valid

Insufficient Salt Entropy Requirements Allow Move Prediction in Commit-Reveal Mechanism

Description

The RockPaperScissors contract implements a commit-reveal pattern to prevent players from seeing each other's moves before making their own. However, the contract does not enforce any minimum entropy requirements for the salt values used in the commitment hashes. This allows players to use predictable or weak salt values, potentially making their moves guessable and undermining the security of the game.

Summary

The commit-reveal mechanism is designed to maintain fairness in the game by requiring players to first commit to a move by submitting a hash, then reveal the actual move and salt used to create that hash. The security of this pattern relies on the unpredictability of the salt value. Without requirements for salt entropy, players might use simple, guessable values such as bytes32(0), sequential numbers, or common strings like "salt", making their moves potentially predictable to sophisticated opponents.

Vulnerability Details

// src/RockPaperScissors.sol (Line ~220-230)
function commitMove(uint256 _gameId, bytes32 _commitHash) external {
// No verification of the _commitHash strength or uniqueness
// ...
if (msg.sender == game.playerA) {
require(game.commitA == bytes32(0), "Already committed");
game.commitA = _commitHash;
} else {
require(game.commitB == bytes32(0), "Already committed");
game.commitB = _commitHash;
}
// ...
}
// src/RockPaperScissors.sol (Line ~250)
function revealMove(uint256 _gameId, uint8 _move, bytes32 _salt) external {
// ...
bytes32 commit = keccak256(abi.encodePacked(move, _salt));
// Verification only checks that hash matches, not salt strength
if (msg.sender == game.playerA) {
require(commit == game.commitA, "Hash doesn't match commitment");
// ...
}
// ...
}

The contract never enforces or validates that the salt has sufficient entropy. It only checks that the hash of the move and salt matches the previously committed hash. This means a player could use a weak or predictable salt, potentially allowing an opponent to guess their move by brute-forcing common salt values.

Impact

  1. Compromised game fairness: Players using weak salts may have their moves predicted, giving an unfair advantage to opponents.

  2. Reduced security of commit-reveal: The core security mechanism becomes less effective for players who don't follow good salt generation practices.

  3. Strategy leakage: In multi-turn games, a player who successfully guesses an opponent's move pattern based on weak salts gains a significant advantage.

While this vulnerability requires some sophistication to exploit and isn't guaranteed to work in all cases (depends on player behavior), it fundamentally undermines the commit-reveal security model that the game relies on.

Tools Used

Manual code review

Recommendations

  1. Enforce minimum salt entropy:

    function commitMove(uint256 _gameId, bytes32 _commitHash, bytes32 _saltPreimage) external {
    // Verify salt has sufficient entropy
    require(uint256(_saltPreimage) > 1000000, "Salt too weak");
    // Rest of the function...
    }
  2. Auto-incorporate additional entropy:

    function commitMove(uint256 _gameId, bytes32 _userSalt) external {
    // Add entropy automatically
    bytes32 strengthenedSalt = keccak256(abi.encodePacked(
    _userSalt,
    msg.sender,
    block.timestamp,
    blockhash(block.number - 1)
    ));
    bytes32 _commitHash = keccak256(abi.encodePacked(move, strengthenedSalt));
    // Store commitment...
    }
  3. Document best practices: Provide clear guidelines to users on generating strong, unique salts for each game and move.

Updates

Appeal created

m3dython Lead Judge about 2 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Lack of Salt Uniqueness Enforcement

The contract does not enforce salt uniqueness

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.