0
uint private seed;

// starts from 0 (including) to _length number (excluding)
function random(uint _length) private returns(uint) {
    seed = seed.add(block.timestamp.add(uint(msg.sender)));
    return uint(sha256(toBytes(uint(blockhash(block.number - 1)) + seed))) % _length;
}

function toBytes(uint256 x) private pure returns(bytes b) {
    b = new bytes(32);
    assembly {
        mstore(add(b, 32), x)
    }
}

How safe is this to be used for generating a random number?

I have a seed in there based on the previous generated random number which would make it pretty much impossible to track.

will this be expensive in terms of gas usage?

3
  • As a rule of thumb: if there's a big enough monetary gain all such preudo-random number generators will be cracked Commented Nov 11, 2019 at 10:20
  • @LauriPeltonen i can't see how it could be cracked, there is no way to find the seed, it's just based the previous generated number which that previous number is also based on it previous and so on. enlighten me if i'm missing something here
    – Adrin
    Commented Nov 11, 2019 at 10:27
  • From security point of view the seed is rather pointless if used across different transactions because then everyone sees the seed and they can just factor that data in their abuse. So if an attacker wants to game the system they influence some of the input data in a way which benefits them - factoring in all the rest of the pseudo-random input such as the seed. Commented Nov 11, 2019 at 10:38

2 Answers 2

1

How safe is this to be used for generating a random number?

Close to zero.

  • As answered by Mikhail: miners can manipulate it
  • It's still low safety without considering miners. There isn't much randomness in the implementation.
    1. Given a block and a length, the result is deterministic.
    2. Therefore, if the return result is used for activities like lottery, and suppose the usage is something like
function try_my_luck() {
    r=random(some_len)
    if r < 0.01 {
       award(100Eth)
    }
}
  1. Then because it's doesn't cost too much gas to call your random function, a straightforward attack is
function attack() {
    r = random(some_len)
    if r >= 0.01 {
        revert; // will be back and try another block
    }
    for i = 0; i < 100000; i++ {
        try_my_luck()
    }
}
  1. A real-life example is here.

[Edit] One might argue that it's pretty hard to enumerate the combination of

  • length
  • sender address
  • block time
  • block number

However,

  • length - it probably is the length of some array in your contract
  • sender address - easy to generate and retry
  • block time - only in seconds precision, easy to guess
  • block number - pretty much deterministic

When then incentive is great enough, it's not that difficult to do off-line computation to generate an optimal combination of these values.

0

This random number generator could easily be manipulated by miners. When constructing next block to be mined, the miner may freely choose set of transactions to be included, and may place the transactions in arbitrary order. Also, the miner may adjust block timestamp and probably some other block attributes. By playing with these possibilities, the miner may construct many different candidate blocks with different hashes, and they proceed with the candidate where generated random number is good for the miner.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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