EIP.tools

EIP.tools

⚠️ DraftStandards Track: Core

EIP-8384: Deterministic sync committee aggregators

Select sync committee aggregators as a function of beacon state

Authors
Created2026-08-19
Discussion Linkhttps://ethereum-magicians.org/t/eip-8384-deterministic-sync-committee-aggregators/29465

Markdown

https://raw.githubusercontent.com/ethereum/EIPs/re...
Pull Request#12207PR open

EIP-GPT summary

Contents
AbstractMotivationSpecificationNew constantsNew getsyncaggregatorpubkeysModified issynccommitteeaggregatorModified ContributionAndProofModified gossip validationRemovedRationalePrecedenceSeeding from getseedPrefix of a shufflingReduced CostBackwards CompatibilitySecurity ConsiderationsLoss of aggregator secrecyRANDAO grindingCopyright

Abstract

Sync committee aggregators are currently self-selected, so each member signs a SyncAggregatorSelectionData under DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF and aggregates if the hash of that signature falls below a threshold.

This EIP replaces the VRF-like lottery with get_sync_aggregator_pubkeys, a pure function of beacon state, and removes the selection proof from ContributionAndProof.

The main feature that we lose is lookahead aggregator privacy, however we don't have this for includers and proposers; roles that actually affect consensus.

Motivation

Secrecy of the aggregator set until publication is the main property that the current BLS signature contribution proof is giving us.

Using BLS however means two things:

  • Post-quantum transition: self-selection relies on BLS signatures being unique, so that a validator cannot retry into a win. Hash-based schemes using target-sum encoding (leanSig) are not unique since the signer grinds a randomizer to hit the target sum, so many valid signatures exist per message and a validator could grind itself into the aggregator set.

  • Attributable non-performance: A validator that lost the lottery is today indistinguishable from one that won and stayed silent, so aggregation duty cannot be monitored or penalised (if we wanted to do this).

The more important aspect here is post quantum and we solve this by having a deterministic selection since that does not require key material.

Specification

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.

New constants

NameValue
DOMAIN_SYNC_COMMITTEE_AGGREGATORDomainType('0x12000000')

New get_sync_aggregator_pubkeys

def get_sync_aggregator_pubkeys(state: BeaconState,
                                slot: Slot,
                                subcommittee_index: uint64) -> Sequence[BLSPubkey]:
    """
    Return the aggregator pubkeys for ``subcommittee_index`` at ``slot``.
    """
    seed = hash(
        get_seed(state, compute_epoch_at_slot(slot), DOMAIN_SYNC_COMMITTEE_AGGREGATOR)
        + uint_to_bytes(slot)
        + uint_to_bytes(subcommittee_index)
    )
    subcommittee = get_sync_subcommittee_pubkeys(state, subcommittee_index)
    # Clamped so that small presets, where the subcommittee is smaller than the
    # target, select the whole subcommittee rather than exceeding its bounds
    count = min(TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE, uint64(len(subcommittee)))
    return [
        subcommittee[compute_shuffled_index(uint64(i), uint64(len(subcommittee)), seed)]
        for i in range(count)
    ]
  • The seed MUST be derived via get_seed as shown, not from get_randao_mix(state, get_current_epoch(state)).

  • get_sync_subcommittee_pubkeys is unchanged, including its rule for resolving current_sync_committee against next_sync_committee at a period boundary.

  • Similar to today, aggregating is based on honest validator behavior rather than a consensus obligation, so there is no penalty for an aggregator that stays silent.

Modified is_sync_committee_aggregator

def is_sync_committee_aggregator(state: BeaconState,
                                 slot: Slot,
                                 subcommittee_index: uint64,
                                 pubkey: BLSPubkey) -> bool:
    return pubkey in get_sync_aggregator_pubkeys(state, slot, subcommittee_index)

Modified ContributionAndProof

class ContributionAndProof(Container):
    aggregator_index: ValidatorIndex
    contribution: SyncCommitteeContribution

Modified gossip validation

On the sync_committee_contribution_and_proof topic, the condition that verified selection_proof as a signature over SyncAggregatorSelectionData is removed, and we have:

  • [REJECT] is_sync_committee_aggregator(state, contribution.slot, contribution.subcommittee_index, aggregator_pubkey), where aggregator_pubkey is state.validators[contribution_and_proof.aggregator_index].pubkey.

Removed

  • DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF
  • SyncAggregatorSelectionData
  • get_sync_committee_selection_proof
  • the selection_proof field of ContributionAndProof

TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE is retained, with its meaning changed from an expected count to an exact count.

Rationale

Precedence

EIP-7805 is the closest analogue, it doesn't have lookahead protection. This proposal does the same for a duty that is not consensus critical.

Seeding from get_seed

First, gossip validation for this topic runs against the head state, so the seed must not depend on recent blocks.

process_randao mixes each block's reveal into randao_mixes[current_epoch], so get_randao_mix(state, get_current_epoch(state)) changes with every block. Two honest nodes that momentarily disagree about the head, which happens routinely at every slot, would derive different aggregator sets and reject each other's otherwise valid contributions.

get_seed avoids this since it reads randao_mixes[epoch - MIN_SEED_LOOKAHEAD - 1], and the protocol stops writing that entry once its epoch ends. Within epoch e the seed therefore depends only on blocks up to the final slot of epoch e - 2. Under normal finalization those blocks are at least justified, so in order for two nodes to disagree, they would need to have forked off at a justified checkpoint.

Note: slot is in the seed because get_seed changes every epoch, and we need a new set of aggregators on every slot.

Prefix of a shuffling

compute_shuffled_index is a bijection over the subcommittee, so a fixed-size prefix of it is a sample without replacement.

Note: compute_committee derives every beacon committee the same way.

Reduced Cost

As a secondary benefit, removing the selection proof also removes one BLS verification per contribution message during gossip validation, and 96 bytes from each message.

Backwards Compatibility

This is a consensus change requiring a hard fork.

ContributionAndProof changes so the sync_committee_contribution_and_proof topic is not wire-compatible across the fork boundary and requires a new fork.

Sync committee membership, duties, rewards, penalties, and the on-chain SyncAggregate are unchanged. Light client behaviour is also unchanged.

Security Considerations

Loss of aggregator secrecy

We note that every other duty is public in advance:

  • attestation committees one to two epochs ahead
  • Includers one epoch ahead
  • proposers one epoch
  • sync committee membership about 27 hours.

Aggregation is the exception here since selection proofs are unpredictable until published.

We also note that attestation aggregator secrecy is already partly leaked, because is_aggregator() decides whether a validator subscribes to beacon_attestation_{subnet_id} and non-aggregators need not subscribe, so the subscription signals the outcome to peers before anything is published.

This EIP does not claim that lookahead privacy is not important. A complete solution given privacy would be welcome.

RANDAO grinding

Using randao to select the aggregator set does not introduce any new attack vectors because we were already using randao to select the sync committee.

Copyright and related rights waived via CC0.

EIP.tools

EIP.tools

Search, read, and map Ethereum improvement proposals, ERCs, RIPs, and CAIPs from one focused interface.

Farcaster
by @apoorveth