github.com/cosmos/cosmos-sdk@v0.50.1/crypto/types/multisig/multisignature.go (about) 1 package multisig 2 3 import ( 4 "errors" 5 "fmt" 6 "strings" 7 8 "github.com/cosmos/cosmos-sdk/crypto/types" 9 "github.com/cosmos/cosmos-sdk/types/tx/signing" 10 ) 11 12 // AminoMultisignature is used to represent amino multi-signatures for StdTx's. 13 // It is assumed that all signatures were made with SIGN_MODE_LEGACY_AMINO_JSON. 14 // Sigs is a list of signatures, sorted by corresponding index. 15 type AminoMultisignature struct { 16 BitArray *types.CompactBitArray 17 Sigs [][]byte 18 } 19 20 // NewMultisig returns a new MultiSignatureData 21 func NewMultisig(n int) *signing.MultiSignatureData { 22 return &signing.MultiSignatureData{ 23 BitArray: types.NewCompactBitArray(n), 24 Signatures: make([]signing.SignatureData, 0, n), 25 } 26 } 27 28 // GetIndex returns the index of pk in keys. Returns -1 if not found 29 func getIndex(pk types.PubKey, keys []types.PubKey) int { 30 for i := 0; i < len(keys); i++ { 31 if pk.Equals(keys[i]) { 32 return i 33 } 34 } 35 return -1 36 } 37 38 // AddSignature adds a signature to the multisig, at the corresponding index. The index must 39 // represent the pubkey index in the LegacyAmingPubKey structure, which verifies this signature. 40 // If the signature already exists, replace it. 41 func AddSignature(mSig *signing.MultiSignatureData, sig signing.SignatureData, index int) { 42 newSigIndex := mSig.BitArray.NumTrueBitsBefore(index) 43 // Signature already exists, just replace the value there 44 if mSig.BitArray.GetIndex(index) { 45 mSig.Signatures[newSigIndex] = sig 46 return 47 } 48 mSig.BitArray.SetIndex(index, true) 49 // Optimization if the index is the greatest index 50 if newSigIndex == len(mSig.Signatures) { 51 mSig.Signatures = append(mSig.Signatures, sig) 52 return 53 } 54 // Expand slice by one with a dummy element, move all elements after i 55 // over by one, then place the new signature in that gap. 56 mSig.Signatures = append(mSig.Signatures, &signing.SingleSignatureData{}) 57 copy(mSig.Signatures[newSigIndex+1:], mSig.Signatures[newSigIndex:]) 58 mSig.Signatures[newSigIndex] = sig 59 } 60 61 // AddSignatureFromPubKey adds a signature to the multisig, at the index in 62 // keys corresponding to the provided pubkey. 63 func AddSignatureFromPubKey(mSig *signing.MultiSignatureData, sig signing.SignatureData, pubkey types.PubKey, keys []types.PubKey) error { 64 if mSig == nil { 65 return fmt.Errorf("value of mSig is nil %v", mSig) 66 } 67 68 if sig == nil { 69 return fmt.Errorf("value of sig is nil %v", sig) 70 } 71 72 if pubkey == nil { 73 return fmt.Errorf("pubkey can't be nil %v", pubkey) 74 } 75 76 if len(keys) == 0 { 77 return errors.New("keys can't be empty") 78 } 79 80 index := getIndex(pubkey, keys) 81 if index == -1 { 82 keysStr := make([]string, len(keys)) 83 for i, k := range keys { 84 keysStr[i] = fmt.Sprintf("%X", k.Bytes()) 85 } 86 87 return fmt.Errorf("provided key %X doesn't exist in pubkeys: \n%s", pubkey.Bytes(), strings.Join(keysStr, "\n")) 88 } 89 90 AddSignature(mSig, sig, index) 91 return nil 92 } 93 94 func AddSignatureV2(mSig *signing.MultiSignatureData, sig signing.SignatureV2, keys []types.PubKey) error { 95 return AddSignatureFromPubKey(mSig, sig.Data, sig.PubKey, keys) 96 }