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