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 }