func verifyCommitBatch(
	chainID string,
	vals *ValidatorSet,
	commit *Commit,
	votingPowerNeeded int64,
	ignoreSig func(CommitSig) bool,
	countSig func(CommitSig) bool,
	countAllSignatures bool,
	lookUpByIndex bool,
) error {
	var (
		val                *Validator
		valIdx             int32
		talliedVotingPower int64
		seenVals           = make(map[int32]int, len(commit.Signatures))
		batchSigIdxs       = make([]int, 0, len(commit.Signatures))
	)
	bv, ok := batch.CreateBatchVerifier(vals.GetProposer().PubKey)
	if !ok || len(commit.Signatures) < batchVerifyThreshold {
		return fmt.Errorf("unsupported signature algorithm or insufficient signatures for batch verification")
	}
	for idx, commitSig := range commit.Signatures {
		if ignoreSig(commitSig) {
			continue
		}
		if lookUpByIndex {
			val = vals.Validators[idx]
		} else {
			valIdx, val = vals.GetByAddress(commitSig.ValidatorAddress)
			if val == nil {
				continue
			}
			if firstIndex, ok := seenVals[valIdx]; ok {
				secondIndex := idx
				return fmt.Errorf("double vote from %v (%d and %d)", val, firstIndex, secondIndex)
			}
			seenVals[valIdx] = idx
		}
		voteSignBytes := commit.VoteSignBytes(chainID, int32(idx))
		if err := bv.Add(val.PubKey, voteSignBytes, commitSig.Signature); err != nil {
			return err
		}
		batchSigIdxs = append(batchSigIdxs, idx)
		if countSig(commitSig) {
			talliedVotingPower += val.VotingPower
		}
		if !countAllSignatures && talliedVotingPower > votingPowerNeeded {
			break
		}
	}
	if got, needed := talliedVotingPower, votingPowerNeeded; got <= needed {
		return ErrNotEnoughVotingPowerSigned{Got: got, Needed: needed}
	}
	ok, validSigs := bv.Verify()
	if ok {
		return nil
	}
	for i, ok := range validSigs {
		if !ok {
			idx := batchSigIdxs[i]
			sig := commit.Signatures[idx]
			return fmt.Errorf("wrong signature (#%d): %X", idx, sig)
		}
	}
	return fmt.Errorf("BUG: batch verification failed with no invalid signatures")
}
Batch verification
verifyCommitBatch batch verifies commits.  This routine is equivalent
to verifyCommitSingle in behavior, just faster iff every signature in the
batch is valid.

Note: The caller is responsible for checking to see if this routine is
usable via `shouldVerifyBatch(vals, commit)`.
package types
import (
	"errors"
	"fmt"
	"github.com/tendermint/tendermint/crypto/batch"
	"github.com/tendermint/tendermint/crypto/tmhash"
	tmmath "github.com/tendermint/tendermint/libs/math"
)
const batchVerifyThreshold = 2
func shouldBatchVerify(vals *ValidatorSet, commit *Commit) bool {
	return len(commit.Signatures) >= batchVerifyThreshold && batch.SupportsBatchVerifier(vals.GetProposer().PubKey)
}
func VerifyCommit(chainID string, vals *ValidatorSet, blockID BlockID,
	height int64, commit *Commit) error {
	if err := verifyBasicValsAndCommit(vals, commit, height, blockID); err != nil {
		return err
	}
	votingPowerNeeded := vals.TotalVotingPower() * 2 / 3
	ignore := func(c CommitSig) bool { return c.Absent() }
	count := func(c CommitSig) bool { return c.ForBlock() }
	if shouldBatchVerify(vals, commit) {
		return verifyCommitBatch(chainID, vals, commit,
			votingPowerNeeded, ignore, count, true, true)
	}
	return verifyCommitSingle(chainID, vals, commit, votingPowerNeeded,
		ignore, count, true, true)
}
func VerifyCommitLight(chainID string, vals *ValidatorSet, blockID BlockID,
	height int64, commit *Commit) error {
	if err := verifyBasicValsAndCommit(vals, commit, height, blockID); err != nil {
		return err
	}
	votingPowerNeeded := vals.TotalVotingPower() * 2 / 3
	ignore := func(c CommitSig) bool { return !c.ForBlock() }
	count := func(c CommitSig) bool { return true }
	if shouldBatchVerify(vals, commit) {
		return verifyCommitBatch(chainID, vals, commit,
			votingPowerNeeded, ignore, count, false, true)
	}
	return verifyCommitSingle(chainID, vals, commit, votingPowerNeeded,
		ignore, count, false, true)
}
func VerifyCommitLightTrusting(chainID string, vals *ValidatorSet, commit *Commit, trustLevel tmmath.Fraction) error {
	if vals == nil {
		return errors.New("nil validator set")
	}
	if trustLevel.Denominator == 0 {
		return errors.New("trustLevel has zero Denominator")
	}
	if commit == nil {
		return errors.New("nil commit")
	}
	totalVotingPowerMulByNumerator, overflow := safeMul(vals.TotalVotingPower(), int64(trustLevel.Numerator))
	if overflow {
		return errors.New("int64 overflow while calculating voting power needed. please provide smaller trustLevel numerator")
	}
	votingPowerNeeded := totalVotingPowerMulByNumerator / int64(trustLevel.Denominator)
	ignore := func(c CommitSig) bool { return !c.ForBlock() }
	count := func(c CommitSig) bool { return true }
	if shouldBatchVerify(vals, commit) {
		return verifyCommitBatch(chainID, vals, commit,
			votingPowerNeeded, ignore, count, false, false)
	}
	return verifyCommitSingle(chainID, vals, commit, votingPowerNeeded,
		ignore, count, false, false)
}
func ValidateHash(h []byte) error {
	if len(h) > 0 && len(h) != tmhash.Size {
		return fmt.Errorf("expected size to be %d bytes, got %d bytes",
			tmhash.Size,
			len(h),
		)
	}
	return nil
}