github.com/evdatsion/aphelion-dpos-bft@v0.32.1/crypto/multisig/threshold_pubkey.go (about)

     1  package multisig
     2  
     3  import (
     4  	"github.com/evdatsion/aphelion-dpos-bft/crypto"
     5  )
     6  
     7  // PubKeyMultisigThreshold implements a K of N threshold multisig.
     8  type PubKeyMultisigThreshold struct {
     9  	K       uint            `json:"threshold"`
    10  	PubKeys []crypto.PubKey `json:"pubkeys"`
    11  }
    12  
    13  var _ crypto.PubKey = PubKeyMultisigThreshold{}
    14  
    15  // NewPubKeyMultisigThreshold returns a new PubKeyMultisigThreshold.
    16  // Panics if len(pubkeys) < k or 0 >= k.
    17  func NewPubKeyMultisigThreshold(k int, pubkeys []crypto.PubKey) crypto.PubKey {
    18  	if k <= 0 {
    19  		panic("threshold k of n multisignature: k <= 0")
    20  	}
    21  	if len(pubkeys) < k {
    22  		panic("threshold k of n multisignature: len(pubkeys) < k")
    23  	}
    24  	return PubKeyMultisigThreshold{uint(k), pubkeys}
    25  }
    26  
    27  // VerifyBytes expects sig to be an amino encoded version of a MultiSignature.
    28  // Returns true iff the multisignature contains k or more signatures
    29  // for the correct corresponding keys,
    30  // and all signatures are valid. (Not just k of the signatures)
    31  // The multisig uses a bitarray, so multiple signatures for the same key is not
    32  // a concern.
    33  func (pk PubKeyMultisigThreshold) VerifyBytes(msg []byte, marshalledSig []byte) bool {
    34  	var sig Multisignature
    35  	err := cdc.UnmarshalBinaryBare(marshalledSig, &sig)
    36  	if err != nil {
    37  		return false
    38  	}
    39  	size := sig.BitArray.Size()
    40  	// ensure bit array is the correct size
    41  	if len(pk.PubKeys) != size {
    42  		return false
    43  	}
    44  	// ensure size of signature list
    45  	if len(sig.Sigs) < int(pk.K) || len(sig.Sigs) > size {
    46  		return false
    47  	}
    48  	// ensure at least k signatures are set
    49  	if sig.BitArray.NumTrueBitsBefore(size) < int(pk.K) {
    50  		return false
    51  	}
    52  	// index in the list of signatures which we are concerned with.
    53  	sigIndex := 0
    54  	for i := 0; i < size; i++ {
    55  		if sig.BitArray.GetIndex(i) {
    56  			if !pk.PubKeys[i].VerifyBytes(msg, sig.Sigs[sigIndex]) {
    57  				return false
    58  			}
    59  			sigIndex++
    60  		}
    61  	}
    62  	return true
    63  }
    64  
    65  // Bytes returns the amino encoded version of the PubKeyMultisigThreshold
    66  func (pk PubKeyMultisigThreshold) Bytes() []byte {
    67  	return cdc.MustMarshalBinaryBare(pk)
    68  }
    69  
    70  // Address returns tmhash(PubKeyMultisigThreshold.Bytes())
    71  func (pk PubKeyMultisigThreshold) Address() crypto.Address {
    72  	return crypto.AddressHash(pk.Bytes())
    73  }
    74  
    75  // Equals returns true iff pk and other both have the same number of keys, and
    76  // all constituent keys are the same, and in the same order.
    77  func (pk PubKeyMultisigThreshold) Equals(other crypto.PubKey) bool {
    78  	otherKey, sameType := other.(PubKeyMultisigThreshold)
    79  	if !sameType {
    80  		return false
    81  	}
    82  	if pk.K != otherKey.K || len(pk.PubKeys) != len(otherKey.PubKeys) {
    83  		return false
    84  	}
    85  	for i := 0; i < len(pk.PubKeys); i++ {
    86  		if !pk.PubKeys[i].Equals(otherKey.PubKeys[i]) {
    87  			return false
    88  		}
    89  	}
    90  	return true
    91  }