From 74b5f6ecf29b3cde457f4e52a71d1c81ea7cb54f Mon Sep 17 00:00:00 2001 From: Nishant Das Date: Mon, 8 Jul 2024 17:28:41 +0800 Subject: [PATCH] Add Aggregated Public Key Method (#14178) * Add aggregated key method * Gazelle * Manu's Review --- beacon-chain/core/blocks/signature.go | 7 +---- beacon-chain/state/BUILD.bazel | 1 + beacon-chain/state/interfaces.go | 2 ++ beacon-chain/state/state-native/BUILD.bazel | 2 ++ .../state/state-native/getters_validator.go | 31 +++++++++++++++++++ .../state-native/getters_validator_test.go | 17 ++++++++++ 6 files changed, 54 insertions(+), 6 deletions(-) diff --git a/beacon-chain/core/blocks/signature.go b/beacon-chain/core/blocks/signature.go index c0f9741589cf..dedd5856ec68 100644 --- a/beacon-chain/core/blocks/signature.go +++ b/beacon-chain/core/blocks/signature.go @@ -204,12 +204,7 @@ func createAttestationSignatureBatch( return nil, err } indices := ia.GetAttestingIndices() - pubkeys := make([][]byte, len(indices)) - for i := 0; i < len(indices); i++ { - pubkeyAtIdx := beaconState.PubkeyAtIndex(primitives.ValidatorIndex(indices[i])) - pubkeys[i] = pubkeyAtIdx[:] - } - aggP, err := bls.AggregatePublicKeys(pubkeys) + aggP, err := beaconState.AggregateKeyFromIndices(indices) if err != nil { return nil, err } diff --git a/beacon-chain/state/BUILD.bazel b/beacon-chain/state/BUILD.bazel index fa1ee84cff41..295cfa2110d5 100644 --- a/beacon-chain/state/BUILD.bazel +++ b/beacon-chain/state/BUILD.bazel @@ -13,6 +13,7 @@ go_library( "//config/fieldparams:go_default_library", "//consensus-types/interfaces:go_default_library", "//consensus-types/primitives:go_default_library", + "//crypto/bls:go_default_library", "//proto/engine/v1:go_default_library", "//proto/prysm/v1alpha1:go_default_library", "@com_github_prometheus_client_golang//prometheus:go_default_library", diff --git a/beacon-chain/state/interfaces.go b/beacon-chain/state/interfaces.go index 85c9bb9e25e2..949d735881ea 100644 --- a/beacon-chain/state/interfaces.go +++ b/beacon-chain/state/interfaces.go @@ -11,6 +11,7 @@ import ( fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" "github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces" "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" + "github.com/prysmaticlabs/prysm/v5/crypto/bls" enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" ) @@ -129,6 +130,7 @@ type ReadOnlyValidators interface { ValidatorIndexByPubkey(key [fieldparams.BLSPubkeyLength]byte) (primitives.ValidatorIndex, bool) PublicKeys() ([][fieldparams.BLSPubkeyLength]byte, error) PubkeyAtIndex(idx primitives.ValidatorIndex) [fieldparams.BLSPubkeyLength]byte + AggregateKeyFromIndices(idxs []uint64) (bls.PublicKey, error) NumValidators() int ReadFromEveryValidator(f func(idx int, val ReadOnlyValidator) error) error } diff --git a/beacon-chain/state/state-native/BUILD.bazel b/beacon-chain/state/state-native/BUILD.bazel index 46c8bb8e4497..da2f397025f1 100644 --- a/beacon-chain/state/state-native/BUILD.bazel +++ b/beacon-chain/state/state-native/BUILD.bazel @@ -68,6 +68,7 @@ go_library( "//consensus-types/primitives:go_default_library", "//container/multi-value-slice:go_default_library", "//container/slice:go_default_library", + "//crypto/bls:go_default_library", "//crypto/hash:go_default_library", "//encoding/bytesutil:go_default_library", "//encoding/ssz:go_default_library", @@ -141,6 +142,7 @@ go_test( "//consensus-types/interfaces:go_default_library", "//consensus-types/primitives:go_default_library", "//container/trie:go_default_library", + "//crypto/bls:go_default_library", "//crypto/rand:go_default_library", "//encoding/bytesutil:go_default_library", "//proto/engine/v1:go_default_library", diff --git a/beacon-chain/state/state-native/getters_validator.go b/beacon-chain/state/state-native/getters_validator.go index 0f1df58b9cef..cfc3779c170e 100644 --- a/beacon-chain/state/state-native/getters_validator.go +++ b/beacon-chain/state/state-native/getters_validator.go @@ -9,6 +9,7 @@ import ( "github.com/prysmaticlabs/prysm/v5/config/params" consensus_types "github.com/prysmaticlabs/prysm/v5/consensus-types" "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" + "github.com/prysmaticlabs/prysm/v5/crypto/bls" "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" "github.com/prysmaticlabs/prysm/v5/runtime/version" @@ -223,6 +224,36 @@ func (b *BeaconState) PubkeyAtIndex(idx primitives.ValidatorIndex) [fieldparams. return bytesutil.ToBytes48(v.PublicKey) } +// AggregateKeyFromIndices builds an aggregated public key from the provided +// validator indices. +func (b *BeaconState) AggregateKeyFromIndices(idxs []uint64) (bls.PublicKey, error) { + b.lock.RLock() + defer b.lock.RUnlock() + + pubKeys := make([][]byte, len(idxs)) + for i, idx := range idxs { + var v *ethpb.Validator + if features.Get().EnableExperimentalState { + var err error + v, err = b.validatorsMultiValue.At(b, idx) + if err != nil { + return nil, err + } + } else { + if idx >= uint64(len(b.validators)) { + return nil, consensus_types.ErrOutOfBounds + } + v = b.validators[idx] + } + + if v == nil { + return nil, ErrNilWrappedValidator + } + pubKeys[i] = v.PublicKey + } + return bls.AggregatePublicKeys(pubKeys) +} + // PublicKeys builds a list of all validator public keys, with each key's index aligned to its validator index. func (b *BeaconState) PublicKeys() ([][fieldparams.BLSPubkeyLength]byte, error) { b.lock.RLock() diff --git a/beacon-chain/state/state-native/getters_validator_test.go b/beacon-chain/state/state-native/getters_validator_test.go index 81e823c19487..c4938832067d 100644 --- a/beacon-chain/state/state-native/getters_validator_test.go +++ b/beacon-chain/state/state-native/getters_validator_test.go @@ -10,7 +10,9 @@ import ( testtmpl "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/testing" "github.com/prysmaticlabs/prysm/v5/config/params" consensus_types "github.com/prysmaticlabs/prysm/v5/consensus-types" + "github.com/prysmaticlabs/prysm/v5/crypto/bls" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v5/testing/assert" "github.com/prysmaticlabs/prysm/v5/testing/require" "github.com/prysmaticlabs/prysm/v5/testing/util" ) @@ -145,3 +147,18 @@ func TestPendingBalanceToWithdraw(t *testing.T) { require.NoError(t, err) require.Equal(t, uint64(600), ab) } + +func TestAggregateKeyFromIndices(t *testing.T) { + dState, _ := util.DeterministicGenesisState(t, 10) + pKey1 := dState.PubkeyAtIndex(3) + pKey2 := dState.PubkeyAtIndex(7) + pKey3 := dState.PubkeyAtIndex(9) + + aggKey, err := bls.AggregatePublicKeys([][]byte{pKey1[:], pKey2[:], pKey3[:]}) + require.NoError(t, err) + + retKey, err := dState.AggregateKeyFromIndices([]uint64{3, 7, 9}) + require.NoError(t, err) + + assert.Equal(t, true, aggKey.Equals(retKey), "unequal aggregated keys") +}