I need to add a random number function in my smart contract. Is it best to use Oraclize and e.g. random.org? It's not a lottery which means the random number generation does not require heavy security.
[Ethereum] Random number generation in certain range
contract-designoraclessolidity
Related Solutions
There are a few trade-offs and key points to keep in mind in this area.
Any decision that a user makes which affects the outcome gives that user an unfair advantage. Examples include:
- Using a blockhash, timestamp, or other miner-defined value. Keep in mind that the miner has a choice of whether to publish a block or not, so they could conceivably have one chance at the prize per block they mine.
- Any user-submitted random number. Even if the user pre-commits to a number, they have a choice in whether or not to reveal the number.
Everything that the contract sees, the public sees.
- This means that the number should not be generated until after entry into the lottery has been closed.
The EVM will not outrace a physical computer.
- Any number that the contract generates may be known before the end of that block. Leave time between the generation of the number and its use.
Now for the technique:
Perfectly Decentralized Lottery-Style Non-Malleable Commitment:
- The Casino sets aside a reward for a random number
- Each user generates their own secret random number
N
- Users create their commitment by hashing their
N
with their address:bytes32 hash = sha3(N,msg.sender)
1- note: steps 2 & 3 should be performed locally, in secret
- Users send their hash to the contract, along with ether greater than or equal in value to the value of the random number.2
- Submissions continue for some number of blocks, or until sufficient participants have joined.
Once the submission round has ended, the reveal round begins.
- Each user submits their random number
N
to the contract - The contract verifies that the
sha3(N,msg.sender)
matches the original submission
If the user does not submit a valid N
in time, his deposit is forfeit.
- The
N
s are allXOR
'd together to generate the resulting random number. - This number is used to determine which of the participants receives the reward. (
N % numUsers
)3
Notes and alternatives:
1. The users must concatenate their address to their N
before hashing. Otherwise, another user could simply submit an identical hash, then wait for N
to be revealed, then submit that. N XOR N
equals 0, so this could be used to cancel out all submissions except the attacker's.
2. This is where the trade-offs come in. The last person to reveal their N
has a choice whether to reveal or to not reveal. This essentially gives them a double chance at winning. Enter enough times, and you get a new choice for each entry. Hint: Miners chose the order of transactions in a block. In order to discourage this, users must put up a large security deposit, equal to the value they would gain by manipulating the random number. This could be a problem for many users, especially for large jackpots, even with game-theoretic optimizations.
- A commonly used alternative is a semi-centralized system. This requires the "house" to submit the first hash and last reveal. If the house does not fulfill their duty, everyone's ether is returned. This has issues, such as the house choosing to flake if a jackpot payout is imminent. The idea is that the house's reputation is at stake.
- Note that this essentially centralizes the whole system. One simply needs to take down the house for the whole operation to be shut down. This risk can be reduced by hiring multiple trusted non-players to be the first/last commiters.
- Another trick is to use hired professional third parties to "mine" randomness for you, so that the players need not be bothered with the process.
3. A reward is necessary in order to foster competition among participants. It causes a classic tragedy-of-the-commons/prisoner's dilemma situation. Collusion between participants would allow them to win a large pot and split it among themselves, but if everyone knows what everyone else will submit, they know what they themselves should submit to win the reward. Thus, if the reward is larger than the value of the random number divided by the number of players, then everyone is incentivised to keep their own number a secret in order to have a better shot at the reward. Note that only one of the participants needs to submit a good random number, and the result will be unpredictable.
Examples: Chainlink VRF, RANDAO, The thread where I first thought through this
The organizer can cheat the system by attempting many different addresses, which, when added to your formula Key number + address1 + address2 ... + addressN % 255
as the last address and getting the hash of the block, make this address the winner.
You can think about it this way:
- If your system is secure, there is no way to cheat the system.
- If there is no way to cheat the system, the organizer also cannot cheat the system.
- If there is no way for organizer to cheat the system, then knowing the key number doesn't give you any way to cheat the system. (Otherwise the organizer would cheat the system because he knows the key number)
- If knowing the key number doesn't give you any way to cheat the system, the system is as secure with the key number as without the key number.
- You can get rid of the key number. The formula
Key number + address1 + address2 ... + addressN % 255
is as secure as this oneaddress1 + address2 ... + addressN % 255
. - However, the above formula without the key number is insecure as it's subject to the same attack I described in the beginning. Right before the time when the winner is decided someone can atempt a bunch of addresses and find one that makes him the winner.
- This means that the formula with the key number is insecure also.
As a result we came to a contradiction - we made the assumption that our system is secure in the beginning and at the end concluded that it's insecure. Thus our assumption is not correct.
What you should do instead is split the lottery into 2 phases:
When buying a ticket participants must include with the transaction:
- hash of some random number.
- cost of the ticket.
- some fairly large deposit.
When all tickets are sold (or after some expiration) everyone who bought a ticket in the 1st phase must reveal the secret number.
- When you reveal your secret number you get your deposit back.
- After everyone revealed their secret number, those secret numbers together are used as source of randomness to determine the winner, e.g. concat them and hash.
- If anyone didn't reveal their secret number (or after some expiration), the lottery is cancelled: everyone who revealed their secret numbers can withdraw the price they paid for tickets. Everyone who didn't reveal the secret number loses their deposit and the cost of ticket.
- The deposit provides the incentive to reveal the secret number. The reason why lottery must be cancelled if anyone didn't reveal their secret number is there is a way to cheat the system by not exposing the secret number if it's favorable for the attacker.
In a similar way RANDAO is implemented. Check out the section Additional Rules and Incentives for other things you need to make sure to prevent the possibility of cheating.
In particular, the deposit size summed with the ticket price has to be not lesser than the maximum reward (normally, total amount in the lottery). Any deposit smaller than this will give an opportunity for cheating as explained by lungj here
Best Answer
Responding to comments...
Although you say it does not require heavy security, I feel it is worthwhile to mention that a simple hash function would be predictable. For example,
keccak256(now)
can be calculated, trivially, by another contract that calls into your contract. By working it out ahead of time, it will know, in advance, what your hash function will produce. This works because the time is "now" (same) in both contexts.Setting the predictability concern aside, you would convert a hash function to a uint, e.g.
uint(keccak256(now))
and this will yield a number in the range of 0-2^256-1. You would scale that number to the desired range and precision with divisors and offsets.Hope it helps.
UPDATE
Scaling is a general programming concern not unique to Solidity. We're just going to take a number with known range and adjust it for another range.
pragma solidity 0.5.1;