github.com/vipernet-xyz/tendermint-core@v0.32.0/crypto/multisig/threshold_pubkey.go (about) 1 package multisig 2 3 import ( 4 "github.com/tendermint/tendermint/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 for _, pubkey := range pubkeys { 25 if pubkey == nil { 26 panic("nil pubkey") 27 } 28 } 29 return PubKeyMultisigThreshold{uint(k), pubkeys} 30 } 31 32 // VerifyBytes expects sig to be an amino encoded version of a MultiSignature. 33 // Returns true iff the multisignature contains k or more signatures 34 // for the correct corresponding keys, 35 // and all signatures are valid. (Not just k of the signatures) 36 // The multisig uses a bitarray, so multiple signatures for the same key is not 37 // a concern. 38 func (pk PubKeyMultisigThreshold) VerifyBytes(msg []byte, marshalledSig []byte) bool { 39 var sig Multisignature 40 err := cdc.UnmarshalBinaryBare(marshalledSig, &sig) 41 if err != nil { 42 return false 43 } 44 size := sig.BitArray.Size() 45 // ensure bit array is the correct size 46 if len(pk.PubKeys) != size { 47 return false 48 } 49 // ensure size of signature list 50 if len(sig.Sigs) < int(pk.K) || len(sig.Sigs) > size { 51 return false 52 } 53 // ensure at least k signatures are set 54 if sig.BitArray.NumTrueBitsBefore(size) < int(pk.K) { 55 return false 56 } 57 // index in the list of signatures which we are concerned with. 58 sigIndex := 0 59 for i := 0; i < size; i++ { 60 if sig.BitArray.GetIndex(i) { 61 if !pk.PubKeys[i].VerifyBytes(msg, sig.Sigs[sigIndex]) { 62 return false 63 } 64 sigIndex++ 65 } 66 } 67 return true 68 } 69 70 // Bytes returns the amino encoded version of the PubKeyMultisigThreshold 71 func (pk PubKeyMultisigThreshold) Bytes() []byte { 72 return cdc.MustMarshalBinaryBare(pk) 73 } 74 75 // Address returns tmhash(PubKeyMultisigThreshold.Bytes()) 76 func (pk PubKeyMultisigThreshold) Address() crypto.Address { 77 return crypto.AddressHash(pk.Bytes()) 78 } 79 80 // Equals returns true iff pk and other both have the same number of keys, and 81 // all constituent keys are the same, and in the same order. 82 func (pk PubKeyMultisigThreshold) Equals(other crypto.PubKey) bool { 83 otherKey, sameType := other.(PubKeyMultisigThreshold) 84 if !sameType { 85 return false 86 } 87 if pk.K != otherKey.K || len(pk.PubKeys) != len(otherKey.PubKeys) { 88 return false 89 } 90 for i := 0; i < len(pk.PubKeys); i++ { 91 if !pk.PubKeys[i].Equals(otherKey.PubKeys[i]) { 92 return false 93 } 94 } 95 return true 96 }