3

I've read through this thread and this thread and they offer a lot of interesting techniques, but what's the minimal code snippet for the currently accepted method of generating a random number in solidity?

This isn't a super high security need, approximates and PRNG solutions are fine for my use-case, so long as it spans any of the values of uint with (not lottery level, but roughly) equal probability.

2
  • 1
    What is the application here? Would it matter to you if miners could choose the number arbitrarily? Is there an incentive for people to manipulate the number? Commented Nov 15, 2018 at 3:42
  • Right, arbitrarily absolutely acceptable. I'm just trying to provide a helper function that produces a suggestion for something that can also be requested explicitly. I will probably end up doing this off-chain prior, but I am still working up to understanding that... :/ Commented Nov 15, 2018 at 3:47

2 Answers 2

2

It feels like in your situation, simply hashing some unique value would be a good pseudo-random number generator.

A snippet like this:

pragma solidity ^0.4.24;

contract Test {

    uint nonce = 0;

    function PRNG() public returns(uint) {
        nonce += 1;
        return uint(keccak256(abi.encodePacked(nonce, msg.sender, blockhash(block.number - 1))));
    }
}

The main concern here would be that someone with enough computational power may be able to generate transactions and blocks which control this random number. For example, this user may be able to generate a transactions until they get the random number they want, and then they would need to mine that block and publish it before anyone else changes something. However, this would be a costly attack, so there would need to be something to gain from doing so.

Here is what the solidity documentation has to say:

Do not rely on block.timestamp, now and blockhash as a source of randomness, unless you know what you are doing.

Both the timestamp and the block hash can be influenced by miners to some degree. Bad actors in the mining community can for example run a casino payout function on a chosen hash and just retry a different hash if they did not receive any money.

In my snippet, we also include a nonce and a msg.sender to try and make it harder for such malicious actors. In this situation, each sender would have a unique set of hashes generated for their account, and the nonce is a global variable which means it can be influenced by other people, making it harder to control by the malicious individual.

3
  • It is misguided to try to avoid influence in this manner. In particular, msg.sender is arbitrarily manipulable, so the whole thing is arbitrarily manipulable. Either accept that the number is whatever an interested party would like, or do randomness the correct way. Commented Nov 15, 2018 at 4:06
  • Is that true though? I agree, msg.sender should probably not be included, but in your answer, you omitted blockhash() which allows people to determine all random numbers that will ever be generated by this function. In the case where we introduce blockhash(), it is unknown what the value will be in the far future, and thus not possible to predict the outcome of the random number generator far ahead of time (more than the average block production time). Commented Nov 15, 2018 at 4:47
  • 1
    If you include blockhash, you are vulnerable to manipulation from dropped blocks. I guess my main point is that any naive solution (including any one-phase protocol) is inherently insecure, so you should make this fact as clear as possible. OP stated that they want no guarantees, so I give no guarantees Commented Nov 15, 2018 at 15:02
1

While Shawn is on the right track, I think that is very important to make a clear distinction between arbitrarily manipulable randomness used for convenience and pseudorandomness with guarantees on the difficulty of manipulation. In the first case, the easiest way is

pragma solidity ^0.4.24;

contract Random {

    uint nonce = 0;

    function random() public returns(uint) {
        nonce += 1;
        return uint(keccak256(abi.encodePacked(nonce)));
    }
}

Trying to add obfuscating variables like block number or msg.sender makes it unclear to the reader that this randomness source is predictable and not to be trusted. Adding other variables in general only makes tampering easier, and may convince a reader that the number is more random than it truly is.

In the latter case, the real answer is that this is a very difficult problem and you will need to formally specify the required properties and then prove that your solution satisfies these.

Not the answer you're looking for? Browse other questions tagged or ask your own question.