github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/core/blocks/signature.go (about)

     1  package blocks
     2  
     3  import (
     4  	"context"
     5  	"encoding/binary"
     6  
     7  	"github.com/pkg/errors"
     8  	types "github.com/prysmaticlabs/eth2-types"
     9  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    10  	iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
    11  	pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    12  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    13  	"github.com/prysmaticlabs/prysm/shared/attestationutil"
    14  	"github.com/prysmaticlabs/prysm/shared/bls"
    15  	"github.com/prysmaticlabs/prysm/shared/params"
    16  )
    17  
    18  // retrieves the signature set from the raw data, public key,signature and domain provided.
    19  func signatureSet(signedData, pub, signature, domain []byte) (*bls.SignatureSet, error) {
    20  	publicKey, err := bls.PublicKeyFromBytes(pub)
    21  	if err != nil {
    22  		return nil, errors.Wrap(err, "could not convert bytes to public key")
    23  	}
    24  	signingData := &pb.SigningData{
    25  		ObjectRoot: signedData,
    26  		Domain:     domain,
    27  	}
    28  	root, err := signingData.HashTreeRoot()
    29  	if err != nil {
    30  		return nil, errors.Wrap(err, "could not hash container")
    31  	}
    32  	return &bls.SignatureSet{
    33  		Signatures: [][]byte{signature},
    34  		PublicKeys: []bls.PublicKey{publicKey},
    35  		Messages:   [][32]byte{root},
    36  	}, nil
    37  }
    38  
    39  // verifies the signature from the raw data, public key and domain provided.
    40  func verifySignature(signedData, pub, signature, domain []byte) error {
    41  	set, err := signatureSet(signedData, pub, signature, domain)
    42  	if err != nil {
    43  		return err
    44  	}
    45  	if len(set.Signatures) != 1 {
    46  		return errors.Errorf("signature set contains %d signatures instead of 1", len(set.Signatures))
    47  	}
    48  	// We assume only one signature set is returned here.
    49  	sig := set.Signatures[0]
    50  	publicKey := set.PublicKeys[0]
    51  	root := set.Messages[0]
    52  	rSig, err := bls.SignatureFromBytes(sig)
    53  	if err != nil {
    54  		return err
    55  	}
    56  	if !rSig.Verify(publicKey, root[:]) {
    57  		return helpers.ErrSigFailedToVerify
    58  	}
    59  	return nil
    60  }
    61  
    62  // VerifyBlockSignature verifies the proposer signature of a beacon block.
    63  func VerifyBlockSignature(beaconState iface.ReadOnlyBeaconState,
    64  	proposerIndex types.ValidatorIndex,
    65  	sig []byte,
    66  	rootFunc func() ([32]byte, error)) error {
    67  	currentEpoch := helpers.SlotToEpoch(beaconState.Slot())
    68  	domain, err := helpers.Domain(beaconState.Fork(), currentEpoch, params.BeaconConfig().DomainBeaconProposer, beaconState.GenesisValidatorRoot())
    69  	if err != nil {
    70  		return err
    71  	}
    72  	proposer, err := beaconState.ValidatorAtIndex(proposerIndex)
    73  	if err != nil {
    74  		return err
    75  	}
    76  	proposerPubKey := proposer.PublicKey
    77  	return helpers.VerifyBlockSigningRoot(proposerPubKey, sig, domain, rootFunc)
    78  }
    79  
    80  // BlockSignatureSet retrieves the block signature set from the provided block and its corresponding state.
    81  func BlockSignatureSet(beaconState iface.ReadOnlyBeaconState,
    82  	proposerIndex types.ValidatorIndex,
    83  	sig []byte,
    84  	rootFunc func() ([32]byte, error)) (*bls.SignatureSet, error) {
    85  	currentEpoch := helpers.SlotToEpoch(beaconState.Slot())
    86  	domain, err := helpers.Domain(beaconState.Fork(), currentEpoch, params.BeaconConfig().DomainBeaconProposer, beaconState.GenesisValidatorRoot())
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  	proposer, err := beaconState.ValidatorAtIndex(proposerIndex)
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  	proposerPubKey := proposer.PublicKey
    95  	return helpers.BlockSignatureSet(proposerPubKey, sig, domain, rootFunc)
    96  }
    97  
    98  // RandaoSignatureSet retrieves the relevant randao specific signature set object
    99  // from a block and its corresponding state.
   100  func RandaoSignatureSet(beaconState iface.ReadOnlyBeaconState,
   101  	reveal []byte,
   102  ) (*bls.SignatureSet, error) {
   103  	buf, proposerPub, domain, err := randaoSigningData(beaconState)
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	set, err := signatureSet(buf, proposerPub, reveal, domain)
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  	return set, nil
   112  }
   113  
   114  // retrieves the randao related signing data from the state.
   115  func randaoSigningData(beaconState iface.ReadOnlyBeaconState) ([]byte, []byte, []byte, error) {
   116  	proposerIdx, err := helpers.BeaconProposerIndex(beaconState)
   117  	if err != nil {
   118  		return nil, nil, nil, errors.Wrap(err, "could not get beacon proposer index")
   119  	}
   120  	proposerPub := beaconState.PubkeyAtIndex(proposerIdx)
   121  
   122  	currentEpoch := helpers.SlotToEpoch(beaconState.Slot())
   123  	buf := make([]byte, 32)
   124  	binary.LittleEndian.PutUint64(buf, uint64(currentEpoch))
   125  
   126  	domain, err := helpers.Domain(beaconState.Fork(), currentEpoch, params.BeaconConfig().DomainRandao, beaconState.GenesisValidatorRoot())
   127  	if err != nil {
   128  		return nil, nil, nil, err
   129  	}
   130  	return buf, proposerPub[:], domain, nil
   131  }
   132  
   133  // Method to break down attestations of the same domain and collect them into a single signature set.
   134  func createAttestationSignatureSet(
   135  	ctx context.Context,
   136  	beaconState iface.ReadOnlyBeaconState,
   137  	atts []*ethpb.Attestation,
   138  	domain []byte,
   139  ) (*bls.SignatureSet, error) {
   140  	if len(atts) == 0 {
   141  		return nil, nil
   142  	}
   143  
   144  	sigs := make([][]byte, len(atts))
   145  	pks := make([]bls.PublicKey, len(atts))
   146  	msgs := make([][32]byte, len(atts))
   147  	for i, a := range atts {
   148  		sigs[i] = a.Signature
   149  		c, err := helpers.BeaconCommitteeFromState(beaconState, a.Data.Slot, a.Data.CommitteeIndex)
   150  		if err != nil {
   151  			return nil, err
   152  		}
   153  		ia, err := attestationutil.ConvertToIndexed(ctx, a, c)
   154  		if err != nil {
   155  			return nil, err
   156  		}
   157  		if err := attestationutil.IsValidAttestationIndices(ctx, ia); err != nil {
   158  			return nil, err
   159  		}
   160  		indices := ia.AttestingIndices
   161  		pubkeys := make([][]byte, len(indices))
   162  		for i := 0; i < len(indices); i++ {
   163  			pubkeyAtIdx := beaconState.PubkeyAtIndex(types.ValidatorIndex(indices[i]))
   164  			pubkeys[i] = pubkeyAtIdx[:]
   165  		}
   166  		aggP, err := bls.AggregatePublicKeys(pubkeys)
   167  		if err != nil {
   168  			return nil, err
   169  		}
   170  		pks[i] = aggP
   171  
   172  		root, err := helpers.ComputeSigningRoot(ia.Data, domain)
   173  		if err != nil {
   174  			return nil, errors.Wrap(err, "could not get signing root of object")
   175  		}
   176  		msgs[i] = root
   177  	}
   178  	return &bls.SignatureSet{
   179  		Signatures: sigs,
   180  		PublicKeys: pks,
   181  		Messages:   msgs,
   182  	}, nil
   183  }
   184  
   185  // AttestationSignatureSet retrieves all the related attestation signature data such as the relevant public keys,
   186  // signatures and attestation signing data and collate it into a signature set object.
   187  func AttestationSignatureSet(ctx context.Context, beaconState iface.ReadOnlyBeaconState, atts []*ethpb.Attestation) (*bls.SignatureSet, error) {
   188  	if len(atts) == 0 {
   189  		return bls.NewSet(), nil
   190  	}
   191  
   192  	fork := beaconState.Fork()
   193  	gvr := beaconState.GenesisValidatorRoot()
   194  	dt := params.BeaconConfig().DomainBeaconAttester
   195  
   196  	// Split attestations by fork. Note: the signature domain will differ based on the fork.
   197  	var preForkAtts []*ethpb.Attestation
   198  	var postForkAtts []*ethpb.Attestation
   199  	for _, a := range atts {
   200  		if helpers.SlotToEpoch(a.Data.Slot) < fork.Epoch {
   201  			preForkAtts = append(preForkAtts, a)
   202  		} else {
   203  			postForkAtts = append(postForkAtts, a)
   204  		}
   205  	}
   206  	set := bls.NewSet()
   207  
   208  	// Check attestations from before the fork.
   209  	if fork.Epoch > 0 && len(preForkAtts) > 0 { // Check to prevent underflow and there is valid attestations to create sig set.
   210  		prevDomain, err := helpers.Domain(fork, fork.Epoch-1, dt, gvr)
   211  		if err != nil {
   212  			return nil, err
   213  		}
   214  		aSet, err := createAttestationSignatureSet(ctx, beaconState, preForkAtts, prevDomain)
   215  		if err != nil {
   216  			return nil, err
   217  		}
   218  		if aSet != nil {
   219  			set.Join(aSet)
   220  		}
   221  	} else if len(preForkAtts) > 0 {
   222  		// This is a sanity check that preForkAtts were not ignored when fork.Epoch == 0. This
   223  		// condition is not possible, but it doesn't hurt to check anyway.
   224  		return nil, errors.New("some attestations were not verified from previous fork before genesis")
   225  	}
   226  
   227  	if len(postForkAtts) > 0 {
   228  		// Then check attestations from after the fork.
   229  		currDomain, err := helpers.Domain(fork, fork.Epoch, dt, gvr)
   230  		if err != nil {
   231  			return nil, err
   232  		}
   233  
   234  		aSet, err := createAttestationSignatureSet(ctx, beaconState, postForkAtts, currDomain)
   235  		if err != nil {
   236  			return nil, err
   237  		}
   238  		if aSet != nil {
   239  			return set.Join(aSet), nil
   240  		}
   241  	}
   242  
   243  	return set, nil
   244  }