github.com/koko1123/flow-go-1@v0.29.6/consensus/hotstuff/verification/staking_verifier.go (about)

     1  //go:build relic
     2  // +build relic
     3  
     4  package verification
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/koko1123/flow-go-1/consensus/hotstuff"
    10  	"github.com/koko1123/flow-go-1/consensus/hotstuff/model"
    11  	"github.com/onflow/flow-go/crypto"
    12  	"github.com/onflow/flow-go/crypto/hash"
    13  	"github.com/koko1123/flow-go-1/model/flow"
    14  	msig "github.com/koko1123/flow-go-1/module/signature"
    15  )
    16  
    17  // StakingVerifier is a verifier capable of verifying staking signature for each
    18  // verifying operation. It's used primarily with collection cluster where hotstuff without beacon signers is used.
    19  type StakingVerifier struct {
    20  	stakingHasher hash.Hasher
    21  }
    22  
    23  var _ hotstuff.Verifier = (*StakingVerifier)(nil)
    24  
    25  // NewStakingVerifier creates a new single verifier with the given dependencies.
    26  func NewStakingVerifier() *StakingVerifier {
    27  	return &StakingVerifier{
    28  		stakingHasher: msig.NewBLSHasher(msig.CollectorVoteTag),
    29  	}
    30  }
    31  
    32  // VerifyVote verifies the validity of a single signature from a vote.
    33  // Usually this method is only used to verify the proposer's vote, which is
    34  // the vote included in a block proposal.
    35  // The implementation returns the following sentinel errors:
    36  //   - model.InvalidFormatError if the signature has an incompatible format.
    37  //   - model.ErrInvalidSignature is the signature is invalid
    38  //   - unexpected errors should be treated as symptoms of bugs or uncovered
    39  //     edge cases in the logic (i.e. as fatal)
    40  func (v *StakingVerifier) VerifyVote(signer *flow.Identity, sigData []byte, block *model.Block) error {
    41  
    42  	// create the to-be-signed message
    43  	msg := MakeVoteMessage(block.View, block.BlockID)
    44  
    45  	// verify each signature against the message
    46  	stakingValid, err := signer.StakingPubKey.Verify(sigData, msg, v.stakingHasher)
    47  	if err != nil {
    48  		return fmt.Errorf("internal error while verifying staking signature: %w", err)
    49  	}
    50  	if !stakingValid {
    51  		return fmt.Errorf("invalid sig for block %v: %w", block.BlockID, model.ErrInvalidSignature)
    52  	}
    53  
    54  	return nil
    55  }
    56  
    57  // VerifyQC checks the cryptographic validity of the QC's `sigData` for the
    58  // given block. It is the responsibility of the calling code to ensure
    59  // that all `voters` are authorized, without duplicates. Return values:
    60  //   - nil if `sigData` is cryptographically valid
    61  //   - model.InvalidFormatError if `sigData` has an incompatible format
    62  //   - model.ErrInvalidSignature if a signature is invalid
    63  //   - unexpected errors should be treated as symptoms of bugs or uncovered
    64  //     edge cases in the logic (i.e. as fatal)
    65  //
    66  // In the single verification case, `sigData` represents a single signature (`crypto.Signature`).
    67  func (v *StakingVerifier) VerifyQC(signers flow.IdentityList, sigData []byte, block *model.Block) error {
    68  	if len(signers) == 0 {
    69  		return model.NewInvalidFormatErrorf("empty list of signers")
    70  	}
    71  	msg := MakeVoteMessage(block.View, block.BlockID)
    72  
    73  	// verify the aggregated staking signature
    74  	// TODO: to be replaced by module/signature.PublicKeyAggregator in V2
    75  	aggregatedKey, err := crypto.AggregateBLSPublicKeys(signers.PublicStakingKeys()) // caution: requires non-empty slice of keys!
    76  	if err != nil {
    77  		// `AggregateBLSPublicKeys` returns a `crypto.invalidInputsError` in two distinct cases:
    78  		//  (i) In case no keys are provided, i.e.  `len(signers) == 0`.
    79  		//      This scenario _is expected_ during normal operations, because a byzantine
    80  		//      proposer might construct an (invalid) QC with an empty list of signers.
    81  		// (ii) In case some provided public keys type is not BLS.
    82  		//      This scenario is _not expected_ during normal operations, because all keys are
    83  		//      guaranteed by the protocol to be BLS keys.
    84  		//
    85  		// By checking `len(signers) == 0` upfront , we can rule out case (i) as a source of error.
    86  		// Hence, if we encounter an error here, we know it is case (ii). Thereby, we can clearly
    87  		// distinguish a faulty _external_ input from an _internal_ uncovered edge-case.
    88  		return fmt.Errorf("could not compute aggregated key: %w", err)
    89  	}
    90  	stakingValid, err := aggregatedKey.Verify(sigData, msg, v.stakingHasher)
    91  	if err != nil {
    92  		return fmt.Errorf("internal error while verifying staking signature: %w", err)
    93  	}
    94  
    95  	if !stakingValid {
    96  		return fmt.Errorf("invalid aggregated staking sig for block %v: %w", block.BlockID, model.ErrInvalidSignature)
    97  	}
    98  	return nil
    99  }