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  }