# Security Discussion

### Ideas

1. It costs nothing to see what the future randao value would be, and can be calculated sufficiently fast enough. Every block proposer has 1 bit of influence power per slot. A coalition of proposers have 2^n "rolls" where n is the number of malicious proposers in a row. 5 proposers would get 32 roll chances to produce the most desired randao value. The proposer may deliberately refuse to propose an entire block to prevent a RANDAO mix from being updated in a particular slot if they found a beneficial randao value. This costs them the block reward and tx fees they would have received. If they found no useful random value, they can propose blocks like normal and lose nothing. The proposer's 1 bit of influence power lasts only until the first honest RANDAO reveal is made afterwards. This applies also to a string of multiple malicious proposers. One honest block proposal is enough to unbias the RANDAO value even if it was biased during several slots in a row.
2. Proposers can ALSO gain 1 bit of influence power on apps by simply excluding the dice roll in their current slot transaction, and instead forcing the transaction to be included in the next block, thus forcing the RANDAO value to be that of the next block which the proposer knows in advance. This costs them nothing to execute this attack.

* The proposer manipulation threat is neutralized by associating an array of future blocks with a randomness request, and hashing each of their randao values to return a single bytes32 value. The more blocks you include, the more proposers have to be colluding together. For example, say you request a random number derived from 3 block numbers. The oracle gets the 3 randao values and then hashes them to give you a single bytes32 value as the randomness value back to the user.
* If the future blocks are less than 128 blocks (4 epochs) into the future, the malicious user knows exactly who the proposers are going to be, and can simply wait until his validator(s) will be a proposer, and then match the block that he is assigned to when his proposer will propose that block, for 2^m "rolls". Again, if you had an array of 10 future blocks associated with a request, all 10 blocks would have to be controlled/proposed by the malicious actor.
* If the future blocks are more than 128 blocks (4 epochs) into the future, nobody knows who the proposer(s) will be. This separates a malicious user completely from knowing if his malicious proposers will be used or not.
* The ultimate bulwark would be having an array of like 10 block numbers over 128. This requires ALL 10 proposers that are unknown at the time to each collude with each other. If just one was honest, then the random number is not manipulated.

### More Ideas

* Using L2 RANDAO for randomness is not advised because the sequencer can easily forge any RANDAO number. A look up L1 RANDAO from L2 would fix this. An RIP is proposing to support reading L1 block hash and thus L1 RANDAO: <https://github.com/ethereum/RIPs/issues/16>

How far in the future? Well this is where it gets tricky. And also where there is further support required in the EVM. EIP-4399 recommends to use:

* At least four epochs in the future. A new epoch ensures a new set of validators. And in particular four epochs ensures the network will miss at least one proposal further reducing Randao predictability.
* A slot that is not near the beginning of an epoch. Imagine you would use the validator in slot 4 of an epoch. It’s known roughly 6 minutes before the epoch runs who will be the validators in the new epoch. An attacker could use this time to try and bribe or attack these exact 4 validators. He can then gain knowledge of the randomness early, while also having an influence on the randomness, choosing between 2^4 = 16 different outcomes.
* EVM doesn't even currently allow to access the current epoch number. So all we could do is use the block number to approximate it. Remember a slot can be empty and not producing a block. That means if we wait 128 blocks we at least have the guarantee of waiting four full epoch, so let's do that.

EIP:

A list of inputs influencing future randomness on the beacon chain consists of but is not limited to the following items:

* **Accumulated randomness.** A RANDAO mix produced by the beacon chain in the last slot of epoch `N` is the main input to the function defining block proposers in each slot of epoch `N + MIN_SEED_LOOKAHEAD + 1`, i.e. it is the main factor defining future RANDAO revealers.
* **Number of active validators.** A number of active validators throughout an epoch is another input to the block proposer function.
* **Effective balance.** All else being equal, the lower the effective balance of a validator the lower the chance this validator has to be designated as a proposer in a slot.
* **Accidentally missed proposals.** Network conditions and other factors that are resulting in accidentally missed proposals is a source of highly qualitative entropy that impacts RANDAO mixes. Usual rate of missed proposals on the Mainnet is about `1%`.

These inputs may be predictable and malleable on a short range of slots but the longer the attempted lookahead the more entropy is accumulated by the beacon chain.

1. Make your applications rely on the future randomness with a reasonably high lookahead. For example, an application stops accepting bids at the end of epoch `K` and uses a RANDAO mix produced in slot `K + N + ε` to roll the dice, where `N` is a lookahead in epochs and `ε` is a few slots into epoch `N + 1`.
2. At least four epochs of lookahead results in the following outcome:
   * A proposer set of epoch `N + 1` isn’t known at the end of epoch `K` breaking a direct link between bidders and dice rollers
   * A number of active validators is updated at the end of each epoch affecting a set of proposers of next epochs, thus, impacting a RANDAO mix used by the application to roll the dice
   * Due to Mainnet statistics, there is about a `100%` chance for the network to accidentally miss a proposal during this period of time which reduces predictability of a RANDAO mix used to roll the dice.
3. Setting `ε` to a small number, e.g. 2 or 4 slots, gives a third party a little time to gain influence power on the future randomness that is being used to roll the dice. This amount of time is defined by `MIN_SEED_LOOKAHEAD` parameter and is about 6 minutes on the Mainnet.

A reasonably high distance between bidding and rolling the dice attempts to leave low chance for bidders controlling a subset of validators to directly exploit their influence power. Ultimately, this chance depends on the type of the game and on a number of controlled validators. For instance, a chance of a single validator to affect a one-time game is negligible, and becomes bigger for multiple validators in a repeated game scenario.

### Misc

* What happens if the oracle isn't listening to a request and then re-boots? Is that request lost?
* What happens if the fulfillRandomness function reverts?
* What happens if a re-org happens?
* What happens if the oracle system fails to listen and callback from a requestRandomness function? Reconnection logic and Error handling around WebSocket for disconnections and issues.
* What happens if a block that does not exist yet is requested?
* What if multiple consumers request randomness during the same block, can the oracles process multiple requests in a single block properly?
* Is the `mixHash` a truly random number when converted from bytes32 to uint256? Can it be "split up" to use multiple random numbers from 1 request?
* If the oracles are widely used, it may be better approach to have the oracles RLP encode every single block, and then just match the encoded block with the incoming requests. That way they always have them at disposal if needed. We also don't want to be doing redundant computations (imagine two consumers request from the same block).

### Ethereum Update Considerations

If the block header elements change in the next update of Ethereum:

1. The `rlpEncodeHeader()` function in `oracle.js` will need to be changed to match the new elements exactly, so that the recreated block hash still matches the actual block.hash of the block.
2. The `getRandaoFromHeader()` function from `RandaoLib.sol` may need to change if the `randao/mixHash` value is no longer at item 13.

### Different Techniques for Future Blocks

* BN+1, BN+2, BN+3 is just as random as BN+1, BN+3, BN+5 because each proposer is random. No need to do any fancy gaps. Counting in a row works.
* You could do BN+1, BN+2 ... BN+10. The downside is increased gas cost.
* You could wait until BN+128 or beyond. This way nobody knows the proposers and can't organize anything, but takes longer, less gas.
