Skip to content

Commit 47edde5

Browse files
Optimized sync committee signature verification (#4687)
Enhanced sync committee signature verification to leverage precomputed aggregate pubkey for improved efficiency in high-participation scenarios, particularly for light clients, while ensuring compatibility with existing BLS operations and maintaining spec clarity with added explanatory notes. Fixes #4195
1 parent bc731ee commit 47edde5

File tree

1 file changed

+27
-3
lines changed

1 file changed

+27
-3
lines changed

specs/altair/beacon-chain.md

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -575,12 +575,36 @@ def add_validator_to_registry(
575575
def process_sync_aggregate(state: BeaconState, sync_aggregate: SyncAggregate) -> None:
576576
# Verify sync committee aggregate signature signing over the previous slot block root
577577
committee_pubkeys = state.current_sync_committee.pubkeys
578-
participant_pubkeys = [
579-
pubkey for pubkey, bit in zip(committee_pubkeys, sync_aggregate.sync_committee_bits) if bit
580-
]
578+
committee_bits = sync_aggregate.sync_committee_bits
579+
if sum(committee_bits) == SYNC_COMMITTEE_SIZE:
580+
# All members participated - use precomputed aggregate key
581+
participant_pubkeys = [state.current_sync_committee.aggregate_pubkey]
582+
elif sum(committee_bits) > SYNC_COMMITTEE_SIZE // 2:
583+
# More than half participated - subtract non-participant keys.
584+
# First determine nonparticipating members
585+
non_participant_pubkeys = [
586+
pubkey for pubkey, bit in zip(committee_pubkeys, committee_bits) if not bit
587+
]
588+
# Compute aggregate of non-participants
589+
non_participant_aggregate = eth_aggregate_pubkeys(non_participant_pubkeys)
590+
# Subtract non-participants from the full aggregate
591+
# This is equivalent to: aggregate_pubkey + (-non_participant_aggregate)
592+
participant_pubkey = bls.add(
593+
bls.bytes48_to_G1(state.current_sync_committee.aggregate_pubkey),
594+
bls.neg(bls.bytes48_to_G1(non_participant_aggregate)),
595+
)
596+
participant_pubkeys = [BLSPubkey(bls.G1_to_bytes48(participant_pubkey))]
597+
else:
598+
# Less than half participated - aggregate participant keys
599+
participant_pubkeys = [
600+
pubkey
601+
for pubkey, bit in zip(committee_pubkeys, sync_aggregate.sync_committee_bits)
602+
if bit
603+
]
581604
previous_slot = max(state.slot, Slot(1)) - Slot(1)
582605
domain = get_domain(state, DOMAIN_SYNC_COMMITTEE, compute_epoch_at_slot(previous_slot))
583606
signing_root = compute_signing_root(get_block_root_at_slot(state, previous_slot), domain)
607+
# Note: eth_fast_aggregate_verify works with a singleton list containing an aggregated key
584608
assert eth_fast_aggregate_verify(
585609
participant_pubkeys, signing_root, sync_aggregate.sync_committee_signature
586610
)

0 commit comments

Comments
 (0)