This EIP proposes a modification to the data signed by a block proposer for the randao_reveal
. The current randao_reveal
is a BLS signature over the current epoch number, which is predictable. This proposal incorporates the RANDAO mix of the previous epoch and the current slot number into the signed data. This change transforms the randao_reveal
into a Verifiable Random Function (VRF), making it unpredictable across epochs even for the revealer itself. This enhancement strengthens Ethereum's native randomness source and enables protocols such as Single Secret Leader Election (SSLE).
This change creates a secure, per-slot VRF output from the proposer, with several benefits:
Using a BLS signature as a VRF is sound under the Computational Diffie-Hellman (CDH) assumption, rather than Decisional Diffie-Hellman. The BLS verification process inherently proves the correctness of the VRF output without requiring a separate proof.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
The gist of the change is in process_randao
, which now uses the RANDAO mix of the previous epoch and the current slot number to seed the randao_reveal
signature. We are introducing a new SSZ-serializable container called RandaoRevealSeed
containing that information.
A new SSZ Container
is introduced to serve as the message for the randao_reveal
signature post-fork.
class RandaoRevealSeed(Container):
previous_mix: Bytes32 # last RANDAO mix of the previous epoch
slot: Slot # current slot number
process_randao
The block processing function process_randao
in the beacon state transition is modified.
Let FORK_EPOCH
be the epoch of the network upgrade.
The logic for verifying body.randao_reveal
within process_randao
is updated as follows:
def process_randao(state: BeaconState, body: BeaconBlockBody) -> None:
epoch = get_current_epoch(state)
previous_epoch = get_previous_epoch(state)
previous_mix = get_randao_mix(state, previous_epoch)
# Verify RANDAO reveal
proposer = state.validators[get_beacon_proposer_index(state)]
if epoch < FORK_EPOCH:
signing_root = compute_signing_root(epoch, get_domain(state, DOMAIN_RANDAO))
else:
seed = RandaoRevealSeed(previous_mix, state.slot)
signing_root = compute_signing_root(seed, get_domain(state, DOMAIN_RANDAO))
assert bls.Verify(proposer.pubkey, signing_root, body.randao_reveal)
# Mix in RANDAO reveal
mix = xor(get_randao_mix(state, epoch), hash(body.randao_reveal))
state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR] = mix
The randao_reveal
is effectively transformed into VRF(sk, message)
where the message
is the SSZ serialization of the RandaoRevealSeed
container.
previous_mix
: Including the RANDAO mix from the previous epoch (previous_mix
) is the core of this proposal. Since the previous epoch's final mix is not known until the end of that epoch, a proposer cannot compute their randao_reveal
of future epochs, beforehand.slot
: Including the current slot
number ensures that the randao_reveal
is unique for each slot and unpredictable to other validators. Without it, a validator chosen to propose multiple times in an epoch would produce the same reveal, which is undesirable for protocols that require unique randomness per instance, such as SSLE.We considered adding the latest RANDAO mix rather than that from the previous epoch so that we could obtain per-slot unpredictability, but that would cause fork ambiguity in the future if randao_reveal
is used to implement SSLE.
This EIP introduces a backwards-incompatible change to the consensus rules and MUST be activated as part of a scheduled network upgrade (i.e., a hard fork).
Blocks produced after the FORK_EPOCH
that do not use the new RandaoRevealSeed
structure for the randao_reveal
signature SHALL be considered invalid. Pre-fork blocks remain valid under the old rules.
The security of the BLS signature scheme as a VRF relies on the Computational Diffie-Hellman (CDH) assumption in the target group. This is a standard cryptographic assumption. The output of the signature (a uniformly distributed G2 point in compressed format) can be treated as a pseudorandom number.
The value of randao_reveal
is deterministic and cannot be manipulated. It will be verified with the public BLS key of the validator, so it must be calculated using the corresponding private key. There are no grindable elements.
Including the slot number is superfluous at the moment because it does not make the VRF slot-by-slot unpredictable to the revealer, only to other validators. But it will become critical in the future if and when we decide to implement secret proposer election and/or EIP-7956.
Copyright and related rights waived via CC0.