Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 5 additions & 11 deletions packages/testing/src/consensus_testing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,18 @@
from consensus_testing.test_fixtures import (
ApiEndpointTest,
BaseConsensusFixture,
DropComponentMessageBinding,
DropMessageBinding,
ForkChoiceTest,
GossipsubHandlerTest,
IncrementComponentSlot,
IncrementEmittedSlot,
JustifiabilityTest,
NetworkingCodecTest,
PoseidonPermutationTest,
RebindComponentToAlternateHeadRoot,
RebindToAlternateHeadRoot,
SlotClockTest,
SSZTest,
StateTransitionTest,
SwapComponentMessageBindings,
SwapComponentParticipantPublicKey,
SwapMessageBindings,
SwapParticipantPublicKey,
SyncTest,
VerifyMultiMessageProofsTest,
Expand Down Expand Up @@ -72,15 +69,12 @@
"StateTransitionTest",
"ForkChoiceTest",
"VerifySingleMessageProofsTest",
"VerifyMultiMessageProofsTest",
"RebindToAlternateHeadRoot",
"IncrementEmittedSlot",
"SwapParticipantPublicKey",
"VerifyMultiMessageProofsTest",
"RebindComponentToAlternateHeadRoot",
"IncrementComponentSlot",
"SwapComponentParticipantPublicKey",
"SwapComponentMessageBindings",
"DropComponentMessageBinding",
"SwapMessageBindings",
"DropMessageBinding",
"VerifySignaturesTest",
"SSZTest",
"NetworkingCodecTest",
Expand Down
49 changes: 16 additions & 33 deletions packages/testing/src/consensus_testing/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ def sign_and_aggregate(
self,
validator_indices: list[ValidatorIndex],
attestation_data: AttestationData,
precomputed_signatures: Mapping[ValidatorIndex, Signature] | None = None,
) -> SingleMessageAggregate:
"""
Sign attestation data with each validator and aggregate the result.
Expand All @@ -529,15 +530,19 @@ def sign_and_aggregate(
Args:
validator_indices: Validators to sign with.
attestation_data: The attestation data to sign.
precomputed_signatures: Optional pre-computed signatures keyed by
validator index. Missing entries are signed on the fly.

Returns:
Cryptographically valid single-message aggregate proof covering validator_indices.
"""
signatures = precomputed_signatures or {}
raw_xmss = [
(
validator_index,
self.get_public_keys(validator_index)[0],
self.sign_attestation_data(validator_index, attestation_data),
signatures.get(validator_index)
or self.sign_attestation_data(validator_index, attestation_data),
)
for validator_index in validator_indices
]
Expand Down Expand Up @@ -577,39 +582,17 @@ def build_attestation_proofs(
"""
lookup = signature_lookup or {}

proofs: list[SingleMessageAggregate] = []
for aggregate in aggregated_attestations:
# Decode which validators participated from the bitfield.
validator_indices = aggregate.aggregation_bits.to_validator_indices()

# Try the lookup first for pre-computed signatures.
# Fall back to signing on the fly for any missing entries.
signatures_for_data = lookup.get(aggregate.data, {})

# Collect the attestation public keys for each participant.
public_keys = [
self.get_public_keys(validator_index)[0] for validator_index in validator_indices
]

# Gather individual signatures, computing any that are missing.
signatures = [
signatures_for_data.get(validator_index)
or self.sign_attestation_data(validator_index, aggregate.data)
for validator_index in validator_indices
]

# Produce a single aggregated proof that the leanVM can verify
# in one pass over all participants.
proofs.append(
SingleMessageAggregate.aggregate(
children=[],
raw_xmss=list(zip(validator_indices, public_keys, signatures, strict=True)),
message=hash_tree_root(aggregate.data),
slot=aggregate.data.slot,
)
# Produce one aggregated proof per attestation that the leanVM can
# verify in one pass over all participants.
# Participants are decoded from each attestation's bitfield.
return [
self.sign_and_aggregate(
list(aggregate.aggregation_bits.to_validator_indices()),
aggregate.data,
precomputed_signatures=lookup.get(aggregate.data, {}),
)

return proofs
for aggregate in aggregated_attestations
]


def _generate_single_keypair(
Expand Down
24 changes: 8 additions & 16 deletions packages/testing/src/consensus_testing/test_fixtures/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,28 @@
from consensus_testing.test_fixtures.ssz import SSZTest
from consensus_testing.test_fixtures.state_transition import StateTransitionTest
from consensus_testing.test_fixtures.sync import SyncTest
from consensus_testing.test_fixtures.verify_multi_message_proofs import (
DropComponentMessageBinding,
IncrementComponentSlot,
RebindComponentToAlternateHeadRoot,
SwapComponentMessageBindings,
SwapComponentParticipantPublicKey,
VerifyMultiMessageProofsTest,
)
from consensus_testing.test_fixtures.verify_signatures import VerifySignaturesTest
from consensus_testing.test_fixtures.verify_single_message_proofs import (
from consensus_testing.test_fixtures.verify_proofs import (
DropMessageBinding,
IncrementEmittedSlot,
RebindToAlternateHeadRoot,
SwapMessageBindings,
SwapParticipantPublicKey,
VerifyMultiMessageProofsTest,
VerifySingleMessageProofsTest,
)
from consensus_testing.test_fixtures.verify_signatures import VerifySignaturesTest

__all__ = [
"BaseConsensusFixture",
"StateTransitionTest",
"ForkChoiceTest",
"VerifySingleMessageProofsTest",
"VerifyMultiMessageProofsTest",
"RebindToAlternateHeadRoot",
"IncrementEmittedSlot",
"SwapParticipantPublicKey",
"VerifyMultiMessageProofsTest",
"RebindComponentToAlternateHeadRoot",
"IncrementComponentSlot",
"SwapComponentParticipantPublicKey",
"SwapComponentMessageBindings",
"DropComponentMessageBinding",
"SwapMessageBindings",
"DropMessageBinding",
"VerifySignaturesTest",
"SSZTest",
"NetworkingCodecTest",
Expand Down
Loading
Loading