github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/consensus/hotstuff/verification/staking_verifier.go (about)

     1  package verification
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/onflow/crypto/hash"
     7  
     8  	"github.com/onflow/flow-go/consensus/hotstuff"
     9  	"github.com/onflow/flow-go/consensus/hotstuff/model"
    10  	"github.com/onflow/flow-go/model/flow"
    11  	msig "github.com/onflow/flow-go/module/signature"
    12  )
    13  
    14  // StakingVerifier is a verifier capable of verifying staking signature for each
    15  // verifying operation. It's used primarily with collection cluster where hotstuff without beacon signers is used.
    16  type StakingVerifier struct {
    17  	stakingHasher       hash.Hasher
    18  	timeoutObjectHasher hash.Hasher
    19  }
    20  
    21  var _ hotstuff.Verifier = (*StakingVerifier)(nil)
    22  
    23  // NewStakingVerifier creates a new single verifier with the given dependencies.
    24  func NewStakingVerifier() *StakingVerifier {
    25  	return &StakingVerifier{
    26  		stakingHasher:       msig.NewBLSHasher(msig.CollectorVoteTag),
    27  		timeoutObjectHasher: msig.NewBLSHasher(msig.CollectorTimeoutTag),
    28  	}
    29  }
    30  
    31  // VerifyVote verifies the validity of a single signature from a vote.
    32  // Usually this method is only used to verify the proposer's vote, which is
    33  // the vote included in a block proposal.
    34  // The implementation returns the following sentinel errors:
    35  //   - model.ErrInvalidSignature is the signature is invalid
    36  //   - unexpected errors should be treated as symptoms of bugs or uncovered
    37  //     edge cases in the logic (i.e. as fatal)
    38  func (v *StakingVerifier) VerifyVote(signer *flow.IdentitySkeleton, sigData []byte, view uint64, blockID flow.Identifier) error {
    39  
    40  	// create the to-be-signed message
    41  	msg := MakeVoteMessage(view, blockID)
    42  
    43  	// verify each signature against the message
    44  	stakingValid, err := signer.StakingPubKey.Verify(sigData, msg, v.stakingHasher)
    45  	if err != nil {
    46  		return fmt.Errorf("internal error while verifying staking signature: %w", err)
    47  	}
    48  	if !stakingValid {
    49  		return fmt.Errorf("invalid sig for block %v: %w", blockID, model.ErrInvalidSignature)
    50  	}
    51  
    52  	return nil
    53  }
    54  
    55  // VerifyQC checks the cryptographic validity of the QC's `sigData` for the
    56  // given block. It is the responsibility of the calling code to ensure
    57  // that all `signers` are authorized, without duplicates. Return values:
    58  //   - nil if `sigData` is cryptographically valid
    59  //   - model.InvalidFormatError if `sigData` has an incompatible format
    60  //   - model.InsufficientSignaturesError if `signers` is empty.
    61  //   - model.ErrInvalidSignature if a signature is invalid
    62  //   - unexpected errors should be treated as symptoms of bugs or uncovered
    63  //     edge cases in the logic (i.e. as fatal)
    64  //
    65  // In the single verification case, `sigData` represents a single signature (`crypto.Signature`).
    66  func (v *StakingVerifier) VerifyQC(signers flow.IdentitySkeletonList, sigData []byte, view uint64, blockID flow.Identifier) error {
    67  	msg := MakeVoteMessage(view, blockID)
    68  
    69  	err := verifyAggregatedSignatureOneMessage(signers.PublicStakingKeys(), sigData, v.stakingHasher, msg)
    70  	if err != nil {
    71  		return fmt.Errorf("verifying aggregated staking signature failed for block %v: %w", blockID, err)
    72  	}
    73  
    74  	return nil
    75  }
    76  
    77  // VerifyTC checks cryptographic validity of the TC's `sigData` w.r.t. the
    78  // given view. It is the responsibility of the calling code to ensure
    79  // that all `signers` are authorized, without duplicates. Return values:
    80  //   - nil if `sigData` is cryptographically valid
    81  //   - model.InsufficientSignaturesError if `signers is empty.
    82  //   - model.InvalidFormatError if `signers`/`highQCViews` have differing lengths
    83  //   - model.ErrInvalidSignature if a signature is invalid
    84  //   - unexpected errors should be treated as symptoms of bugs or uncovered
    85  //     edge cases in the logic (i.e. as fatal)
    86  func (v *StakingVerifier) VerifyTC(signers flow.IdentitySkeletonList, sigData []byte, view uint64, highQCViews []uint64) error {
    87  	return verifyTCSignatureManyMessages(signers.PublicStakingKeys(), sigData, view, highQCViews, v.timeoutObjectHasher)
    88  }