Creating Random Secrets For Blockchain Games
December 29th, 2021

*DISCLAIMER: The method described in this article for generating random secrets **IS FLAWED AND NOT SECURE. *I’m leaving the content up as a learning exercise, but generating random numbers from signatures is not good practice. An attacker could control k, the secure random variable used in generating a signature and create a valid signature until finding one that generates a favorable roll.

Motivation

Many games involve elements of chance such as rolling dice or drawing cards. Often times, the result of this random event is to be held secret by a participant in the game until it is time to reveal the whole thing or a partial component of it. For example, in card games you are dealt a hand and you keep it secret from the opponents until it is time to show your hand or a card of your hand.

There are tools for generating randomness on chain using oracles such as Chainlink VRF, but keeping the result of this randomness secret to a specific participant could be potentially challenging. In this article I will propose a method for generating random secrets that accomplish the following goals.

  • Can be effectively kept secret from other participants for any amount of time until the game mechanics require it to be revealed to continue.
  • Is a good approximate for generating random numbers. That is, the distribution of randomness produced is uniform or follows whatever the desired distribution is.
  • Cannot be cheated by game participants to produce favorable outcomes.
  • Can be used by anyone regardless of cryptography knowledge as long as they have access to a web3 account and can click a button to sign a message.

I believe the following proposal fits these criteria, but I am looking for feedback on the security and viability of this method. It is possible this contains a massive flaw, so if you are stumbling upon this at some later date, there is no guarantee of security.

Proposal

Imagine a game where two players, Alice and Bob, each roll a dice under a cup and keep the result secret from each other. They then take some action (wagering, bluffing, whatever game mechanics) about their two numbers. They reveal them to each other, and the round is over.

On the blockchain, we could program the game as such:

  • Generate a source of randomness from a random number oracle like Chainlink VRF or another secure random number oracle/generator and store this in a mapping.
function generateRandomness() external {
  ...
  randomSeed[msg.sender] = randomness;
}    
  • Sign the randomness or hash of the randomness with the users account/private key from the browser (ethersjs psuedocode)
...
player1RandomSeed = await contract.randomSeed(player1.address);
player1Sig = await player1.signMessage(ethers.utils.arrayify(player1RandomSeed);
  • Hash the signature to convert it to a 256 bit number and take this modulo 6 + 1 to create a dice roll number between 1 and 6.
p1RandomNum = sha256(player1Sig) % 6 + 1

When it is time to reveal the randomness, we can use Open Zeppelin’s ECDSA library and the mathematics of ECC to verify the signature on chain and set the number/do whatever is necessary for our game mechanics.

function revealAndVerify(bytes calldata _sig) external {
  bytes32 signedHash =         ECDSA.toEthSignedMessageHash(randomSeed[msg.sender]);
  require(ECDSA.recover(signedHash, _sig) == msg.sender);
  revealedNum = uint256(sha256(_sig))%6+1;
}

Implementation

An extremely barebones implementation of this is on my Github:

Thanks for reading and appreciate any and all comments or feedback!

Subscribe to Derked
Receive the latest updates directly to your inbox.
Verification
This entry has been permanently stored onchain and signed by its creator.
More from Derked

Skeleton

Skeleton

Skeleton