If I'm building a smart contract that requires random numbers (e.g. games of chance), how do I reliably generate randomness inside a smart contract?
-
1Great and simple question that comes up all the time! I would have thought it comes up in the dice example smart contract on github, but I guess not: github.com/EOSIO/eos/tree/master/contracts/dice– SoleoneCommented May 8, 2018 at 18:30
-
2@Soleone I find that contract hard to follow. A succinct discussion of the issues with generating randomness in smart contracts would go along way to helping new developers understand the issue.– John HaagerCommented May 8, 2018 at 18:32
-
developers.eos.io/eosio-cpp/v1.0.0/docs/…– NatCommented Jul 10, 2018 at 21:19
4 Answers
One method of achieving pseudo-randomness can be accomplished by comparing hashes
// variable to get result from hashing all players hashes and secrets
checksum256 result;
// hash the contents in memory, starting at game.player1 and spanning sizeof(player)*2
bytes sha256( (char *)&game.player1, sizeof(player)*2, &result);
// compares first and second 4 byte chunks in result to determine a winner
int winner = result.hash[1] < result.hash[0] ? 0 : 1;
// report appropriate winner
if( winner ) { report_winner(game.player1); } else { report_winner(game.player2); }
-
1What is the mathematical and theoretical underpinnings for this approach? And where do the hashes and secrets come from in this example? Commented May 8, 2018 at 20:31
-
1This approach seems like it would only work if I am playing a game against other players. How do I deal with generating randomness in a single player game, such as Solitaire? Commented May 8, 2018 at 20:46
-
-
Hi, please format code as code block by indenting it with 4 spaces (or press Ctrl+K or the
{}
button in the editor) Commented May 16, 2018 at 13:54 -
Randomness without risk of anyone "knowing" it requires a three step process:
- both parties commit hashes of secrets hash(secreta) and hash(secretb)
- both parties reveal secrets secreta and secretb
- hash(secreta + secretb)
If either party fails to reveal then the process fails.
-
1What about the possibility of using a future block as seed data to hash, then having the "users" commit to the random transaction before the block is produced? Commented May 13, 2018 at 6:04
-
Did you get any progress doing like that way? Do have any code example of getting the block number? Commented May 17, 2018 at 15:15
-
@JoshuaShope the future still can be controlled and gamed by BP and participant of network. That is not real randomness– hanCommented Jul 24, 2019 at 9:53
EOS Knights implements a random generator, which, at the moment, is MIT-licensed:
// Linear Congruential Generator
class random_gen {
private:
static random_gen instance;
const uint32_t a = 1103515245;
const uint32_t c = 12345;
uint64_t seed = 0;
public:
static random_gen& get_instance(account_name player) {
if (instance.seed == 0) {
instance.seed = current_time() + player;
}
return instance;
}
uint32_t range(uint32_t to) {
checksum256 result;
sha256((char *)&seed, sizeof(seed), &result);
seed = result.hash[1];
seed <<= 32;
seed |= result.hash[0];
return (uint32_t)(seed % to);
// old implementation
// seed = (a * seed + c) % 0x7fffffff;
// return (uint32_t)(seed % to);
}
};
-
now here - github.com/bada-studio/knights_contract/blob/master/knights/…– Raanan WCommented Jun 5, 2019 at 11:23
According to this github issue, using pseudo-random number generation libraries inside the contract would break the consesus because the execution of smart contracts must be deterministic. That means that all nodes executing the same transaction must always get the same output.
Furthermore, you can deterministically derive random numbers from secret data you can pass into the contract. See for example the deterministic way EOSbet generates a random number between 0-100 from a hash which was created from hashing a secret.
-
However, the way EOSbet does it appears to be manipulatable by a malicious user: medium.com/@peckshield/… Commented May 13, 2019 at 5:51