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