From fb8be4d555dd67e091c5740fe48f568599a94d48 Mon Sep 17 00:00:00 2001 From: Preston Van Loon Date: Wed, 24 Jun 2020 17:47:51 -0700 Subject: [PATCH] Refactor BLS (#6395) * refactor BLS to expose an interface rather than a single implementation * Split up tests, gofmt, goimports, docs * godoc for signature.Copy() * more godocs * revert gomod / deps changes * rm newline * revert proto changes * rename bls12 to herumi for clarity --- beacon-chain/core/blocks/block_operations.go | 8 +- .../core/blocks/block_operations_test.go | 20 +- .../core/blocks/block_regression_test.go | 4 +- beacon-chain/core/helpers/attestation.go | 6 +- beacon-chain/core/helpers/attestation_test.go | 4 +- beacon-chain/core/state/transition_test.go | 8 +- .../slashings/service_attester_test.go | 6 +- beacon-chain/rpc/validator/aggregator_test.go | 8 +- beacon-chain/rpc/validator/proposer_test.go | 2 +- .../sync/pending_attestations_queue_test.go | 2 +- .../sync/validate_aggregate_proof_test.go | 4 +- .../sync/validate_attester_slashing_test.go | 4 +- .../aggregation/attestations/attestations.go | 2 +- shared/aggregation/attestations/maxcover.go | 2 +- shared/attestationutil/attestation_utils.go | 2 +- shared/bls/BUILD.bazel | 48 +-- shared/bls/bls.go | 277 +---------------- shared/bls/bls_test.go | 285 ------------------ shared/bls/constants.go | 7 + shared/bls/herumi/BUILD.bazel | 66 ++++ shared/bls/{ => herumi}/bls_benchmark_test.go | 33 +- shared/bls/herumi/docs.go | 6 + shared/bls/herumi/init.go | 12 + shared/bls/herumi/public_key.go | 65 ++++ shared/bls/herumi/public_key_test.go | 80 +++++ shared/bls/herumi/secret_key.go | 67 ++++ shared/bls/herumi/secret_key_test.go | 94 ++++++ shared/bls/herumi/signature.go | 157 ++++++++++ shared/bls/herumi/signature_test.go | 127 ++++++++ shared/bls/iface/BUILD.bazel | 8 + shared/bls/iface/interface.go | 29 ++ shared/bls/interface.go | 14 + shared/bls/spectest/BUILD.bazel | 1 + shared/bls/spectest/aggregate_test.go | 3 +- shared/bls/spectest/aggregate_verify_test.go | 3 +- .../spectest/fast_aggregate_verify_test.go | 3 +- shared/interop/generate_genesis_state.go | 6 +- shared/interop/generate_keys.go | 16 +- shared/keystore/key.go | 6 +- shared/keystore/utils.go | 2 +- shared/testutil/block.go | 20 +- shared/testutil/deposits.go | 10 +- shared/testutil/helpers.go | 6 +- slasher/rpc/server.go | 2 +- slasher/rpc/server_test.go | 6 +- third_party/herumi/bls_eth_go_binary.BUILD | 2 +- tools/unencrypted-keys-gen/main.go | 2 +- validator/client/polling/attest.go | 2 +- validator/client/polling/propose.go | 2 +- validator/client/polling/service.go | 2 +- validator/client/polling/service_test.go | 4 +- validator/client/polling/validator_test.go | 4 +- validator/client/streaming/attest.go | 2 +- validator/client/streaming/propose.go | 2 +- validator/client/streaming/service.go | 2 +- validator/client/streaming/service_test.go | 4 +- validator/client/streaming/validator_test.go | 4 +- validator/keymanager/direct.go | 12 +- validator/keymanager/direct_interop.go | 4 +- validator/keymanager/direct_keystore.go | 4 +- validator/keymanager/direct_test.go | 8 +- validator/keymanager/direct_unencrypted.go | 10 +- validator/keymanager/keymanager.go | 8 +- validator/keymanager/remote.go | 8 +- validator/keymanager/wallet.go | 2 +- 65 files changed, 901 insertions(+), 728 deletions(-) delete mode 100644 shared/bls/bls_test.go create mode 100644 shared/bls/constants.go create mode 100644 shared/bls/herumi/BUILD.bazel rename shared/bls/{ => herumi}/bls_benchmark_test.go (68%) create mode 100644 shared/bls/herumi/docs.go create mode 100644 shared/bls/herumi/init.go create mode 100644 shared/bls/herumi/public_key.go create mode 100644 shared/bls/herumi/public_key_test.go create mode 100644 shared/bls/herumi/secret_key.go create mode 100644 shared/bls/herumi/secret_key_test.go create mode 100644 shared/bls/herumi/signature.go create mode 100644 shared/bls/herumi/signature_test.go create mode 100644 shared/bls/iface/BUILD.bazel create mode 100644 shared/bls/iface/interface.go create mode 100644 shared/bls/interface.go diff --git a/beacon-chain/core/blocks/block_operations.go b/beacon-chain/core/blocks/block_operations.go index 3602c2dfed..fbac69f9b4 100644 --- a/beacon-chain/core/blocks/block_operations.go +++ b/beacon-chain/core/blocks/block_operations.go @@ -758,7 +758,7 @@ func VerifyIndexedAttestation(ctx context.Context, beaconState *stateTrie.Beacon return err } indices := indexedAtt.AttestingIndices - pubkeys := []*bls.PublicKey{} + pubkeys := []bls.PublicKey{} if len(indices) > 0 { for i := 0; i < len(indices); i++ { pubkeyAtIdx := beaconState.PubkeyAtIndex(indices[i]) @@ -847,8 +847,8 @@ func verifyAttestationsWithDomain(ctx context.Context, beaconState *stateTrie.Be return nil } - sigs := make([]*bls.Signature, len(atts)) - pks := make([]*bls.PublicKey, len(atts)) + sigs := make([]bls.Signature, len(atts)) + pks := make([]bls.PublicKey, len(atts)) msgs := make([][32]byte, len(atts)) for i, a := range atts { sig, err := bls.SignatureFromBytes(a.Signature) @@ -862,7 +862,7 @@ func verifyAttestationsWithDomain(ctx context.Context, beaconState *stateTrie.Be } ia := attestationutil.ConvertToIndexed(ctx, a, c) indices := ia.AttestingIndices - var pk *bls.PublicKey + var pk bls.PublicKey for i := 0; i < len(indices); i++ { pubkeyAtIdx := beaconState.PubkeyAtIndex(indices[i]) p, err := bls.PublicKeyFromBytes(pubkeyAtIdx[:]) diff --git a/beacon-chain/core/blocks/block_operations_test.go b/beacon-chain/core/blocks/block_operations_test.go index 14bfffe70e..54b7be2c08 100644 --- a/beacon-chain/core/blocks/block_operations_test.go +++ b/beacon-chain/core/blocks/block_operations_test.go @@ -836,7 +836,7 @@ func TestProcessAttesterSlashings_AppliesCorrectStatus(t *testing.T) { } sig0 := privKeys[0].Sign(signingRoot[:]) sig1 := privKeys[1].Sign(signingRoot[:]) - aggregateSig := bls.AggregateSignatures([]*bls.Signature{sig0, sig1}) + aggregateSig := bls.AggregateSignatures([]bls.Signature{sig0, sig1}) att1.Signature = aggregateSig.Marshal()[:] att2 := ðpb.IndexedAttestation{ @@ -852,7 +852,7 @@ func TestProcessAttesterSlashings_AppliesCorrectStatus(t *testing.T) { } sig0 = privKeys[0].Sign(signingRoot[:]) sig1 = privKeys[1].Sign(signingRoot[:]) - aggregateSig = bls.AggregateSignatures([]*bls.Signature{sig0, sig1}) + aggregateSig = bls.AggregateSignatures([]bls.Signature{sig0, sig1}) att2.Signature = aggregateSig.Marshal()[:] slashings := []*ethpb.AttesterSlashing{ @@ -1148,7 +1148,7 @@ func TestProcessAttestations_OK(t *testing.T) { if err != nil { t.Error(err) } - sigs := make([]*bls.Signature, len(attestingIndices)) + sigs := make([]bls.Signature, len(attestingIndices)) for i, indice := range attestingIndices { sig := privKeys[indice].Sign(hashTreeRoot[:]) sigs[i] = sig @@ -1212,7 +1212,7 @@ func TestProcessAggregatedAttestation_OverlappingBits(t *testing.T) { if err != nil { t.Error(err) } - sigs := make([]*bls.Signature, len(attestingIndices1)) + sigs := make([]bls.Signature, len(attestingIndices1)) for i, indice := range attestingIndices1 { sig := privKeys[indice].Sign(hashTreeRoot[:]) sigs[i] = sig @@ -1240,7 +1240,7 @@ func TestProcessAggregatedAttestation_OverlappingBits(t *testing.T) { if err != nil { t.Error(err) } - sigs = make([]*bls.Signature, len(attestingIndices2)) + sigs = make([]bls.Signature, len(attestingIndices2)) for i, indice := range attestingIndices2 { sig := privKeys[indice].Sign(hashTreeRoot[:]) sigs[i] = sig @@ -1294,7 +1294,7 @@ func TestProcessAggregatedAttestation_NoOverlappingBits(t *testing.T) { if err != nil { t.Error(err) } - sigs := make([]*bls.Signature, len(attestingIndices1)) + sigs := make([]bls.Signature, len(attestingIndices1)) for i, indice := range attestingIndices1 { sig := privKeys[indice].Sign(hashTreeRoot[:]) sigs[i] = sig @@ -1321,7 +1321,7 @@ func TestProcessAggregatedAttestation_NoOverlappingBits(t *testing.T) { if err != nil { t.Error(err) } - sigs = make([]*bls.Signature, len(attestingIndices2)) + sigs = make([]bls.Signature, len(attestingIndices2)) for i, indice := range attestingIndices2 { sig := privKeys[indice].Sign(hashTreeRoot[:]) sigs[i] = sig @@ -1540,7 +1540,7 @@ func TestVerifyIndexedAttestation_OK(t *testing.T) { if err != nil { t.Error(err) } - var sig []*bls.Signature + var sig []bls.Signature for _, idx := range tt.attestation.AttestingIndices { validatorSig := keys[idx].Sign(root[:]) sig = append(sig, validatorSig) @@ -2107,7 +2107,7 @@ func TestVerifyAttestations_VerifiesMultipleAttestations(t *testing.T) { if err != nil { t.Fatal(err) } - var sigs []*bls.Signature + var sigs []bls.Signature for i, u := range comm1 { att1.AggregationBits.SetBitAt(uint64(i), true) sigs = append(sigs, keys[u].Sign(root[:])) @@ -2189,7 +2189,7 @@ func TestVerifyAttestations_HandlesPlannedFork(t *testing.T) { if err != nil { t.Fatal(err) } - var sigs []*bls.Signature + var sigs []bls.Signature for i, u := range comm1 { att1.AggregationBits.SetBitAt(uint64(i), true) sigs = append(sigs, keys[u].Sign(root[:])) diff --git a/beacon-chain/core/blocks/block_regression_test.go b/beacon-chain/core/blocks/block_regression_test.go index a52a8f8a4b..40bbd472b5 100644 --- a/beacon-chain/core/blocks/block_regression_test.go +++ b/beacon-chain/core/blocks/block_regression_test.go @@ -50,7 +50,7 @@ func TestProcessAttesterSlashings_RegressionSlashableIndices(t *testing.T) { if err != nil { t.Errorf("Could not get signing root of beacon block header: %v", err) } - aggSigs := []*bls.Signature{} + aggSigs := []bls.Signature{} for _, index := range setA { sig := privKeys[index].Sign(signingRoot[:]) aggSigs = append(aggSigs, sig) @@ -70,7 +70,7 @@ func TestProcessAttesterSlashings_RegressionSlashableIndices(t *testing.T) { if err != nil { t.Errorf("Could not get signing root of beacon block header: %v", err) } - aggSigs = []*bls.Signature{} + aggSigs = []bls.Signature{} for _, index := range setB { sig := privKeys[index].Sign(signingRoot[:]) aggSigs = append(aggSigs, sig) diff --git a/beacon-chain/core/helpers/attestation.go b/beacon-chain/core/helpers/attestation.go index 0eb8567c79..cdad1963d1 100644 --- a/beacon-chain/core/helpers/attestation.go +++ b/beacon-chain/core/helpers/attestation.go @@ -17,7 +17,7 @@ import ( // domain = get_domain(state, DOMAIN_SELECTION_PROOF, compute_epoch_at_slot(slot)) // signing_root = compute_signing_root(slot, domain) // return bls.Sign(privkey, signing_root) -func SlotSignature(state *stateTrie.BeaconState, slot uint64, privKey *bls.SecretKey) (*bls.Signature, error) { +func SlotSignature(state *stateTrie.BeaconState, slot uint64, privKey bls.SecretKey) (bls.Signature, error) { d, err := Domain(state.Fork(), CurrentEpoch(state), params.BeaconConfig().DomainBeaconAttester, state.GenesisValidatorRoot()) if err != nil { return nil, err @@ -54,8 +54,8 @@ func IsAggregator(committeeCount uint64, slotSig []byte) (bool, error) { // def get_aggregate_signature(attestations: Sequence[Attestation]) -> BLSSignature: // signatures = [attestation.signature for attestation in attestations] // return bls_aggregate_signatures(signatures) -func AggregateSignature(attestations []*ethpb.Attestation) (*bls.Signature, error) { - sigs := make([]*bls.Signature, len(attestations)) +func AggregateSignature(attestations []*ethpb.Attestation) (bls.Signature, error) { + sigs := make([]bls.Signature, len(attestations)) var err error for i := 0; i < len(sigs); i++ { sigs[i], err = bls.SignatureFromBytes(attestations[i].Signature) diff --git a/beacon-chain/core/helpers/attestation_test.go b/beacon-chain/core/helpers/attestation_test.go index 48813507c2..718f7cd343 100644 --- a/beacon-chain/core/helpers/attestation_test.go +++ b/beacon-chain/core/helpers/attestation_test.go @@ -88,7 +88,7 @@ func TestAttestation_IsAggregator(t *testing.T) { func TestAttestation_AggregateSignature(t *testing.T) { t.Run("verified", func(t *testing.T) { - pubkeys := make([]*bls.PublicKey, 0, 100) + pubkeys := make([]bls.PublicKey, 0, 100) atts := make([]*ethpb.Attestation, 0, 100) msg := bytesutil.ToBytes32([]byte("hello")) for i := 0; i < 100; i++ { @@ -109,7 +109,7 @@ func TestAttestation_AggregateSignature(t *testing.T) { }) t.Run("not verified", func(t *testing.T) { - pubkeys := make([]*bls.PublicKey, 0, 100) + pubkeys := make([]bls.PublicKey, 0, 100) atts := make([]*ethpb.Attestation, 0, 100) msg := []byte("hello") for i := 0; i < 100; i++ { diff --git a/beacon-chain/core/state/transition_test.go b/beacon-chain/core/state/transition_test.go index 0765f3192e..cc1974bcd0 100644 --- a/beacon-chain/core/state/transition_test.go +++ b/beacon-chain/core/state/transition_test.go @@ -451,7 +451,7 @@ func TestProcessBlock_PassesProcessingConditions(t *testing.T) { } sig0 := privKeys[0].Sign(hashTreeRoot[:]) sig1 := privKeys[1].Sign(hashTreeRoot[:]) - aggregateSig := bls.AggregateSignatures([]*bls.Signature{sig0, sig1}) + aggregateSig := bls.AggregateSignatures([]bls.Signature{sig0, sig1}) att1.Signature = aggregateSig.Marshal()[:] mockRoot3 := [32]byte{'B'} @@ -468,7 +468,7 @@ func TestProcessBlock_PassesProcessingConditions(t *testing.T) { } sig0 = privKeys[0].Sign(hashTreeRoot[:]) sig1 = privKeys[1].Sign(hashTreeRoot[:]) - aggregateSig = bls.AggregateSignatures([]*bls.Signature{sig0, sig1}) + aggregateSig = bls.AggregateSignatures([]bls.Signature{sig0, sig1}) att2.Signature = aggregateSig.Marshal()[:] attesterSlashings := []*ethpb.AttesterSlashing{ @@ -511,7 +511,7 @@ func TestProcessBlock_PassesProcessingConditions(t *testing.T) { if err != nil { t.Error(err) } - sigs := make([]*bls.Signature, len(attestingIndices)) + sigs := make([]bls.Signature, len(attestingIndices)) for i, indice := range attestingIndices { sig := privKeys[indice].Sign(hashTreeRoot[:]) sigs[i] = sig @@ -875,7 +875,7 @@ func TestProcessBlk_AttsBasedOnValidatorCount(t *testing.T) { if err != nil { t.Fatal(err) } - sigs := make([]*bls.Signature, len(attestingIndices)) + sigs := make([]bls.Signature, len(attestingIndices)) for i, indice := range attestingIndices { hashTreeRoot, err := helpers.ComputeSigningRoot(att.Data, domain) if err != nil { diff --git a/beacon-chain/operations/slashings/service_attester_test.go b/beacon-chain/operations/slashings/service_attester_test.go index f766902dc8..73df634cb8 100644 --- a/beacon-chain/operations/slashings/service_attester_test.go +++ b/beacon-chain/operations/slashings/service_attester_test.go @@ -15,7 +15,7 @@ import ( "github.com/prysmaticlabs/prysm/shared/testutil" ) -func validAttesterSlashingForValIdx(t *testing.T, beaconState *state.BeaconState, privs []*bls.SecretKey, valIdx ...uint64) *ethpb.AttesterSlashing { +func validAttesterSlashingForValIdx(t *testing.T, beaconState *state.BeaconState, privs []bls.SecretKey, valIdx ...uint64) *ethpb.AttesterSlashing { slashings := []*ethpb.AttesterSlashing{} for _, idx := range valIdx { slashing, err := testutil.GenerateAttesterSlashingForValidator(beaconState, privs[idx], idx) @@ -24,8 +24,8 @@ func validAttesterSlashingForValIdx(t *testing.T, beaconState *state.BeaconState } slashings = append(slashings, slashing) } - allSig1 := []*bls.Signature{} - allSig2 := []*bls.Signature{} + allSig1 := []bls.Signature{} + allSig2 := []bls.Signature{} for _, slashing := range slashings { sig1 := slashing.Attestation_1.Signature sig2 := slashing.Attestation_2.Signature diff --git a/beacon-chain/rpc/validator/aggregator_test.go b/beacon-chain/rpc/validator/aggregator_test.go index c34955894a..373247bfe4 100644 --- a/beacon-chain/rpc/validator/aggregator_test.go +++ b/beacon-chain/rpc/validator/aggregator_test.go @@ -251,7 +251,7 @@ func TestSubmitAggregateAndProof_AggregateNotOk(t *testing.T) { } } -func generateAtt(state *beaconstate.BeaconState, index uint64, privKeys []*bls.SecretKey) (*ethpb.Attestation, error) { +func generateAtt(state *beaconstate.BeaconState, index uint64, privKeys []bls.SecretKey) (*ethpb.Attestation, error) { aggBits := bitfield.NewBitlist(4) aggBits.SetBitAt(index, true) aggBits.SetBitAt(index+1, true) @@ -273,7 +273,7 @@ func generateAtt(state *beaconstate.BeaconState, index uint64, privKeys []*bls.S return nil, err } - sigs := make([]*bls.Signature, len(attestingIndices)) + sigs := make([]bls.Signature, len(attestingIndices)) zeroSig := [96]byte{} att.Signature = zeroSig[:] @@ -291,7 +291,7 @@ func generateAtt(state *beaconstate.BeaconState, index uint64, privKeys []*bls.S return att, nil } -func generateUnaggregatedAtt(state *beaconstate.BeaconState, index uint64, privKeys []*bls.SecretKey) (*ethpb.Attestation, error) { +func generateUnaggregatedAtt(state *beaconstate.BeaconState, index uint64, privKeys []bls.SecretKey) (*ethpb.Attestation, error) { aggBits := bitfield.NewBitlist(4) aggBits.SetBitAt(index, true) att := ðpb.Attestation{ @@ -312,7 +312,7 @@ func generateUnaggregatedAtt(state *beaconstate.BeaconState, index uint64, privK return nil, err } - sigs := make([]*bls.Signature, len(attestingIndices)) + sigs := make([]bls.Signature, len(attestingIndices)) zeroSig := [96]byte{} att.Signature = zeroSig[:] diff --git a/beacon-chain/rpc/validator/proposer_test.go b/beacon-chain/rpc/validator/proposer_test.go index 7fce1f42c6..aec5bf127a 100644 --- a/beacon-chain/rpc/validator/proposer_test.go +++ b/beacon-chain/rpc/validator/proposer_test.go @@ -1430,7 +1430,7 @@ func TestFilterAttestation_OK(t *testing.T) { if err != nil { t.Fatal(err) } - sigs := make([]*bls.Signature, len(attestingIndices)) + sigs := make([]bls.Signature, len(attestingIndices)) zeroSig := [96]byte{} atts[i].Signature = zeroSig[:] diff --git a/beacon-chain/sync/pending_attestations_queue_test.go b/beacon-chain/sync/pending_attestations_queue_test.go index 5b4c6aa659..971d140428 100644 --- a/beacon-chain/sync/pending_attestations_queue_test.go +++ b/beacon-chain/sync/pending_attestations_queue_test.go @@ -158,7 +158,7 @@ func TestProcessPendingAtts_HasBlockSaveAggregatedAtt(t *testing.T) { if err != nil { t.Error(err) } - sigs := make([]*bls.Signature, len(attestingIndices)) + sigs := make([]bls.Signature, len(attestingIndices)) for i, indice := range attestingIndices { sig := privKeys[indice].Sign(hashTreeRoot[:]) sigs[i] = sig diff --git a/beacon-chain/sync/validate_aggregate_proof_test.go b/beacon-chain/sync/validate_aggregate_proof_test.go index eb1cfb0116..9b4723227f 100644 --- a/beacon-chain/sync/validate_aggregate_proof_test.go +++ b/beacon-chain/sync/validate_aggregate_proof_test.go @@ -415,7 +415,7 @@ func TestValidateAggregateAndProofWithNewStateMgmt_CanValidate(t *testing.T) { if err != nil { t.Error(err) } - sigs := make([]*bls.Signature, len(attestingIndices)) + sigs := make([]bls.Signature, len(attestingIndices)) for i, indice := range attestingIndices { sig := privKeys[indice].Sign(hashTreeRoot[:]) sigs[i] = sig @@ -539,7 +539,7 @@ func TestVerifyIndexInCommittee_SeenAggregatorEpoch(t *testing.T) { if err != nil { t.Error(err) } - sigs := make([]*bls.Signature, len(attestingIndices)) + sigs := make([]bls.Signature, len(attestingIndices)) for i, indice := range attestingIndices { sig := privKeys[indice].Sign(hashTreeRoot[:]) sigs[i] = sig diff --git a/beacon-chain/sync/validate_attester_slashing_test.go b/beacon-chain/sync/validate_attester_slashing_test.go index 1b996477b9..455f2dd401 100644 --- a/beacon-chain/sync/validate_attester_slashing_test.go +++ b/beacon-chain/sync/validate_attester_slashing_test.go @@ -50,7 +50,7 @@ func setupValidAttesterSlashing(t *testing.T) (*ethpb.AttesterSlashing, *stateTr } sig0 := privKeys[0].Sign(hashTreeRoot[:]) sig1 := privKeys[1].Sign(hashTreeRoot[:]) - aggregateSig := bls.AggregateSignatures([]*bls.Signature{sig0, sig1}) + aggregateSig := bls.AggregateSignatures([]bls.Signature{sig0, sig1}) att1.Signature = aggregateSig.Marshal()[:] att2 := ðpb.IndexedAttestation{ @@ -66,7 +66,7 @@ func setupValidAttesterSlashing(t *testing.T) (*ethpb.AttesterSlashing, *stateTr } sig0 = privKeys[0].Sign(hashTreeRoot[:]) sig1 = privKeys[1].Sign(hashTreeRoot[:]) - aggregateSig = bls.AggregateSignatures([]*bls.Signature{sig0, sig1}) + aggregateSig = bls.AggregateSignatures([]bls.Signature{sig0, sig1}) att2.Signature = aggregateSig.Marshal()[:] slashing := ðpb.AttesterSlashing{ diff --git a/shared/aggregation/attestations/attestations.go b/shared/aggregation/attestations/attestations.go index d55f3d1592..9402e532b7 100644 --- a/shared/aggregation/attestations/attestations.go +++ b/shared/aggregation/attestations/attestations.go @@ -78,7 +78,7 @@ func AggregatePair(a1 *ethpb.Attestation, a2 *ethpb.Attestation) (*ethpb.Attesta return nil, err } - aggregatedSig := aggregateSignatures([]*bls.Signature{baseSig, newSig}) + aggregatedSig := aggregateSignatures([]bls.Signature{baseSig, newSig}) baseAtt.Signature = aggregatedSig.Marshal() baseAtt.AggregationBits = newBits diff --git a/shared/aggregation/attestations/maxcover.go b/shared/aggregation/attestations/maxcover.go index ed360fb347..96a5611137 100644 --- a/shared/aggregation/attestations/maxcover.go +++ b/shared/aggregation/attestations/maxcover.go @@ -86,7 +86,7 @@ func (al attList) aggregate(coverage bitfield.Bitlist) (*ethpb.Attestation, erro if len(al) < 2 { return nil, errors.Wrap(ErrInvalidAttestationCount, "cannot aggregate") } - signs := make([]*bls.Signature, len(al)) + signs := make([]bls.Signature, len(al)) for i := 0; i < len(al); i++ { sig, err := signatureFromBytes(al[i].Signature) if err != nil { diff --git a/shared/attestationutil/attestation_utils.go b/shared/attestationutil/attestation_utils.go index 1e3c6b6f69..5f39f24ffc 100644 --- a/shared/attestationutil/attestation_utils.go +++ b/shared/attestationutil/attestation_utils.go @@ -94,7 +94,7 @@ func AttestingIndices(bf bitfield.Bitfield, committee []uint64) []uint64 { // domain = get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch) // signing_root = compute_signing_root(indexed_attestation.data, domain) // return bls.FastAggregateVerify(pubkeys, signing_root, indexed_attestation.signature) -func VerifyIndexedAttestationSig(ctx context.Context, indexedAtt *ethpb.IndexedAttestation, pubKeys []*bls.PublicKey, domain []byte) error { +func VerifyIndexedAttestationSig(ctx context.Context, indexedAtt *ethpb.IndexedAttestation, pubKeys []bls.PublicKey, domain []byte) error { ctx, span := trace.StartSpan(ctx, "attestationutil.VerifyIndexedAttestationSig") defer span.End() indices := indexedAtt.AttestingIndices diff --git a/shared/bls/BUILD.bazel b/shared/bls/BUILD.bazel index 934ce97ae2..2ee0298230 100644 --- a/shared/bls/BUILD.bazel +++ b/shared/bls/BUILD.bazel @@ -1,50 +1,16 @@ load("@prysm//tools/go:def.bzl", "go_library") -load("@io_bazel_rules_go//go:def.bzl", "go_test") - -# gazelle:resolve go github.com/herumi/bls-eth-go-binary/bls @herumi_bls_eth_go_binary//:go_default_library go_library( name = "go_default_library", - srcs = ["bls.go"], + srcs = [ + "bls.go", + "constants.go", + "interface.go", + ], importpath = "github.com/prysmaticlabs/prysm/shared/bls", visibility = ["//visibility:public"], deps = [ - "//shared/featureconfig:go_default_library", - "//shared/params:go_default_library", - "@com_github_dgraph_io_ristretto//:go_default_library", - "@com_github_pkg_errors//:go_default_library", - "@herumi_bls_eth_go_binary//:go_default_library", - ], -) - -go_test( - name = "go_default_test", - size = "small", - srcs = ["bls_test.go"], - embed = [":go_default_library"], - deps = ["//shared/bytesutil:go_default_library"], -) - -# gazelle:exclude bls_benchmark_test.go -go_test( - name = "go_benchmark_test", - size = "small", - srcs = ["bls_benchmark_test.go"], - args = [ - "-test.bench=.", - "-test.benchmem", - "-test.v", - ], - local = True, - tags = [ - "benchmark", - "manual", - "no-cache", - ], - deps = [ - "//shared/bls:go_default_library", - "//shared/bytesutil:go_default_library", - "//shared/hashutil:go_default_library", - "@herumi_bls_eth_go_binary//:go_default_library", + "//shared/bls/herumi:go_default_library", + "//shared/bls/iface:go_default_library", ], ) diff --git a/shared/bls/bls.go b/shared/bls/bls.go index 7f91e611d3..470cf2e1f8 100644 --- a/shared/bls/bls.go +++ b/shared/bls/bls.go @@ -4,281 +4,36 @@ package bls import ( - "fmt" - - "github.com/dgraph-io/ristretto" - bls12 "github.com/herumi/bls-eth-go-binary/bls" - "github.com/pkg/errors" - "github.com/prysmaticlabs/prysm/shared/featureconfig" - "github.com/prysmaticlabs/prysm/shared/params" + "github.com/prysmaticlabs/prysm/shared/bls/herumi" + "github.com/prysmaticlabs/prysm/shared/bls/iface" ) -func init() { - if err := bls12.Init(bls12.BLS12_381); err != nil { - panic(err) - } - if err := bls12.SetETHmode(bls12.EthModeDraft07); err != nil { - panic(err) - } -} - -// DomainByteLength length of domain byte array. -const DomainByteLength = 4 - -var maxKeys = int64(100000) -var pubkeyCache, _ = ristretto.NewCache(&ristretto.Config{ - NumCounters: maxKeys, - MaxCost: 1 << 22, // ~4mb is cache max size - BufferItems: 64, -}) - -// CurveOrder for the BLS12-381 curve. -const CurveOrder = "52435875175126190479447740508185965837690552500527637822603658699938581184513" - -// Signature used in the BLS signature scheme. -type Signature struct { - s *bls12.Sign -} - -// PublicKey used in the BLS signature scheme. -type PublicKey struct { - p *bls12.PublicKey -} - -// SecretKey used in the BLS signature scheme. -type SecretKey struct { - p *bls12.SecretKey -} - -// RandKey creates a new private key using a random method provided as an io.Reader. -func RandKey() *SecretKey { - secKey := &bls12.SecretKey{} - secKey.SetByCSPRNG() - return &SecretKey{secKey} -} - // SecretKeyFromBytes creates a BLS private key from a BigEndian byte slice. -func SecretKeyFromBytes(privKey []byte) (*SecretKey, error) { - if len(privKey) != params.BeaconConfig().BLSSecretKeyLength { - return nil, fmt.Errorf("secret key must be %d bytes", params.BeaconConfig().BLSSecretKeyLength) - } - secKey := &bls12.SecretKey{} - err := secKey.Deserialize(privKey) - if err != nil { - return nil, errors.Wrap(err, "could not unmarshal bytes into secret key") - } - return &SecretKey{p: secKey}, err +func SecretKeyFromBytes(privKey []byte) (SecretKey, error) { + return herumi.SecretKeyFromBytes(privKey) } // PublicKeyFromBytes creates a BLS public key from a BigEndian byte slice. -func PublicKeyFromBytes(pubKey []byte) (*PublicKey, error) { - if featureconfig.Get().SkipBLSVerify { - return &PublicKey{}, nil - } - if len(pubKey) != params.BeaconConfig().BLSPubkeyLength { - return nil, fmt.Errorf("public key must be %d bytes", params.BeaconConfig().BLSPubkeyLength) - } - if cv, ok := pubkeyCache.Get(string(pubKey)); ok { - return cv.(*PublicKey).Copy() - } - p := &bls12.PublicKey{} - err := p.Deserialize(pubKey) - if err != nil { - return nil, errors.Wrap(err, "could not unmarshal bytes into public key") - } - pubKeyObj := &PublicKey{p: p} - copiedKey, err := pubKeyObj.Copy() - if err != nil { - return nil, errors.Wrap(err, "could not copy public key") - } - pubkeyCache.Set(string(pubKey), copiedKey, 48) - return pubKeyObj, nil +func PublicKeyFromBytes(pubKey []byte) (PublicKey, error) { + return herumi.PublicKeyFromBytes(pubKey) } // SignatureFromBytes creates a BLS signature from a LittleEndian byte slice. -func SignatureFromBytes(sig []byte) (*Signature, error) { - if featureconfig.Get().SkipBLSVerify { - return &Signature{}, nil - } - if len(sig) != params.BeaconConfig().BLSSignatureLength { - return nil, fmt.Errorf("signature must be %d bytes", params.BeaconConfig().BLSSignatureLength) - } - signature := &bls12.Sign{} - err := signature.Deserialize(sig) - if err != nil { - return nil, errors.Wrap(err, "could not unmarshal bytes into signature") - } - return &Signature{s: signature}, nil -} - -// PublicKey obtains the public key corresponding to the BLS secret key. -func (s *SecretKey) PublicKey() *PublicKey { - return &PublicKey{p: s.p.GetPublicKey()} -} - -// Sign a message using a secret key - in a beacon/validator client. -// -// In IETF draft BLS specification: -// Sign(SK, message) -> signature: a signing algorithm that generates -// a deterministic signature given a secret key SK and a message. -// -// In ETH2.0 specification: -// def Sign(SK: int, message: Bytes) -> BLSSignature -func (s *SecretKey) Sign(msg []byte) *Signature { - if featureconfig.Get().SkipBLSVerify { - return &Signature{} - } - signature := s.p.SignByte(msg) - return &Signature{s: signature} -} - -// Marshal a secret key into a LittleEndian byte slice. -func (s *SecretKey) Marshal() []byte { - keyBytes := s.p.Serialize() - if len(keyBytes) < params.BeaconConfig().BLSSecretKeyLength { - emptyBytes := make([]byte, params.BeaconConfig().BLSSecretKeyLength-len(keyBytes)) - keyBytes = append(emptyBytes, keyBytes...) - } - return keyBytes -} - -// Marshal a public key into a LittleEndian byte slice. -func (p *PublicKey) Marshal() []byte { - return p.p.Serialize() -} - -// Copy the public key to a new pointer reference. -func (p *PublicKey) Copy() (*PublicKey, error) { - np := *p.p - return &PublicKey{p: &np}, nil -} - -// Aggregate two public keys. -func (p *PublicKey) Aggregate(p2 *PublicKey) *PublicKey { - if featureconfig.Get().SkipBLSVerify { - return p - } - p.p.Add(p2.p) - return p -} - -// Verify a bls signature given a public key, a message. -// -// In IETF draft BLS specification: -// Verify(PK, message, signature) -> VALID or INVALID: a verification -// algorithm that outputs VALID if signature is a valid signature of -// message under public key PK, and INVALID otherwise. -// -// In ETH2.0 specification: -// def Verify(PK: BLSPubkey, message: Bytes, signature: BLSSignature) -> bool -func (s *Signature) Verify(pubKey *PublicKey, msg []byte) bool { - if featureconfig.Get().SkipBLSVerify { - return true - } - return s.s.VerifyByte(pubKey.p, msg) -} - -// AggregateVerify verifies each public key against its respective message. -// This is vulnerable to rogue public-key attack. Each user must -// provide a proof-of-knowledge of the public key. -// -// In IETF draft BLS specification: -// AggregateVerify((PK_1, message_1), ..., (PK_n, message_n), -// signature) -> VALID or INVALID: an aggregate verification -// algorithm that outputs VALID if signature is a valid aggregated -// signature for a collection of public keys and messages, and -// outputs INVALID otherwise. -// -// In ETH2.0 specification: -// def AggregateVerify(pairs: Sequence[PK: BLSPubkey, message: Bytes], signature: BLSSignature) -> boo -func (s *Signature) AggregateVerify(pubKeys []*PublicKey, msgs [][32]byte) bool { - if featureconfig.Get().SkipBLSVerify { - return true - } - size := len(pubKeys) - if size == 0 { - return false - } - if size != len(msgs) { - return false - } - msgSlices := make([]byte, 0, 32*len(msgs)) - rawKeys := make([]bls12.PublicKey, 0, len(pubKeys)) - for i := 0; i < size; i++ { - msgSlices = append(msgSlices, msgs[i][:]...) - rawKeys = append(rawKeys, *pubKeys[i].p) - } - // Use "NoCheck" because we do not care if the messages are unique or not. - return s.s.AggregateVerifyNoCheck(rawKeys, msgSlices) -} - -// FastAggregateVerify verifies all the provided public keys with their aggregated signature. -// -// In IETF draft BLS specification: -// FastAggregateVerify(PK_1, ..., PK_n, message, signature) -> VALID -// or INVALID: a verification algorithm for the aggregate of multiple -// signatures on the same message. This function is faster than -// AggregateVerify. -// -// In ETH2.0 specification: -// def FastAggregateVerify(PKs: Sequence[BLSPubkey], message: Bytes, signature: BLSSignature) -> bool -func (s *Signature) FastAggregateVerify(pubKeys []*PublicKey, msg [32]byte) bool { - if featureconfig.Get().SkipBLSVerify { - return true - } - if len(pubKeys) == 0 { - return false - } - rawKeys := make([]bls12.PublicKey, len(pubKeys)) - for i := 0; i < len(pubKeys); i++ { - rawKeys[i] = *pubKeys[i].p - } - - return s.s.FastAggregateVerify(rawKeys, msg[:]) -} - -// NewAggregateSignature creates a blank aggregate signature. -func NewAggregateSignature() *Signature { - return &Signature{s: bls12.HashAndMapToSignature([]byte{'m', 'o', 'c', 'k'})} +func SignatureFromBytes(sig []byte) (Signature, error) { + return herumi.SignatureFromBytes(sig) } // AggregateSignatures converts a list of signatures into a single, aggregated sig. -func AggregateSignatures(sigs []*Signature) *Signature { - if len(sigs) == 0 { - return nil - } - if featureconfig.Get().SkipBLSVerify { - return sigs[0] - } - - // Copy signature - signature := *sigs[0].s - for i := 1; i < len(sigs); i++ { - signature.Add(sigs[i].s) - } - return &Signature{s: &signature} +func AggregateSignatures(sigs []iface.Signature) iface.Signature { + return herumi.AggregateSignatures(sigs) } -// Aggregate is an alias for AggregateSignatures, defined to conform to BLS specification. -// -// In IETF draft BLS specification: -// Aggregate(signature_1, ..., signature_n) -> signature: an -// aggregation algorithm that compresses a collection of signatures -// into a single signature. -// -// In ETH2.0 specification: -// def Aggregate(signatures: Sequence[BLSSignature]) -> BLSSignature -// -// Deprecated: Use AggregateSignatures. -func Aggregate(sigs []*Signature) *Signature { - return AggregateSignatures(sigs) +// NewAggregateSignature creates a blank aggregate signature. +func NewAggregateSignature() iface.Signature { + return herumi.NewAggregateSignature() } -// Marshal a signature into a LittleEndian byte slice. -func (s *Signature) Marshal() []byte { - if featureconfig.Get().SkipBLSVerify { - return make([]byte, params.BeaconConfig().BLSSignatureLength) - } - - return s.s.Serialize() +// RandKey creates a new private key using a random input. +func RandKey() iface.SecretKey { + return herumi.RandKey() } diff --git a/shared/bls/bls_test.go b/shared/bls/bls_test.go deleted file mode 100644 index 7ca937ffa9..0000000000 --- a/shared/bls/bls_test.go +++ /dev/null @@ -1,285 +0,0 @@ -package bls_test - -import ( - "bytes" - "errors" - "testing" - - "github.com/prysmaticlabs/prysm/shared/bls" - "github.com/prysmaticlabs/prysm/shared/bytesutil" -) - -func TestMarshalUnmarshal(t *testing.T) { - b := bls.RandKey().Marshal() - b32 := bytesutil.ToBytes32(b) - pk, err := bls.SecretKeyFromBytes(b32[:]) - if err != nil { - t.Fatal(err) - } - pk2, err := bls.SecretKeyFromBytes(b32[:]) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(pk.Marshal(), pk2.Marshal()) { - t.Errorf("Keys not equal, received %#x == %#x", pk.Marshal(), pk2.Marshal()) - } -} - -func TestSignVerify(t *testing.T) { - priv := bls.RandKey() - pub := priv.PublicKey() - msg := []byte("hello") - sig := priv.Sign(msg) - if !sig.Verify(pub, msg) { - t.Error("Signature did not verify") - } -} - -func TestAggregateVerify(t *testing.T) { - pubkeys := make([]*bls.PublicKey, 0, 100) - sigs := make([]*bls.Signature, 0, 100) - var msgs [][32]byte - for i := 0; i < 100; i++ { - msg := [32]byte{'h', 'e', 'l', 'l', 'o', byte(i)} - priv := bls.RandKey() - pub := priv.PublicKey() - sig := priv.Sign(msg[:]) - pubkeys = append(pubkeys, pub) - sigs = append(sigs, sig) - msgs = append(msgs, msg) - } - aggSig := bls.Aggregate(sigs) - if !aggSig.AggregateVerify(pubkeys, msgs) { - t.Error("Signature did not verify") - } -} - -func TestFastAggregateVerify(t *testing.T) { - pubkeys := make([]*bls.PublicKey, 0, 100) - sigs := make([]*bls.Signature, 0, 100) - msg := [32]byte{'h', 'e', 'l', 'l', 'o'} - for i := 0; i < 100; i++ { - priv := bls.RandKey() - pub := priv.PublicKey() - sig := priv.Sign(msg[:]) - pubkeys = append(pubkeys, pub) - sigs = append(sigs, sig) - } - aggSig := bls.AggregateSignatures(sigs) - if !aggSig.FastAggregateVerify(pubkeys, msg) { - t.Error("Signature did not verify") - } -} - -func TestFastAggregateVerify_ReturnsFalseOnEmptyPubKeyList(t *testing.T) { - var pubkeys []*bls.PublicKey - sigs := make([]*bls.Signature, 0, 100) - msg := [32]byte{'h', 'e', 'l', 'l', 'o'} - - aggSig := bls.AggregateSignatures(sigs) - if aggSig.FastAggregateVerify(pubkeys, msg) != false { - t.Error("Expected FastAggregateVerify to return false with empty input " + - "of public keys.") - } -} - -func TestSecretKeyFromBytes(t *testing.T) { - tests := []struct { - name string - input []byte - err error - }{ - { - name: "Nil", - err: errors.New("secret key must be 32 bytes"), - }, - { - name: "Empty", - input: []byte{}, - err: errors.New("secret key must be 32 bytes"), - }, - { - name: "Short", - input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - err: errors.New("secret key must be 32 bytes"), - }, - { - name: "Long", - input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - err: errors.New("secret key must be 32 bytes"), - }, - { - name: "Bad", - input: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - err: errors.New("could not unmarshal bytes into secret key: err blsSecretKeyDeserialize ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - }, - { - name: "Good", - input: []byte{0x25, 0x29, 0x5f, 0x0d, 0x1d, 0x59, 0x2a, 0x90, 0xb3, 0x33, 0xe2, 0x6e, 0x85, 0x14, 0x97, 0x08, 0x20, 0x8e, 0x9f, 0x8e, 0x8b, 0xc1, 0x8f, 0x6c, 0x77, 0xbd, 0x62, 0xf8, 0xad, 0x7a, 0x68, 0x66}, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - res, err := bls.SecretKeyFromBytes(test.input) - if test.err != nil { - if err == nil { - t.Errorf("No error returned: expected %v", test.err) - } else if test.err.Error() != err.Error() { - t.Errorf("Unexpected error returned: expected %v, received %v", test.err, err) - } - } else { - if err != nil { - t.Errorf("Unexpected error returned: %v", err) - } else { - if bytes.Compare(res.Marshal(), test.input) != 0 { - t.Errorf("Unexpected result: expected %x, received %x", test.input, res.Marshal()) - } - } - } - - }) - } -} - -func TestPublicKeyFromBytes(t *testing.T) { - tests := []struct { - name string - input []byte - err error - }{ - { - name: "Nil", - err: errors.New("public key must be 48 bytes"), - }, - { - name: "Empty", - input: []byte{}, - err: errors.New("public key must be 48 bytes"), - }, - { - name: "Short", - input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - err: errors.New("public key must be 48 bytes"), - }, - { - name: "Long", - input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - err: errors.New("public key must be 48 bytes"), - }, - { - name: "Bad", - input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - err: errors.New("could not unmarshal bytes into public key: err blsPublicKeyDeserialize 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), - }, - { - name: "Good", - input: []byte{0xa9, 0x9a, 0x76, 0xed, 0x77, 0x96, 0xf7, 0xbe, 0x22, 0xd5, 0xb7, 0xe8, 0x5d, 0xee, 0xb7, 0xc5, 0x67, 0x7e, 0x88, 0xe5, 0x11, 0xe0, 0xb3, 0x37, 0x61, 0x8f, 0x8c, 0x4e, 0xb6, 0x13, 0x49, 0xb4, 0xbf, 0x2d, 0x15, 0x3f, 0x64, 0x9f, 0x7b, 0x53, 0x35, 0x9f, 0xe8, 0xb9, 0x4a, 0x38, 0xe4, 0x4c}, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - res, err := bls.PublicKeyFromBytes(test.input) - if test.err != nil { - if err == nil { - t.Errorf("No error returned: expected %v", test.err) - } else if test.err.Error() != err.Error() { - t.Errorf("Unexpected error returned: expected %v, received %v", test.err, err) - } - } else { - if err != nil { - t.Errorf("Unexpected error returned: %v", err) - } else { - if bytes.Compare(res.Marshal(), test.input) != 0 { - t.Errorf("Unexpected result: expected %x, received %x", test.input, res.Marshal()) - } - } - } - - }) - } -} - -func TestSignatureFromBytes(t *testing.T) { - tests := []struct { - name string - input []byte - err error - }{ - { - name: "Nil", - err: errors.New("signature must be 96 bytes"), - }, - { - name: "Empty", - input: []byte{}, - err: errors.New("signature must be 96 bytes"), - }, - { - name: "Short", - input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - err: errors.New("signature must be 96 bytes"), - }, - { - name: "Long", - input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - err: errors.New("signature must be 96 bytes"), - }, - { - name: "Bad", - input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - err: errors.New("could not unmarshal bytes into signature: err blsSignatureDeserialize 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), - }, - { - name: "Good", - input: []byte{0xab, 0xb0, 0x12, 0x4c, 0x75, 0x74, 0xf2, 0x81, 0xa2, 0x93, 0xf4, 0x18, 0x5c, 0xad, 0x3c, 0xb2, 0x26, 0x81, 0xd5, 0x20, 0x91, 0x7c, 0xe4, 0x66, 0x65, 0x24, 0x3e, 0xac, 0xb0, 0x51, 0x00, 0x0d, 0x8b, 0xac, 0xf7, 0x5e, 0x14, 0x51, 0x87, 0x0c, 0xa6, 0xb3, 0xb9, 0xe6, 0xc9, 0xd4, 0x1a, 0x7b, 0x02, 0xea, 0xd2, 0x68, 0x5a, 0x84, 0x18, 0x8a, 0x4f, 0xaf, 0xd3, 0x82, 0x5d, 0xaf, 0x6a, 0x98, 0x96, 0x25, 0xd7, 0x19, 0xcc, 0xd2, 0xd8, 0x3a, 0x40, 0x10, 0x1f, 0x4a, 0x45, 0x3f, 0xca, 0x62, 0x87, 0x8c, 0x89, 0x0e, 0xca, 0x62, 0x23, 0x63, 0xf9, 0xdd, 0xb8, 0xf3, 0x67, 0xa9, 0x1e, 0x84}, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - res, err := bls.SignatureFromBytes(test.input) - if test.err != nil { - if err == nil { - t.Errorf("No error returned: expected %v", test.err) - } else if test.err.Error() != err.Error() { - t.Errorf("Unexpected error returned: expected %v, received %v", test.err, err) - } - } else { - if err != nil { - t.Errorf("Unexpected error returned: %v", err) - } else { - if bytes.Compare(res.Marshal(), test.input) != 0 { - t.Errorf("Unexpected result: expected %x, received %x", test.input, res.Marshal()) - } - } - } - - }) - } -} - -func TestPublicKey_Copy(t *testing.T) { - pubkeyA := bls.RandKey().PublicKey() - pubkeyBytes := pubkeyA.Marshal() - - pubkeyB, err := pubkeyA.Copy() - if err != nil { - t.Fatal(err) - } - pubkeyB.Aggregate(bls.RandKey().PublicKey()) - - if !bytes.Equal(pubkeyA.Marshal(), pubkeyBytes) { - t.Fatal("Pubkey was mutated after copy") - } -} - -func TestSerialize(t *testing.T) { - rk := bls.RandKey() - b := rk.Marshal() - - if _, err := bls.SecretKeyFromBytes(b); err != nil { - t.Error(err) - } -} diff --git a/shared/bls/constants.go b/shared/bls/constants.go new file mode 100644 index 0000000000..f66aa5517a --- /dev/null +++ b/shared/bls/constants.go @@ -0,0 +1,7 @@ +package bls + +// DomainByteLength length of domain byte array. +const DomainByteLength = 4 + +// CurveOrder for the BLS12-381 curve. +const CurveOrder = "52435875175126190479447740508185965837690552500527637822603658699938581184513" diff --git a/shared/bls/herumi/BUILD.bazel b/shared/bls/herumi/BUILD.bazel new file mode 100644 index 0000000000..03532ece33 --- /dev/null +++ b/shared/bls/herumi/BUILD.bazel @@ -0,0 +1,66 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_test") +load("@prysm//tools/go:def.bzl", "go_library") + +# gazelle:resolve go github.com/herumi/bls-eth-go-binary/bls @herumi_bls_eth_go_binary//:go_default_library + +go_library( + name = "go_default_library", + srcs = [ + "docs.go", + "init.go", + "public_key.go", + "secret_key.go", + "signature.go", + ], + importpath = "github.com/prysmaticlabs/prysm/shared/bls/herumi", + visibility = [ + "//shared/bls:__pkg__", + ], + deps = [ + "//shared/bls/iface:go_default_library", + "//shared/featureconfig:go_default_library", + "//shared/params:go_default_library", + "@com_github_dgraph_io_ristretto//:go_default_library", + "@com_github_pkg_errors//:go_default_library", + "@herumi_bls_eth_go_binary//:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = [ + "public_key_test.go", + "secret_key_test.go", + "signature_test.go", + ], + embed = [":go_default_library"], + deps = [ + "//shared/bls/iface:go_default_library", + "//shared/bytesutil:go_default_library", + ], +) + +# gazelle:exclude bls_benchmark_test.go +go_test( + name = "go_benchmark_test", + size = "small", + srcs = ["bls_benchmark_test.go"], + args = [ + "-test.bench=.", + "-test.benchmem", + "-test.v", + ], + local = True, + tags = [ + "benchmark", + "manual", + "no-cache", + ], + deps = [ + ":go_default_library", + "//shared/bls/iface:go_default_library", + "//shared/bytesutil:go_default_library", + "//shared/hashutil:go_default_library", + "@herumi_bls_eth_go_binary//:go_default_library", + ], +) diff --git a/shared/bls/bls_benchmark_test.go b/shared/bls/herumi/bls_benchmark_test.go similarity index 68% rename from shared/bls/bls_benchmark_test.go rename to shared/bls/herumi/bls_benchmark_test.go index 4e69af869f..4ee905921c 100644 --- a/shared/bls/bls_benchmark_test.go +++ b/shared/bls/herumi/bls_benchmark_test.go @@ -1,23 +1,24 @@ -package bls_test +package herumi_test import ( "testing" - bls2 "github.com/herumi/bls-eth-go-binary/bls" - "github.com/prysmaticlabs/prysm/shared/bls" + "github.com/herumi/bls-eth-go-binary/bls" + "github.com/prysmaticlabs/prysm/shared/bls/herumi" + "github.com/prysmaticlabs/prysm/shared/bls/iface" "github.com/prysmaticlabs/prysm/shared/hashutil" ) func BenchmarkPairing(b *testing.B) { - if err := bls2.Init(bls2.BLS12_381); err != nil { + if err := bls.Init(bls.BLS12_381); err != nil { b.Fatal(err) } - if err := bls2.SetETHmode(bls2.EthModeDraft05); err != nil { + if err := bls.SetETHmode(bls.EthModeDraft07); err != nil { panic(err) } - newGt := &bls2.GT{} - newG1 := &bls2.G1{} - newG2 := &bls2.G2{} + newGt := &bls.GT{} + newG1 := &bls.G1{} + newG2 := &bls.G2{} newGt.SetInt64(10) hash := hashutil.Hash([]byte{}) @@ -33,12 +34,12 @@ func BenchmarkPairing(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { - bls2.Pairing(newGt, newG1, newG2) + bls.Pairing(newGt, newG1, newG2) } } func BenchmarkSignature_Verify(b *testing.B) { - sk := bls.RandKey() + sk := herumi.RandKey() msg := []byte("Some msg") sig := sk.Sign(msg) @@ -54,18 +55,18 @@ func BenchmarkSignature_Verify(b *testing.B) { func BenchmarkSignature_AggregateVerify(b *testing.B) { sigN := 128 // MAX_ATTESTATIONS per block. - var pks []*bls.PublicKey - var sigs []*bls.Signature + var pks []iface.PublicKey + var sigs []iface.Signature var msgs [][32]byte for i := 0; i < sigN; i++ { msg := [32]byte{'s', 'i', 'g', 'n', 'e', 'd', byte(i)} - sk := bls.RandKey() + sk := herumi.RandKey() sig := sk.Sign(msg[:]) pks = append(pks, sk.PublicKey()) sigs = append(sigs, sig) msgs = append(msgs, msg) } - aggregated := bls.Aggregate(sigs) + aggregated := herumi.Aggregate(sigs) b.ResetTimer() b.ReportAllocs() @@ -77,12 +78,12 @@ func BenchmarkSignature_AggregateVerify(b *testing.B) { } func BenchmarkSecretKey_Marshal(b *testing.B) { - key := bls.RandKey() + key := herumi.RandKey() d := key.Marshal() b.ResetTimer() for i := 0; i < b.N; i++ { - _, err := bls.SecretKeyFromBytes(d) + _, err := herumi.SecretKeyFromBytes(d) _ = err } } diff --git a/shared/bls/herumi/docs.go b/shared/bls/herumi/docs.go new file mode 100644 index 0000000000..c3d0a30517 --- /dev/null +++ b/shared/bls/herumi/docs.go @@ -0,0 +1,6 @@ +// Package herumi implements a go-wrapper around a library implementing the +// the BLS12-381 curve and signature scheme. This package exposes a public API for +// verifying and aggregating BLS signatures used by Ethereum 2.0. +// +// This implementation uses the library written by Herumi. +package herumi diff --git a/shared/bls/herumi/init.go b/shared/bls/herumi/init.go new file mode 100644 index 0000000000..f6fb807d0b --- /dev/null +++ b/shared/bls/herumi/init.go @@ -0,0 +1,12 @@ +package herumi + +import "github.com/herumi/bls-eth-go-binary/bls" + +func init() { + if err := bls.Init(bls.BLS12_381); err != nil { + panic(err) + } + if err := bls.SetETHmode(bls.EthModeDraft07); err != nil { + panic(err) + } +} diff --git a/shared/bls/herumi/public_key.go b/shared/bls/herumi/public_key.go new file mode 100644 index 0000000000..862df9f67f --- /dev/null +++ b/shared/bls/herumi/public_key.go @@ -0,0 +1,65 @@ +package herumi + +import ( + "fmt" + + "github.com/dgraph-io/ristretto" + bls12 "github.com/herumi/bls-eth-go-binary/bls" + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/shared/bls/iface" + "github.com/prysmaticlabs/prysm/shared/featureconfig" + "github.com/prysmaticlabs/prysm/shared/params" +) + +var maxKeys = int64(100000) +var pubkeyCache, _ = ristretto.NewCache(&ristretto.Config{ + NumCounters: maxKeys, + MaxCost: 1 << 22, // ~4mb is cache max size + BufferItems: 64, +}) + +// PublicKey used in the BLS signature scheme. +type PublicKey struct { + p *bls12.PublicKey +} + +// PublicKeyFromBytes creates a BLS public key from a BigEndian byte slice. +func PublicKeyFromBytes(pubKey []byte) (iface.PublicKey, error) { + if featureconfig.Get().SkipBLSVerify { + return &PublicKey{}, nil + } + if len(pubKey) != params.BeaconConfig().BLSPubkeyLength { + return nil, fmt.Errorf("public key must be %d bytes", params.BeaconConfig().BLSPubkeyLength) + } + if cv, ok := pubkeyCache.Get(string(pubKey)); ok { + return cv.(*PublicKey).Copy(), nil + } + p := &bls12.PublicKey{} + err := p.Deserialize(pubKey) + if err != nil { + return nil, errors.Wrap(err, "could not unmarshal bytes into public key") + } + pubKeyObj := &PublicKey{p: p} + pubkeyCache.Set(string(pubKey), pubKeyObj.Copy(), 48) + return pubKeyObj, nil +} + +// Marshal a public key into a LittleEndian byte slice. +func (p *PublicKey) Marshal() []byte { + return p.p.Serialize() +} + +// Copy the public key to a new pointer reference. +func (p *PublicKey) Copy() iface.PublicKey { + np := *p.p + return &PublicKey{p: &np} +} + +// Aggregate two public keys. +func (p *PublicKey) Aggregate(p2 iface.PublicKey) iface.PublicKey { + if featureconfig.Get().SkipBLSVerify { + return p + } + p.p.Add(p2.(*PublicKey).p) + return p +} diff --git a/shared/bls/herumi/public_key_test.go b/shared/bls/herumi/public_key_test.go new file mode 100644 index 0000000000..f943a2e58b --- /dev/null +++ b/shared/bls/herumi/public_key_test.go @@ -0,0 +1,80 @@ +package herumi_test + +import ( + "bytes" + "errors" + "testing" + + "github.com/prysmaticlabs/prysm/shared/bls/herumi" +) + +func TestPublicKeyFromBytes(t *testing.T) { + tests := []struct { + name string + input []byte + err error + }{ + { + name: "Nil", + err: errors.New("public key must be 48 bytes"), + }, + { + name: "Empty", + input: []byte{}, + err: errors.New("public key must be 48 bytes"), + }, + { + name: "Short", + input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + err: errors.New("public key must be 48 bytes"), + }, + { + name: "Long", + input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + err: errors.New("public key must be 48 bytes"), + }, + { + name: "Bad", + input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + err: errors.New("could not unmarshal bytes into public key: err blsPublicKeyDeserialize 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + }, + { + name: "Good", + input: []byte{0xa9, 0x9a, 0x76, 0xed, 0x77, 0x96, 0xf7, 0xbe, 0x22, 0xd5, 0xb7, 0xe8, 0x5d, 0xee, 0xb7, 0xc5, 0x67, 0x7e, 0x88, 0xe5, 0x11, 0xe0, 0xb3, 0x37, 0x61, 0x8f, 0x8c, 0x4e, 0xb6, 0x13, 0x49, 0xb4, 0xbf, 0x2d, 0x15, 0x3f, 0x64, 0x9f, 0x7b, 0x53, 0x35, 0x9f, 0xe8, 0xb9, 0x4a, 0x38, 0xe4, 0x4c}, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + res, err := herumi.PublicKeyFromBytes(test.input) + if test.err != nil { + if err == nil { + t.Errorf("No error returned: expected %v", test.err) + } else if test.err.Error() != err.Error() { + t.Errorf("Unexpected error returned: expected %v, received %v", test.err, err) + } + } else { + if err != nil { + t.Errorf("Unexpected error returned: %v", err) + } else { + if bytes.Compare(res.Marshal(), test.input) != 0 { + t.Errorf("Unexpected result: expected %x, received %x", test.input, res.Marshal()) + } + } + } + + }) + } +} + +func TestPublicKey_Copy(t *testing.T) { + pubkeyA := herumi.RandKey().PublicKey() + pubkeyBytes := pubkeyA.Marshal() + + pubkeyB := pubkeyA.Copy() + pubkeyB.Aggregate(herumi.RandKey().PublicKey()) + + if !bytes.Equal(pubkeyA.Marshal(), pubkeyBytes) { + t.Fatal("Pubkey was mutated after copy") + } +} diff --git a/shared/bls/herumi/secret_key.go b/shared/bls/herumi/secret_key.go new file mode 100644 index 0000000000..85b559434f --- /dev/null +++ b/shared/bls/herumi/secret_key.go @@ -0,0 +1,67 @@ +package herumi + +import ( + "fmt" + + bls12 "github.com/herumi/bls-eth-go-binary/bls" + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/shared/bls/iface" + "github.com/prysmaticlabs/prysm/shared/featureconfig" + "github.com/prysmaticlabs/prysm/shared/params" +) + +// bls12SecretKey used in the BLS signature scheme. +type bls12SecretKey struct { + p *bls12.SecretKey +} + +// RandKey creates a new private key using a random method provided as an io.Reader. +func RandKey() iface.SecretKey { + secKey := &bls12.SecretKey{} + secKey.SetByCSPRNG() + return &bls12SecretKey{secKey} +} + +// SecretKeyFromBytes creates a BLS private key from a BigEndian byte slice. +func SecretKeyFromBytes(privKey []byte) (iface.SecretKey, error) { + if len(privKey) != params.BeaconConfig().BLSSecretKeyLength { + return nil, fmt.Errorf("secret key must be %d bytes", params.BeaconConfig().BLSSecretKeyLength) + } + secKey := &bls12.SecretKey{} + err := secKey.Deserialize(privKey) + if err != nil { + return nil, errors.Wrap(err, "could not unmarshal bytes into secret key") + } + return &bls12SecretKey{p: secKey}, err +} + +// PublicKey obtains the public key corresponding to the BLS secret key. +func (s *bls12SecretKey) PublicKey() iface.PublicKey { + return &PublicKey{p: s.p.GetPublicKey()} +} + +// Sign a message using a secret key - in a beacon/validator client. +// +// In IETF draft BLS specification: +// Sign(SK, message) -> signature: a signing algorithm that generates +// a deterministic signature given a secret key SK and a message. +// +// In ETH2.0 specification: +// def Sign(SK: int, message: Bytes) -> BLSSignature +func (s *bls12SecretKey) Sign(msg []byte) iface.Signature { + if featureconfig.Get().SkipBLSVerify { + return &Signature{} + } + signature := s.p.SignByte(msg) + return &Signature{s: signature} +} + +// Marshal a secret key into a LittleEndian byte slice. +func (s *bls12SecretKey) Marshal() []byte { + keyBytes := s.p.Serialize() + if len(keyBytes) < params.BeaconConfig().BLSSecretKeyLength { + emptyBytes := make([]byte, params.BeaconConfig().BLSSecretKeyLength-len(keyBytes)) + keyBytes = append(emptyBytes, keyBytes...) + } + return keyBytes +} diff --git a/shared/bls/herumi/secret_key_test.go b/shared/bls/herumi/secret_key_test.go new file mode 100644 index 0000000000..cc69fdb3b3 --- /dev/null +++ b/shared/bls/herumi/secret_key_test.go @@ -0,0 +1,94 @@ +package herumi_test + +import ( + "bytes" + "errors" + "testing" + + "github.com/prysmaticlabs/prysm/shared/bls/herumi" + "github.com/prysmaticlabs/prysm/shared/bytesutil" +) + +func TestMarshalUnmarshal(t *testing.T) { + b := herumi.RandKey().Marshal() + b32 := bytesutil.ToBytes32(b) + pk, err := herumi.SecretKeyFromBytes(b32[:]) + if err != nil { + t.Fatal(err) + } + pk2, err := herumi.SecretKeyFromBytes(b32[:]) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(pk.Marshal(), pk2.Marshal()) { + t.Errorf("Keys not equal, received %#x == %#x", pk.Marshal(), pk2.Marshal()) + } +} + +func TestSecretKeyFromBytes(t *testing.T) { + tests := []struct { + name string + input []byte + err error + }{ + { + name: "Nil", + err: errors.New("secret key must be 32 bytes"), + }, + { + name: "Empty", + input: []byte{}, + err: errors.New("secret key must be 32 bytes"), + }, + { + name: "Short", + input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + err: errors.New("secret key must be 32 bytes"), + }, + { + name: "Long", + input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + err: errors.New("secret key must be 32 bytes"), + }, + { + name: "Bad", + input: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + err: errors.New("could not unmarshal bytes into secret key: err blsSecretKeyDeserialize ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + }, + { + name: "Good", + input: []byte{0x25, 0x29, 0x5f, 0x0d, 0x1d, 0x59, 0x2a, 0x90, 0xb3, 0x33, 0xe2, 0x6e, 0x85, 0x14, 0x97, 0x08, 0x20, 0x8e, 0x9f, 0x8e, 0x8b, 0xc1, 0x8f, 0x6c, 0x77, 0xbd, 0x62, 0xf8, 0xad, 0x7a, 0x68, 0x66}, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + res, err := herumi.SecretKeyFromBytes(test.input) + if test.err != nil { + if err == nil { + t.Errorf("No error returned: expected %v", test.err) + } else if test.err.Error() != err.Error() { + t.Errorf("Unexpected error returned: expected %v, received %v", test.err, err) + } + } else { + if err != nil { + t.Errorf("Unexpected error returned: %v", err) + } else { + if bytes.Compare(res.Marshal(), test.input) != 0 { + t.Errorf("Unexpected result: expected %x, received %x", test.input, res.Marshal()) + } + } + } + + }) + } +} + +func TestSerialize(t *testing.T) { + rk := herumi.RandKey() + b := rk.Marshal() + + if _, err := herumi.SecretKeyFromBytes(b); err != nil { + t.Error(err) + } +} diff --git a/shared/bls/herumi/signature.go b/shared/bls/herumi/signature.go new file mode 100644 index 0000000000..f92d0971a7 --- /dev/null +++ b/shared/bls/herumi/signature.go @@ -0,0 +1,157 @@ +package herumi + +import ( + "fmt" + + bls12 "github.com/herumi/bls-eth-go-binary/bls" + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/shared/bls/iface" + "github.com/prysmaticlabs/prysm/shared/featureconfig" + "github.com/prysmaticlabs/prysm/shared/params" +) + +// Signature used in the BLS signature scheme. +type Signature struct { + s *bls12.Sign +} + +// SignatureFromBytes creates a BLS signature from a LittleEndian byte slice. +func SignatureFromBytes(sig []byte) (iface.Signature, error) { + if featureconfig.Get().SkipBLSVerify { + return &Signature{}, nil + } + if len(sig) != params.BeaconConfig().BLSSignatureLength { + return nil, fmt.Errorf("signature must be %d bytes", params.BeaconConfig().BLSSignatureLength) + } + signature := &bls12.Sign{} + err := signature.Deserialize(sig) + if err != nil { + return nil, errors.Wrap(err, "could not unmarshal bytes into signature") + } + return &Signature{s: signature}, nil +} + +// Verify a bls signature given a public key, a message. +// +// In IETF draft BLS specification: +// Verify(PK, message, signature) -> VALID or INVALID: a verification +// algorithm that outputs VALID if signature is a valid signature of +// message under public key PK, and INVALID otherwise. +// +// In ETH2.0 specification: +// def Verify(PK: BLSPubkey, message: Bytes, signature: BLSSignature) -> bool +func (s *Signature) Verify(pubKey iface.PublicKey, msg []byte) bool { + if featureconfig.Get().SkipBLSVerify { + return true + } + return s.s.VerifyByte(pubKey.(*PublicKey).p, msg) +} + +// AggregateVerify verifies each public key against its respective message. +// This is vulnerable to rogue public-key attack. Each user must +// provide a proof-of-knowledge of the public key. +// +// In IETF draft BLS specification: +// AggregateVerify((PK_1, message_1), ..., (PK_n, message_n), +// signature) -> VALID or INVALID: an aggregate verification +// algorithm that outputs VALID if signature is a valid aggregated +// signature for a collection of public keys and messages, and +// outputs INVALID otherwise. +// +// In ETH2.0 specification: +// def AggregateVerify(pairs: Sequence[PK: BLSPubkey, message: Bytes], signature: BLSSignature) -> boo +func (s *Signature) AggregateVerify(pubKeys []iface.PublicKey, msgs [][32]byte) bool { + if featureconfig.Get().SkipBLSVerify { + return true + } + size := len(pubKeys) + if size == 0 { + return false + } + if size != len(msgs) { + return false + } + msgSlices := make([]byte, 0, 32*len(msgs)) + rawKeys := make([]bls12.PublicKey, 0, len(pubKeys)) + for i := 0; i < size; i++ { + msgSlices = append(msgSlices, msgs[i][:]...) + rawKeys = append(rawKeys, *(pubKeys[i].(*PublicKey).p)) + } + // Use "NoCheck" because we do not care if the messages are unique or not. + return s.s.AggregateVerifyNoCheck(rawKeys, msgSlices) +} + +// FastAggregateVerify verifies all the provided public keys with their aggregated signature. +// +// In IETF draft BLS specification: +// FastAggregateVerify(PK_1, ..., PK_n, message, signature) -> VALID +// or INVALID: a verification algorithm for the aggregate of multiple +// signatures on the same message. This function is faster than +// AggregateVerify. +// +// In ETH2.0 specification: +// def FastAggregateVerify(PKs: Sequence[BLSPubkey], message: Bytes, signature: BLSSignature) -> bool +func (s *Signature) FastAggregateVerify(pubKeys []iface.PublicKey, msg [32]byte) bool { + if featureconfig.Get().SkipBLSVerify { + return true + } + if len(pubKeys) == 0 { + return false + } + rawKeys := make([]bls12.PublicKey, len(pubKeys)) + for i := 0; i < len(pubKeys); i++ { + rawKeys[i] = *(pubKeys[i].(*PublicKey).p) + } + + return s.s.FastAggregateVerify(rawKeys, msg[:]) +} + +// NewAggregateSignature creates a blank aggregate signature. +func NewAggregateSignature() iface.Signature { + return &Signature{s: bls12.HashAndMapToSignature([]byte{'m', 'o', 'c', 'k'})} +} + +// AggregateSignatures converts a list of signatures into a single, aggregated sig. +func AggregateSignatures(sigs []iface.Signature) iface.Signature { + if len(sigs) == 0 { + return nil + } + if featureconfig.Get().SkipBLSVerify { + return sigs[0] + } + + signature := *sigs[0].Copy().(*Signature).s + for i := 1; i < len(sigs); i++ { + signature.Add(sigs[i].(*Signature).s) + } + return &Signature{s: &signature} +} + +// Aggregate is an alias for AggregateSignatures, defined to conform to BLS specification. +// +// In IETF draft BLS specification: +// Aggregate(signature_1, ..., signature_n) -> signature: an +// aggregation algorithm that compresses a collection of signatures +// into a single signature. +// +// In ETH2.0 specification: +// def Aggregate(signatures: Sequence[BLSSignature]) -> BLSSignature +// +// Deprecated: Use AggregateSignatures. +func Aggregate(sigs []iface.Signature) iface.Signature { + return AggregateSignatures(sigs) +} + +// Marshal a signature into a LittleEndian byte slice. +func (s *Signature) Marshal() []byte { + if featureconfig.Get().SkipBLSVerify { + return make([]byte, params.BeaconConfig().BLSSignatureLength) + } + + return s.s.Serialize() +} + +// Copy returns a full deep copy of a signature. +func (s *Signature) Copy() iface.Signature { + return &Signature{s: &*s.s} +} diff --git a/shared/bls/herumi/signature_test.go b/shared/bls/herumi/signature_test.go new file mode 100644 index 0000000000..9a95d33367 --- /dev/null +++ b/shared/bls/herumi/signature_test.go @@ -0,0 +1,127 @@ +package herumi_test + +import ( + "bytes" + "errors" + "testing" + + "github.com/prysmaticlabs/prysm/shared/bls/iface" + + "github.com/prysmaticlabs/prysm/shared/bls/herumi" +) + +func TestSignVerify(t *testing.T) { + priv := herumi.RandKey() + pub := priv.PublicKey() + msg := []byte("hello") + sig := priv.Sign(msg) + if !sig.Verify(pub, msg) { + t.Error("Signature did not verify") + } +} + +func TestAggregateVerify(t *testing.T) { + pubkeys := make([]iface.PublicKey, 0, 100) + sigs := make([]iface.Signature, 0, 100) + var msgs [][32]byte + for i := 0; i < 100; i++ { + msg := [32]byte{'h', 'e', 'l', 'l', 'o', byte(i)} + priv := herumi.RandKey() + pub := priv.PublicKey() + sig := priv.Sign(msg[:]) + pubkeys = append(pubkeys, pub) + sigs = append(sigs, sig) + msgs = append(msgs, msg) + } + aggSig := herumi.Aggregate(sigs) + if !aggSig.AggregateVerify(pubkeys, msgs) { + t.Error("Signature did not verify") + } +} + +func TestFastAggregateVerify(t *testing.T) { + pubkeys := make([]iface.PublicKey, 0, 100) + sigs := make([]iface.Signature, 0, 100) + msg := [32]byte{'h', 'e', 'l', 'l', 'o'} + for i := 0; i < 100; i++ { + priv := herumi.RandKey() + pub := priv.PublicKey() + sig := priv.Sign(msg[:]) + pubkeys = append(pubkeys, pub) + sigs = append(sigs, sig) + } + aggSig := herumi.AggregateSignatures(sigs) + if !aggSig.FastAggregateVerify(pubkeys, msg) { + t.Error("Signature did not verify") + } +} + +func TestFastAggregateVerify_ReturnsFalseOnEmptyPubKeyList(t *testing.T) { + var pubkeys []iface.PublicKey + msg := [32]byte{'h', 'e', 'l', 'l', 'o'} + + aggSig := herumi.NewAggregateSignature() + if aggSig.FastAggregateVerify(pubkeys, msg) != false { + t.Error("Expected FastAggregateVerify to return false with empty input " + + "of public keys.") + } +} + +func TestSignatureFromBytes(t *testing.T) { + tests := []struct { + name string + input []byte + err error + }{ + { + name: "Nil", + err: errors.New("signature must be 96 bytes"), + }, + { + name: "Empty", + input: []byte{}, + err: errors.New("signature must be 96 bytes"), + }, + { + name: "Short", + input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + err: errors.New("signature must be 96 bytes"), + }, + { + name: "Long", + input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + err: errors.New("signature must be 96 bytes"), + }, + { + name: "Bad", + input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + err: errors.New("could not unmarshal bytes into signature: err blsSignatureDeserialize 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + }, + { + name: "Good", + input: []byte{0xab, 0xb0, 0x12, 0x4c, 0x75, 0x74, 0xf2, 0x81, 0xa2, 0x93, 0xf4, 0x18, 0x5c, 0xad, 0x3c, 0xb2, 0x26, 0x81, 0xd5, 0x20, 0x91, 0x7c, 0xe4, 0x66, 0x65, 0x24, 0x3e, 0xac, 0xb0, 0x51, 0x00, 0x0d, 0x8b, 0xac, 0xf7, 0x5e, 0x14, 0x51, 0x87, 0x0c, 0xa6, 0xb3, 0xb9, 0xe6, 0xc9, 0xd4, 0x1a, 0x7b, 0x02, 0xea, 0xd2, 0x68, 0x5a, 0x84, 0x18, 0x8a, 0x4f, 0xaf, 0xd3, 0x82, 0x5d, 0xaf, 0x6a, 0x98, 0x96, 0x25, 0xd7, 0x19, 0xcc, 0xd2, 0xd8, 0x3a, 0x40, 0x10, 0x1f, 0x4a, 0x45, 0x3f, 0xca, 0x62, 0x87, 0x8c, 0x89, 0x0e, 0xca, 0x62, 0x23, 0x63, 0xf9, 0xdd, 0xb8, 0xf3, 0x67, 0xa9, 0x1e, 0x84}, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + res, err := herumi.SignatureFromBytes(test.input) + if test.err != nil { + if err == nil { + t.Errorf("No error returned: expected %v", test.err) + } else if test.err.Error() != err.Error() { + t.Errorf("Unexpected error returned: expected %v, received %v", test.err, err) + } + } else { + if err != nil { + t.Errorf("Unexpected error returned: %v", err) + } else { + if bytes.Compare(res.Marshal(), test.input) != 0 { + t.Errorf("Unexpected result: expected %x, received %x", test.input, res.Marshal()) + } + } + } + + }) + } +} diff --git a/shared/bls/iface/BUILD.bazel b/shared/bls/iface/BUILD.bazel new file mode 100644 index 0000000000..7c92325a2e --- /dev/null +++ b/shared/bls/iface/BUILD.bazel @@ -0,0 +1,8 @@ +load("@prysm//tools/go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["interface.go"], + importpath = "github.com/prysmaticlabs/prysm/shared/bls/iface", + visibility = ["//shared/bls:__subpackages__"], +) diff --git a/shared/bls/iface/interface.go b/shared/bls/iface/interface.go new file mode 100644 index 0000000000..ceff3f760c --- /dev/null +++ b/shared/bls/iface/interface.go @@ -0,0 +1,29 @@ +// Package iface provides the BLS interfaces that are implemented by the various BLS wrappers. +// +// This package should not be used by downstream consumers. These interfaces are re-exporter by +// github.com/prysmaticlabs/prysm/shared/bls. This package exists to prevent an import circular +// dependency. +package iface + +// SecretKey represents a BLS secret or private key. +type SecretKey interface { + PublicKey() PublicKey + Sign(msg []byte) Signature + Marshal() []byte +} + +// PublicKey represents a BLS public key. +type PublicKey interface { + Marshal() []byte + Copy() PublicKey + Aggregate(p2 PublicKey) PublicKey +} + +// Signature represents a BLS signature. +type Signature interface { + Verify(pubKey PublicKey, msg []byte) bool + AggregateVerify(pubKeys []PublicKey, msgs [][32]byte) bool + FastAggregateVerify(pubKeys []PublicKey, msg [32]byte) bool + Marshal() []byte + Copy() Signature +} diff --git a/shared/bls/interface.go b/shared/bls/interface.go new file mode 100644 index 0000000000..b569a64006 --- /dev/null +++ b/shared/bls/interface.go @@ -0,0 +1,14 @@ +package bls + +import ( + "github.com/prysmaticlabs/prysm/shared/bls/iface" +) + +// PublicKey represents a BLS public key. +type PublicKey = iface.PublicKey + +// SecretKey represents a BLS secret or private key. +type SecretKey = iface.SecretKey + +// Signature represents a BLS signature. +type Signature = iface.Signature diff --git a/shared/bls/spectest/BUILD.bazel b/shared/bls/spectest/BUILD.bazel index 3aedfc24f2..5c4d36d626 100644 --- a/shared/bls/spectest/BUILD.bazel +++ b/shared/bls/spectest/BUILD.bazel @@ -32,6 +32,7 @@ go_test( tags = ["spectest"], deps = [ "//shared/bls:go_default_library", + "//shared/bls/iface:go_default_library", "//shared/bytesutil:go_default_library", "//shared/testutil:go_default_library", "@com_github_ghodss_yaml//:go_default_library", diff --git a/shared/bls/spectest/aggregate_test.go b/shared/bls/spectest/aggregate_test.go index cb1d9cc30c..21c4236ac3 100644 --- a/shared/bls/spectest/aggregate_test.go +++ b/shared/bls/spectest/aggregate_test.go @@ -9,6 +9,7 @@ import ( "github.com/ghodss/yaml" "github.com/prysmaticlabs/prysm/shared/bls" + "github.com/prysmaticlabs/prysm/shared/bls/iface" "github.com/prysmaticlabs/prysm/shared/testutil" ) @@ -25,7 +26,7 @@ func TestAggregateYaml(t *testing.T) { if err := yaml.Unmarshal(file, test); err != nil { t.Fatalf("Failed to unmarshal: %v", err) } - var sigs []*bls.Signature + var sigs []iface.Signature for _, s := range test.Input { sigBytes, err := hex.DecodeString(s[2:]) if err != nil { diff --git a/shared/bls/spectest/aggregate_verify_test.go b/shared/bls/spectest/aggregate_verify_test.go index c6ab14f270..22d700ee02 100644 --- a/shared/bls/spectest/aggregate_verify_test.go +++ b/shared/bls/spectest/aggregate_verify_test.go @@ -7,6 +7,7 @@ import ( "github.com/ghodss/yaml" "github.com/prysmaticlabs/prysm/shared/bls" + "github.com/prysmaticlabs/prysm/shared/bls/iface" "github.com/prysmaticlabs/prysm/shared/bytesutil" "github.com/prysmaticlabs/prysm/shared/testutil" ) @@ -25,7 +26,7 @@ func TestAggregateVerifyYaml(t *testing.T) { t.Fatalf("Failed to unmarshal: %v", err) } - pubkeys := make([]*bls.PublicKey, 0, len(test.Input.Pubkeys)) + pubkeys := make([]iface.PublicKey, 0, len(test.Input.Pubkeys)) msgs := make([][32]byte, 0, len(test.Input.Messages)) for _, pubKey := range test.Input.Pubkeys { pkBytes, err := hex.DecodeString(pubKey[2:]) diff --git a/shared/bls/spectest/fast_aggregate_verify_test.go b/shared/bls/spectest/fast_aggregate_verify_test.go index 6ea7235325..3259a6fc3d 100644 --- a/shared/bls/spectest/fast_aggregate_verify_test.go +++ b/shared/bls/spectest/fast_aggregate_verify_test.go @@ -7,6 +7,7 @@ import ( "github.com/ghodss/yaml" "github.com/prysmaticlabs/prysm/shared/bls" + "github.com/prysmaticlabs/prysm/shared/bls/iface" "github.com/prysmaticlabs/prysm/shared/bytesutil" "github.com/prysmaticlabs/prysm/shared/testutil" ) @@ -25,7 +26,7 @@ func TestFastAggregateVerifyYaml(t *testing.T) { t.Fatalf("Failed to unmarshal: %v", err) } - pubkeys := make([]*bls.PublicKey, len(test.Input.Pubkeys)) + pubkeys := make([]iface.PublicKey, len(test.Input.Pubkeys)) for j, raw := range test.Input.Pubkeys { pkBytes, err := hex.DecodeString(raw[2:]) if err != nil { diff --git a/shared/interop/generate_genesis_state.go b/shared/interop/generate_genesis_state.go index 012f4e480c..cdc087cc40 100644 --- a/shared/interop/generate_genesis_state.go +++ b/shared/interop/generate_genesis_state.go @@ -98,7 +98,7 @@ func generateDepositsFromData(depositDataItems []*ethpb.Deposit_Data, offset int } // DepositDataFromKeys generates a list of deposit data items from a set of BLS validator keys. -func DepositDataFromKeys(privKeys []*bls.SecretKey, pubKeys []*bls.PublicKey) ([]*ethpb.Deposit_Data, [][]byte, error) { +func DepositDataFromKeys(privKeys []bls.SecretKey, pubKeys []bls.PublicKey) ([]*ethpb.Deposit_Data, [][]byte, error) { type depositData struct { items []*ethpb.Deposit_Data roots [][]byte @@ -123,7 +123,7 @@ func DepositDataFromKeys(privKeys []*bls.SecretKey, pubKeys []*bls.PublicKey) ([ return depositDataItems, depositDataRoots, nil } -func depositDataFromKeys(privKeys []*bls.SecretKey, pubKeys []*bls.PublicKey) ([]*ethpb.Deposit_Data, [][]byte, error) { +func depositDataFromKeys(privKeys []bls.SecretKey, pubKeys []bls.PublicKey) ([]*ethpb.Deposit_Data, [][]byte, error) { dataRoots := make([][]byte, len(privKeys)) depositDataItems := make([]*ethpb.Deposit_Data, len(privKeys)) for i := 0; i < len(privKeys); i++ { @@ -142,7 +142,7 @@ func depositDataFromKeys(privKeys []*bls.SecretKey, pubKeys []*bls.PublicKey) ([ } // Generates a deposit data item from BLS keys and signs the hash tree root of the data. -func createDepositData(privKey *bls.SecretKey, pubKey *bls.PublicKey) (*ethpb.Deposit_Data, error) { +func createDepositData(privKey bls.SecretKey, pubKey bls.PublicKey) (*ethpb.Deposit_Data, error) { di := ðpb.Deposit_Data{ PublicKey: pubKey.Marshal(), WithdrawalCredentials: withdrawalCredentialsHash(pubKey.Marshal()), diff --git a/shared/interop/generate_keys.go b/shared/interop/generate_keys.go index 33a8b79cfb..85fc0b60ca 100644 --- a/shared/interop/generate_keys.go +++ b/shared/interop/generate_keys.go @@ -18,12 +18,12 @@ const ( // DeterministicallyGenerateKeys creates BLS private keys using a fixed curve order according to // the algorithm specified in the Eth2.0-Specs interop mock start section found here: // https://github.com/ethereum/eth2.0-pm/blob/a085c9870f3956d6228ed2a40cd37f0c6580ecd7/interop/mocked_start/README.md -func DeterministicallyGenerateKeys(startIndex, numKeys uint64) ([]*bls.SecretKey, []*bls.PublicKey, error) { - privKeys := make([]*bls.SecretKey, numKeys) - pubKeys := make([]*bls.PublicKey, numKeys) +func DeterministicallyGenerateKeys(startIndex, numKeys uint64) ([]bls.SecretKey, []bls.PublicKey, error) { + privKeys := make([]bls.SecretKey, numKeys) + pubKeys := make([]bls.PublicKey, numKeys) type keys struct { - secrets []*bls.SecretKey - publics []*bls.PublicKey + secrets []bls.SecretKey + publics []bls.PublicKey } results, err := mputil.Scatter(int(numKeys), func(offset int, entries int, _ *sync.RWMutex) (interface{}, error) { secs, pubs, err := deterministicallyGenerateKeys(uint64(offset)+startIndex, uint64(entries)) @@ -43,9 +43,9 @@ func DeterministicallyGenerateKeys(startIndex, numKeys uint64) ([]*bls.SecretKey return privKeys, pubKeys, nil } -func deterministicallyGenerateKeys(startIndex, numKeys uint64) ([]*bls.SecretKey, []*bls.PublicKey, error) { - privKeys := make([]*bls.SecretKey, numKeys) - pubKeys := make([]*bls.PublicKey, numKeys) +func deterministicallyGenerateKeys(startIndex, numKeys uint64) ([]bls.SecretKey, []bls.PublicKey, error) { + privKeys := make([]bls.SecretKey, numKeys) + pubKeys := make([]bls.PublicKey, numKeys) for i := startIndex; i < startIndex+numKeys; i++ { enc := make([]byte, 32) binary.LittleEndian.PutUint32(enc, uint32(i)) diff --git a/shared/keystore/key.go b/shared/keystore/key.go index 9ee7cf3181..00f38d8fd5 100644 --- a/shared/keystore/key.go +++ b/shared/keystore/key.go @@ -56,9 +56,9 @@ const ( type Key struct { ID uuid.UUID // Version 4 "random" for unique id not derived from key data - PublicKey *bls.PublicKey // Represents the public key of the user. + PublicKey bls.PublicKey // Represents the public key of the user. - SecretKey *bls.SecretKey // Represents the private key of the user. + SecretKey bls.SecretKey // Represents the private key of the user. } type keyStore interface { @@ -138,7 +138,7 @@ func (k *Key) UnmarshalJSON(j []byte) (err error) { } // NewKeyFromBLS creates a new keystore Key type using a BLS private key. -func NewKeyFromBLS(blsKey *bls.SecretKey) (*Key, error) { +func NewKeyFromBLS(blsKey bls.SecretKey) (*Key, error) { id := uuid.NewRandom() pubkey := blsKey.PublicKey() key := &Key{ diff --git a/shared/keystore/utils.go b/shared/keystore/utils.go index 8c31039458..260946b84b 100644 --- a/shared/keystore/utils.go +++ b/shared/keystore/utils.go @@ -51,7 +51,7 @@ func ensureInt(x interface{}) int { // keyFileName implements the naming convention for keyfiles: // UTC--- -func keyFileName(pubkey *bls.PublicKey) string { +func keyFileName(pubkey bls.PublicKey) string { ts := roughtime.Now().UTC() return fmt.Sprintf("UTC--%s--%s", toISO8601(ts), hex.EncodeToString(pubkey.Marshal())[:8]) } diff --git a/shared/testutil/block.go b/shared/testutil/block.go index 2cd5f32cfd..ec1787dc99 100644 --- a/shared/testutil/block.go +++ b/shared/testutil/block.go @@ -64,7 +64,7 @@ func NewBeaconBlock() *ethpb.SignedBeaconBlock { // Use BlockGenConfig to declare the conditions you would like the block generated under. func GenerateFullBlock( bState *stateTrie.BeaconState, - privs []*bls.SecretKey, + privs []bls.SecretKey, conf *BlockGenConfig, slot uint64, ) (*ethpb.SignedBeaconBlock, error) { @@ -184,7 +184,7 @@ func GenerateFullBlock( // GenerateProposerSlashingForValidator for a specific validator index. func GenerateProposerSlashingForValidator( bState *stateTrie.BeaconState, - priv *bls.SecretKey, + priv bls.SecretKey, idx uint64, ) (*ethpb.ProposerSlashing, error) { header1 := ðpb.SignedBeaconBlockHeader{ @@ -230,7 +230,7 @@ func GenerateProposerSlashingForValidator( func generateProposerSlashings( bState *stateTrie.BeaconState, - privs []*bls.SecretKey, + privs []bls.SecretKey, numSlashings uint64, ) ([]*ethpb.ProposerSlashing, error) { proposerSlashings := make([]*ethpb.ProposerSlashing, numSlashings) @@ -251,7 +251,7 @@ func generateProposerSlashings( // GenerateAttesterSlashingForValidator for a specific validator index. func GenerateAttesterSlashingForValidator( bState *stateTrie.BeaconState, - priv *bls.SecretKey, + priv bls.SecretKey, idx uint64, ) (*ethpb.AttesterSlashing, error) { currentEpoch := helpers.CurrentEpoch(bState) @@ -280,7 +280,7 @@ func GenerateAttesterSlashingForValidator( return nil, err } sig := priv.Sign(dataRoot[:]) - att1.Signature = bls.AggregateSignatures([]*bls.Signature{sig}).Marshal() + att1.Signature = bls.AggregateSignatures([]bls.Signature{sig}).Marshal() att2 := ðpb.IndexedAttestation{ Data: ðpb.AttestationData{ @@ -302,7 +302,7 @@ func GenerateAttesterSlashingForValidator( return nil, err } sig = priv.Sign(dataRoot[:]) - att2.Signature = bls.AggregateSignatures([]*bls.Signature{sig}).Marshal() + att2.Signature = bls.AggregateSignatures([]bls.Signature{sig}).Marshal() return ðpb.AttesterSlashing{ Attestation_1: att1, @@ -312,7 +312,7 @@ func GenerateAttesterSlashingForValidator( func generateAttesterSlashings( bState *stateTrie.BeaconState, - privs []*bls.SecretKey, + privs []bls.SecretKey, numSlashings uint64, ) ([]*ethpb.AttesterSlashing, error) { attesterSlashings := make([]*ethpb.AttesterSlashing, numSlashings) @@ -340,7 +340,7 @@ func generateAttesterSlashings( // for the same data with their aggregation bits split uniformly. // // If you request 4 attestations, but there are 8 committees, you will get 4 fully aggregated attestations. -func GenerateAttestations(bState *stateTrie.BeaconState, privs []*bls.SecretKey, numToGen uint64, slot uint64, randomRoot bool) ([]*ethpb.Attestation, error) { +func GenerateAttestations(bState *stateTrie.BeaconState, privs []bls.SecretKey, numToGen uint64, slot uint64, randomRoot bool) ([]*ethpb.Attestation, error) { currentEpoch := helpers.SlotToEpoch(slot) attestations := []*ethpb.Attestation{} generateHeadState := false @@ -447,7 +447,7 @@ func GenerateAttestations(bState *stateTrie.BeaconState, privs []*bls.SecretKey, bitsPerAtt := committeeSize / uint64(attsPerCommittee) for i := uint64(0); i < committeeSize; i += bitsPerAtt { aggregationBits := bitfield.NewBitlist(committeeSize) - sigs := []*bls.Signature{} + sigs := []bls.Signature{} for b := i; b < i+bitsPerAtt; b++ { aggregationBits.SetBitAt(b, true) sigs = append(sigs, privs[committee[b]].Sign(dataRoot[:])) @@ -491,7 +491,7 @@ func generateDepositsAndEth1Data( func generateVoluntaryExits( bState *stateTrie.BeaconState, - privs []*bls.SecretKey, + privs []bls.SecretKey, numExits uint64, ) ([]*ethpb.SignedVoluntaryExit, error) { currentEpoch := helpers.CurrentEpoch(bState) diff --git a/shared/testutil/deposits.go b/shared/testutil/deposits.go index 58a87e8219..b8aaf75678 100644 --- a/shared/testutil/deposits.go +++ b/shared/testutil/deposits.go @@ -23,7 +23,7 @@ var lock sync.Mutex // Caches var cachedDeposits []*ethpb.Deposit -var privKeys []*bls.SecretKey +var privKeys []bls.SecretKey var trie *trieutil.SparseMerkleTrie // DeterministicDepositsAndKeys returns the entered amount of deposits and secret keys. @@ -31,7 +31,7 @@ var trie *trieutil.SparseMerkleTrie // account is key n and the withdrawal account is key n+1. As such, // if all secret keys for n validators are required then numDeposits // should be n+1. -func DeterministicDepositsAndKeys(numDeposits uint64) ([]*ethpb.Deposit, []*bls.SecretKey, error) { +func DeterministicDepositsAndKeys(numDeposits uint64) ([]*ethpb.Deposit, []bls.SecretKey, error) { lock.Lock() defer lock.Unlock() var err error @@ -152,7 +152,7 @@ func DeterministicEth1Data(size int) (*ethpb.Eth1Data, error) { } // DeterministicGenesisState returns a genesis state made using the deterministic deposits. -func DeterministicGenesisState(t testing.TB, numValidators uint64) (*stateTrie.BeaconState, []*bls.SecretKey) { +func DeterministicGenesisState(t testing.TB, numValidators uint64) (*stateTrie.BeaconState, []bls.SecretKey) { deposits, privKeys, err := DeterministicDepositsAndKeys(numValidators) if err != nil { t.Fatal(errors.Wrapf(err, "failed to get %d deposits", numValidators)) @@ -196,14 +196,14 @@ func DepositTrieFromDeposits(deposits []*ethpb.Deposit) (*trieutil.SparseMerkleT // ResetCache clears out the old trie, private keys and deposits. func ResetCache() { trie = nil - privKeys = []*bls.SecretKey{} + privKeys = []bls.SecretKey{} cachedDeposits = []*ethpb.Deposit{} } // DeterministicDepositsAndKeysSameValidator returns the entered amount of deposits and secret keys // of the same validator. This is for negative test cases such as same deposits from same validators in a block don't // result in duplicated validator indices. -func DeterministicDepositsAndKeysSameValidator(numDeposits uint64) ([]*ethpb.Deposit, []*bls.SecretKey, error) { +func DeterministicDepositsAndKeysSameValidator(numDeposits uint64) ([]*ethpb.Deposit, []bls.SecretKey, error) { lock.Lock() defer lock.Unlock() var err error diff --git a/shared/testutil/helpers.go b/shared/testutil/helpers.go index d05dd01ccc..0d8777cb5a 100644 --- a/shared/testutil/helpers.go +++ b/shared/testutil/helpers.go @@ -16,7 +16,7 @@ import ( ) // RandaoReveal returns a signature of the requested epoch using the beacon proposer private key. -func RandaoReveal(beaconState *stateTrie.BeaconState, epoch uint64, privKeys []*bls.SecretKey) ([]byte, error) { +func RandaoReveal(beaconState *stateTrie.BeaconState, epoch uint64, privKeys []bls.SecretKey) ([]byte, error) { // We fetch the proposer's index as that is whom the RANDAO will be verified against. proposerIdx, err := helpers.BeaconProposerIndex(beaconState) if err != nil { @@ -41,8 +41,8 @@ func RandaoReveal(beaconState *stateTrie.BeaconState, epoch uint64, privKeys []* func BlockSignature( bState *stateTrie.BeaconState, block *ethpb.BeaconBlock, - privKeys []*bls.SecretKey, -) (*bls.Signature, error) { + privKeys []bls.SecretKey, +) (bls.Signature, error) { var err error s, err := state.CalculateStateRoot(context.Background(), bState, ðpb.SignedBeaconBlock{Block: block}) if err != nil { diff --git a/slasher/rpc/server.go b/slasher/rpc/server.go index 9d96c335d2..f01cb515c8 100644 --- a/slasher/rpc/server.go +++ b/slasher/rpc/server.go @@ -71,7 +71,7 @@ func (ss *Server) IsSlashableAttestation(ctx context.Context, req *ethpb.Indexed if err != nil { return nil, err } - pubkeys := []*bls.PublicKey{} + pubkeys := []bls.PublicKey{} for _, pkBytes := range pkMap { pk, err := bls.PublicKeyFromBytes(pkBytes[:]) if err != nil { diff --git a/slasher/rpc/server_test.go b/slasher/rpc/server_test.go index ae6c85225e..ca202c5158 100644 --- a/slasher/rpc/server_test.go +++ b/slasher/rpc/server_test.go @@ -86,7 +86,7 @@ func TestServer_IsSlashableAttestation(t *testing.T) { if err != nil { t.Error(err) } - var sig []*bls.Signature + var sig []bls.Signature for _, idx := range incomingAtt.AttestingIndices { validatorSig := keys[idx].Sign(root[:]) sig = append(sig, validatorSig) @@ -104,7 +104,7 @@ func TestServer_IsSlashableAttestation(t *testing.T) { if err != nil { t.Error(err) } - sig = []*bls.Signature{} + sig = []bls.Signature{} for _, idx := range savedAttestation.AttestingIndices { validatorSig := keys[idx].Sign(root[:]) sig = append(sig, validatorSig) @@ -195,7 +195,7 @@ func TestServer_IsSlashableAttestationNoUpdate(t *testing.T) { if err != nil { t.Error(err) } - sig := []*bls.Signature{} + sig := []bls.Signature{} for _, idx := range savedAttestation.AttestingIndices { validatorSig := keys[idx].Sign(root[:]) sig = append(sig, validatorSig) diff --git a/third_party/herumi/bls_eth_go_binary.BUILD b/third_party/herumi/bls_eth_go_binary.BUILD index 3dbf2645de..cf2057a9ef 100644 --- a/third_party/herumi/bls_eth_go_binary.BUILD +++ b/third_party/herumi/bls_eth_go_binary.BUILD @@ -149,7 +149,7 @@ go_library( copts = OPTS, visibility = [ # Additional access will require security approval. - "@prysm//shared/bls:__pkg__", + "@prysm//shared/bls/herumi:__pkg__", "@com_github_wealdtech_go_eth2_types_v2//:__pkg__", ], clinkopts = select({ diff --git a/tools/unencrypted-keys-gen/main.go b/tools/unencrypted-keys-gen/main.go index 637f98c941..fd7a23dd2c 100644 --- a/tools/unencrypted-keys-gen/main.go +++ b/tools/unencrypted-keys-gen/main.go @@ -2,10 +2,10 @@ package main import ( "flag" - "github.com/prysmaticlabs/prysm/shared/bls" "log" "os" + "github.com/prysmaticlabs/prysm/shared/bls" "github.com/prysmaticlabs/prysm/shared/interop" "github.com/prysmaticlabs/prysm/tools/unencrypted-keys-gen/keygen" ) diff --git a/validator/client/polling/attest.go b/validator/client/polling/attest.go index 997fe09512..567e64cc6a 100644 --- a/validator/client/polling/attest.go +++ b/validator/client/polling/attest.go @@ -226,7 +226,7 @@ func (v *validator) signAtt(ctx context.Context, pubKey [48]byte, data *ethpb.At return nil, err } - var sig *bls.Signature + var sig bls.Signature if protectingKeymanager, supported := v.keyManager.(keymanager.ProtectingKeyManager); supported { sig, err = protectingKeymanager.SignAttestation(pubKey, bytesutil.ToBytes32(domain.SignatureDomain), data) } else { diff --git a/validator/client/polling/propose.go b/validator/client/polling/propose.go index 64022ac171..e146b3843c 100644 --- a/validator/client/polling/propose.go +++ b/validator/client/polling/propose.go @@ -189,7 +189,7 @@ func (v *validator) signBlock(ctx context.Context, pubKey [48]byte, epoch uint64 if err != nil { return nil, errors.Wrap(err, "could not get domain data") } - var sig *bls.Signature + var sig bls.Signature if protectingKeymanager, supported := v.keyManager.(keymanager.ProtectingKeyManager); supported { bodyRoot, err := stateutil.BlockBodyRoot(b.Body) if err != nil { diff --git a/validator/client/polling/service.go b/validator/client/polling/service.go index 08ce2e5e8e..58a5c03048 100644 --- a/validator/client/polling/service.go +++ b/validator/client/polling/service.go @@ -180,7 +180,7 @@ func (v *ValidatorService) Status() error { } // signObject signs a generic object, with protection if available. -func (v *validator) signObject(pubKey [48]byte, object interface{}, domain []byte) (*bls.Signature, error) { +func (v *validator) signObject(pubKey [48]byte, object interface{}, domain []byte) (bls.Signature, error) { if protectingKeymanager, supported := v.keyManager.(keymanager.ProtectingKeyManager); supported { root, err := ssz.HashTreeRoot(object) if err != nil { diff --git a/validator/client/polling/service_test.go b/validator/client/polling/service_test.go index a8976bfdb5..db5dbf6668 100644 --- a/validator/client/polling/service_test.go +++ b/validator/client/polling/service_test.go @@ -36,11 +36,11 @@ func keySetup() { copy(validatorPubKey[:], validatorKey.PublicKey.Marshal()) keyMap[validatorPubKey] = validatorKey - sks := make([]*bls.SecretKey, 1) + sks := make([]bls.SecretKey, 1) sks[0] = validatorKey.SecretKey testKeyManager = keymanager.NewDirect(sks) - sks = make([]*bls.SecretKey, 3) + sks = make([]bls.SecretKey, 3) for i := 0; i < 3; i++ { vKey, err := keystore.NewKey() if err != nil { diff --git a/validator/client/polling/validator_test.go b/validator/client/polling/validator_test.go index db7b5fa539..2a1813c8b1 100644 --- a/validator/client/polling/validator_test.go +++ b/validator/client/polling/validator_test.go @@ -809,7 +809,7 @@ func TestRolesAt_OK(t *testing.T) { v, m, finish := setup(t) defer finish() - sks := make([]*bls.SecretKey, 4) + sks := make([]bls.SecretKey, 4) sks[0] = bls.RandKey() sks[1] = bls.RandKey() sks[2] = bls.RandKey() @@ -880,7 +880,7 @@ func TestRolesAt_DoesNotAssignProposer_Slot0(t *testing.T) { v, m, finish := setup(t) defer finish() - sks := make([]*bls.SecretKey, 3) + sks := make([]bls.SecretKey, 3) sks[0] = bls.RandKey() sks[1] = bls.RandKey() sks[2] = bls.RandKey() diff --git a/validator/client/streaming/attest.go b/validator/client/streaming/attest.go index a4fb7243df..ef6f4b147c 100644 --- a/validator/client/streaming/attest.go +++ b/validator/client/streaming/attest.go @@ -155,7 +155,7 @@ func (v *validator) signAtt(ctx context.Context, pubKey [48]byte, data *ethpb.At return nil, err } - var sig *bls.Signature + var sig bls.Signature if protectingKeymanager, supported := v.keyManager.(keymanager.ProtectingKeyManager); supported { sig, err = protectingKeymanager.SignAttestation(pubKey, bytesutil.ToBytes32(domain.SignatureDomain), data) } else { diff --git a/validator/client/streaming/propose.go b/validator/client/streaming/propose.go index e68f8b27ca..fd5c65ab38 100644 --- a/validator/client/streaming/propose.go +++ b/validator/client/streaming/propose.go @@ -191,7 +191,7 @@ func (v *validator) signBlock(ctx context.Context, pubKey [48]byte, epoch uint64 if err != nil { return nil, errors.Wrap(err, "could not get domain data") } - var sig *bls.Signature + var sig bls.Signature if protectingKeymanager, supported := v.keyManager.(keymanager.ProtectingKeyManager); supported { bodyRoot, err := stateutil.BlockBodyRoot(b.Body) if err != nil { diff --git a/validator/client/streaming/service.go b/validator/client/streaming/service.go index ddbeff10f6..3aa45c637d 100644 --- a/validator/client/streaming/service.go +++ b/validator/client/streaming/service.go @@ -172,7 +172,7 @@ func (v *ValidatorService) Status() error { } // signObject signs a generic object, with protection if available. -func (v *validator) signObject(pubKey [48]byte, object interface{}, domain []byte) (*bls.Signature, error) { +func (v *validator) signObject(pubKey [48]byte, object interface{}, domain []byte) (bls.Signature, error) { if protectingKeymanager, supported := v.keyManager.(keymanager.ProtectingKeyManager); supported { root, err := ssz.HashTreeRoot(object) if err != nil { diff --git a/validator/client/streaming/service_test.go b/validator/client/streaming/service_test.go index 8b598e68cd..dddadb9b4f 100644 --- a/validator/client/streaming/service_test.go +++ b/validator/client/streaming/service_test.go @@ -36,11 +36,11 @@ func keySetup() { copy(validatorPubKey[:], validatorKey.PublicKey.Marshal()) keyMap[validatorPubKey] = validatorKey - sks := make([]*bls.SecretKey, 1) + sks := make([]bls.SecretKey, 1) sks[0] = validatorKey.SecretKey testKeyManager = keymanager.NewDirect(sks) - sks = make([]*bls.SecretKey, 3) + sks = make([]bls.SecretKey, 3) for i := 0; i < 3; i++ { vKey, err := keystore.NewKey() if err != nil { diff --git a/validator/client/streaming/validator_test.go b/validator/client/streaming/validator_test.go index ad07b26215..48a76cdedd 100644 --- a/validator/client/streaming/validator_test.go +++ b/validator/client/streaming/validator_test.go @@ -639,7 +639,7 @@ func TestRolesAt_OK(t *testing.T) { v, m, finish := setup(t) defer finish() - sks := make([]*bls.SecretKey, 4) + sks := make([]bls.SecretKey, 4) sks[0] = bls.RandKey() sks[1] = bls.RandKey() sks[2] = bls.RandKey() @@ -710,7 +710,7 @@ func TestRolesAt_DoesNotAssignProposer_Slot0(t *testing.T) { v, m, finish := setup(t) defer finish() - sks := make([]*bls.SecretKey, 3) + sks := make([]bls.SecretKey, 3) sks[0] = bls.RandKey() sks[1] = bls.RandKey() sks[2] = bls.RandKey() diff --git a/validator/keymanager/direct.go b/validator/keymanager/direct.go index d59e68ebe0..2a1bddbacb 100644 --- a/validator/keymanager/direct.go +++ b/validator/keymanager/direct.go @@ -8,16 +8,16 @@ import ( // Direct is a key manager that holds all secret keys directly. type Direct struct { // Key to the map is the bytes of the public key. - publicKeys map[[48]byte]*bls.PublicKey + publicKeys map[[48]byte]bls.PublicKey // Key to the map is the bytes of the public key. - secretKeys map[[48]byte]*bls.SecretKey + secretKeys map[[48]byte]bls.SecretKey } // NewDirect creates a new direct key manager from the secret keys provided to it. -func NewDirect(sks []*bls.SecretKey) *Direct { +func NewDirect(sks []bls.SecretKey) *Direct { res := &Direct{ - publicKeys: make(map[[48]byte]*bls.PublicKey), - secretKeys: make(map[[48]byte]*bls.SecretKey), + publicKeys: make(map[[48]byte]bls.PublicKey), + secretKeys: make(map[[48]byte]bls.SecretKey), } for _, sk := range sks { publicKey := sk.PublicKey() @@ -38,7 +38,7 @@ func (km *Direct) FetchValidatingKeys() ([][48]byte, error) { } // Sign signs a message for the validator to broadcast. -func (km *Direct) Sign(pubKey [48]byte, root [32]byte) (*bls.Signature, error) { +func (km *Direct) Sign(pubKey [48]byte, root [32]byte) (bls.Signature, error) { if secretKey, exists := km.secretKeys[pubKey]; exists { return secretKey.Sign(root[:]), nil } diff --git a/validator/keymanager/direct_interop.go b/validator/keymanager/direct_interop.go index 7fc33879de..f79f616a37 100644 --- a/validator/keymanager/direct_interop.go +++ b/validator/keymanager/direct_interop.go @@ -42,8 +42,8 @@ func NewInterop(input string) (*Interop, string, error) { km := &Interop{ Direct: &Direct{ - publicKeys: make(map[[48]byte]*bls.PublicKey), - secretKeys: make(map[[48]byte]*bls.SecretKey), + publicKeys: make(map[[48]byte]bls.PublicKey), + secretKeys: make(map[[48]byte]bls.SecretKey), }, } for i := 0; uint64(i) < opts.Keys; i++ { diff --git a/validator/keymanager/direct_keystore.go b/validator/keymanager/direct_keystore.go index 034e5aa5c0..0bbdaa3a38 100644 --- a/validator/keymanager/direct_keystore.go +++ b/validator/keymanager/direct_keystore.go @@ -79,8 +79,8 @@ func NewKeystore(input string) (KeyManager, string, error) { km := &Unencrypted{ Direct: &Direct{ - publicKeys: make(map[[48]byte]*bls.PublicKey), - secretKeys: make(map[[48]byte]*bls.SecretKey), + publicKeys: make(map[[48]byte]bls.PublicKey), + secretKeys: make(map[[48]byte]bls.SecretKey), }, } for _, key := range keyMap { diff --git a/validator/keymanager/direct_test.go b/validator/keymanager/direct_test.go index 1b7a008beb..e348876e6e 100644 --- a/validator/keymanager/direct_test.go +++ b/validator/keymanager/direct_test.go @@ -21,7 +21,7 @@ func TestDirectListValidatingKeysNil(t *testing.T) { } func TestDirectListValidatingKeysSingle(t *testing.T) { - sks := make([]*bls.SecretKey, 0) + sks := make([]bls.SecretKey, 0) sks = append(sks, bls.RandKey()) direct := keymanager.NewDirect(sks) keys, err := direct.FetchValidatingKeys() @@ -34,7 +34,7 @@ func TestDirectListValidatingKeysSingle(t *testing.T) { } func TestDirectListValidatingKeysMultiple(t *testing.T) { - sks := make([]*bls.SecretKey, 0) + sks := make([]bls.SecretKey, 0) numKeys := 256 for i := 0; i < numKeys; i++ { sks = append(sks, bls.RandKey()) @@ -50,7 +50,7 @@ func TestDirectListValidatingKeysMultiple(t *testing.T) { } func TestSignNoSuchKey(t *testing.T) { - sks := make([]*bls.SecretKey, 0) + sks := make([]bls.SecretKey, 0) // sks = append(sks, bls.RandKey()) direct := keymanager.NewDirect(sks) @@ -62,7 +62,7 @@ func TestSignNoSuchKey(t *testing.T) { } func TestSign(t *testing.T) { - sks := make([]*bls.SecretKey, 0) + sks := make([]bls.SecretKey, 0) sks = append(sks, bls.RandKey()) direct := keymanager.NewDirect(sks) diff --git a/validator/keymanager/direct_unencrypted.go b/validator/keymanager/direct_unencrypted.go index 56f2b3adbb..1dd69a62c0 100644 --- a/validator/keymanager/direct_unencrypted.go +++ b/validator/keymanager/direct_unencrypted.go @@ -58,15 +58,15 @@ func NewUnencrypted(input string) (*Unencrypted, string, error) { if err != nil { return nil, unencryptedOptsHelp, err } - sks := make([]*bls.SecretKey, 0, len(keyMap)) + sks := make([]bls.SecretKey, 0, len(keyMap)) for _, key := range keyMap { sks = append(sks, key) } km := &Unencrypted{ Direct: &Direct{ - publicKeys: make(map[[48]byte]*bls.PublicKey), - secretKeys: make(map[[48]byte]*bls.SecretKey), + publicKeys: make(map[[48]byte]bls.PublicKey), + secretKeys: make(map[[48]byte]bls.SecretKey), }, } for i := 0; i < len(sks); i++ { @@ -87,7 +87,7 @@ type unencryptedKeys struct { } // unencryptedKeysFromReader loads the unencrypted keys from the given reader. -func unencryptedKeysFromReader(reader io.Reader) ([]*bls.SecretKey, error) { +func unencryptedKeysFromReader(reader io.Reader) ([]bls.SecretKey, error) { log.Warn("Loading encrypted keys from disk. Do not do this in production!") data, err := ioutil.ReadAll(reader) @@ -99,7 +99,7 @@ func unencryptedKeysFromReader(reader io.Reader) ([]*bls.SecretKey, error) { return nil, err } - res := make([]*bls.SecretKey, 0, len(ctnr.Keys)) + res := make([]bls.SecretKey, 0, len(ctnr.Keys)) for i := range ctnr.Keys { secretKey, err := bls.SecretKeyFromBytes(ctnr.Keys[i].ValidatorKey) if err != nil { diff --git a/validator/keymanager/keymanager.go b/validator/keymanager/keymanager.go index f803f84386..04a789a1a4 100644 --- a/validator/keymanager/keymanager.go +++ b/validator/keymanager/keymanager.go @@ -22,18 +22,18 @@ type KeyManager interface { FetchValidatingKeys() ([][48]byte, error) // Sign signs a message for the validator to broadcast. // Note that the domain should already be part of the root, but it is passed along for security purposes. - Sign(pubKey [48]byte, root [32]byte) (*bls.Signature, error) + Sign(pubKey [48]byte, root [32]byte) (bls.Signature, error) } // ProtectingKeyManager provides access to a keymanager that protects its clients from slashing events. type ProtectingKeyManager interface { // SignGeneric signs a generic root. // Note that the domain should already be part of the root, but it is provided for authorisation purposes. - SignGeneric(pubKey [48]byte, root [32]byte, domain [32]byte) (*bls.Signature, error) + SignGeneric(pubKey [48]byte, root [32]byte, domain [32]byte) (bls.Signature, error) // SignProposal signs a block proposal for the validator to broadcast. - SignProposal(pubKey [48]byte, domain [32]byte, data *ethpb.BeaconBlockHeader) (*bls.Signature, error) + SignProposal(pubKey [48]byte, domain [32]byte, data *ethpb.BeaconBlockHeader) (bls.Signature, error) // SignAttestation signs an attestation for the validator to broadcast. - SignAttestation(pubKey [48]byte, domain [32]byte, data *ethpb.AttestationData) (*bls.Signature, error) + SignAttestation(pubKey [48]byte, domain [32]byte, data *ethpb.AttestationData) (bls.Signature, error) } diff --git a/validator/keymanager/remote.go b/validator/keymanager/remote.go index a4b4feb03b..71ecf27962 100644 --- a/validator/keymanager/remote.go +++ b/validator/keymanager/remote.go @@ -155,12 +155,12 @@ func (km *Remote) FetchValidatingKeys() ([][48]byte, error) { } // Sign without protection is not supported by remote keymanagers. -func (km *Remote) Sign(pubKey [48]byte, root [32]byte) (*bls.Signature, error) { +func (km *Remote) Sign(pubKey [48]byte, root [32]byte) (bls.Signature, error) { return nil, errors.New("remote keymanager does not support unprotected signing") } // SignGeneric signs a generic message for the validator to broadcast. -func (km *Remote) SignGeneric(pubKey [48]byte, root [32]byte, domain [32]byte) (*bls.Signature, error) { +func (km *Remote) SignGeneric(pubKey [48]byte, root [32]byte, domain [32]byte) (bls.Signature, error) { accountInfo, exists := km.accounts[pubKey] if !exists { return nil, ErrNoSuchKey @@ -186,7 +186,7 @@ func (km *Remote) SignGeneric(pubKey [48]byte, root [32]byte, domain [32]byte) ( } // SignProposal signs a block proposal for the validator to broadcast. -func (km *Remote) SignProposal(pubKey [48]byte, domain [32]byte, data *ethpb.BeaconBlockHeader) (*bls.Signature, error) { +func (km *Remote) SignProposal(pubKey [48]byte, domain [32]byte, data *ethpb.BeaconBlockHeader) (bls.Signature, error) { accountInfo, exists := km.accounts[pubKey] if !exists { return nil, ErrNoSuchKey @@ -218,7 +218,7 @@ func (km *Remote) SignProposal(pubKey [48]byte, domain [32]byte, data *ethpb.Bea } // SignAttestation signs an attestation for the validator to broadcast. -func (km *Remote) SignAttestation(pubKey [48]byte, domain [32]byte, data *ethpb.AttestationData) (*bls.Signature, error) { +func (km *Remote) SignAttestation(pubKey [48]byte, domain [32]byte, data *ethpb.AttestationData) (bls.Signature, error) { accountInfo, exists := km.accounts[pubKey] if !exists { return nil, ErrNoSuchKey diff --git a/validator/keymanager/wallet.go b/validator/keymanager/wallet.go index 532628f1b5..c4c1e15499 100644 --- a/validator/keymanager/wallet.go +++ b/validator/keymanager/wallet.go @@ -134,7 +134,7 @@ func (km *Wallet) FetchValidatingKeys() ([][48]byte, error) { } // Sign signs a message for the validator to broadcast. -func (km *Wallet) Sign(pubKey [48]byte, root [32]byte) (*bls.Signature, error) { +func (km *Wallet) Sign(pubKey [48]byte, root [32]byte) (bls.Signature, error) { account, exists := km.accounts[pubKey] if !exists { return nil, ErrNoSuchKey