github.com/cosmos/cosmos-sdk@v0.50.10/x/auth/tx/sigs.go (about)

     1  package tx
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/cosmos/cosmos-sdk/codec"
     7  	codectypes "github.com/cosmos/cosmos-sdk/codec/types"
     8  	cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
     9  	"github.com/cosmos/cosmos-sdk/types/tx"
    10  	"github.com/cosmos/cosmos-sdk/types/tx/signing"
    11  )
    12  
    13  // SignatureDataToModeInfoAndSig converts a SignatureData to a ModeInfo and raw bytes signature
    14  func SignatureDataToModeInfoAndSig(data signing.SignatureData) (*tx.ModeInfo, []byte) {
    15  	if data == nil {
    16  		return nil, nil
    17  	}
    18  
    19  	switch data := data.(type) {
    20  	case *signing.SingleSignatureData:
    21  		return &tx.ModeInfo{
    22  			Sum: &tx.ModeInfo_Single_{
    23  				Single: &tx.ModeInfo_Single{Mode: data.SignMode},
    24  			},
    25  		}, data.Signature
    26  	case *signing.MultiSignatureData:
    27  		n := len(data.Signatures)
    28  		modeInfos := make([]*tx.ModeInfo, n)
    29  		sigs := make([][]byte, n)
    30  
    31  		for i, d := range data.Signatures {
    32  			modeInfos[i], sigs[i] = SignatureDataToModeInfoAndSig(d)
    33  		}
    34  
    35  		multisig := cryptotypes.MultiSignature{
    36  			Signatures: sigs,
    37  		}
    38  		sig, err := multisig.Marshal()
    39  		if err != nil {
    40  			panic(err)
    41  		}
    42  
    43  		return &tx.ModeInfo{
    44  			Sum: &tx.ModeInfo_Multi_{
    45  				Multi: &tx.ModeInfo_Multi{
    46  					Bitarray:  data.BitArray,
    47  					ModeInfos: modeInfos,
    48  				},
    49  			},
    50  		}, sig
    51  	default:
    52  		panic(fmt.Sprintf("unexpected signature data type %T", data))
    53  	}
    54  }
    55  
    56  // ModeInfoAndSigToSignatureData converts a ModeInfo and raw bytes signature to a SignatureData or returns
    57  // an error
    58  func ModeInfoAndSigToSignatureData(modeInfo *tx.ModeInfo, sig []byte) (signing.SignatureData, error) {
    59  	switch modeInfo := modeInfo.Sum.(type) {
    60  	case *tx.ModeInfo_Single_:
    61  		return &signing.SingleSignatureData{
    62  			SignMode:  modeInfo.Single.Mode,
    63  			Signature: sig,
    64  		}, nil
    65  
    66  	case *tx.ModeInfo_Multi_:
    67  		multi := modeInfo.Multi
    68  
    69  		sigs, err := decodeMultisignatures(sig)
    70  		if err != nil {
    71  			return nil, err
    72  		}
    73  
    74  		sigv2s := make([]signing.SignatureData, len(sigs))
    75  		for i, mi := range multi.ModeInfos {
    76  			sigv2s[i], err = ModeInfoAndSigToSignatureData(mi, sigs[i])
    77  			if err != nil {
    78  				return nil, err
    79  			}
    80  		}
    81  
    82  		return &signing.MultiSignatureData{
    83  			BitArray:   multi.Bitarray,
    84  			Signatures: sigv2s,
    85  		}, nil
    86  
    87  	default:
    88  		panic(fmt.Errorf("unexpected ModeInfo data type %T", modeInfo))
    89  	}
    90  }
    91  
    92  // decodeMultisignatures safely decodes the raw bytes as a MultiSignature protobuf message
    93  func decodeMultisignatures(bz []byte) ([][]byte, error) {
    94  	multisig := cryptotypes.MultiSignature{}
    95  	err := multisig.Unmarshal(bz)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  	// NOTE: it is import to reject multi-signatures that contain unrecognized fields because this is an exploitable
   100  	// malleability in the protobuf message. Basically an attacker could bloat a MultiSignature message with unknown
   101  	// fields, thus bloating the transaction and causing it to fail.
   102  	if len(multisig.XXX_unrecognized) > 0 {
   103  		return nil, fmt.Errorf("rejecting unrecognized fields found in MultiSignature")
   104  	}
   105  	return multisig.Signatures, nil
   106  }
   107  
   108  func (g config) MarshalSignatureJSON(sigs []signing.SignatureV2) ([]byte, error) {
   109  	descs := make([]*signing.SignatureDescriptor, len(sigs))
   110  
   111  	for i, sig := range sigs {
   112  		descData := signing.SignatureDataToProto(sig.Data)
   113  		any, err := codectypes.NewAnyWithValue(sig.PubKey)
   114  		if err != nil {
   115  			return nil, err
   116  		}
   117  
   118  		descs[i] = &signing.SignatureDescriptor{
   119  			PublicKey: any,
   120  			Data:      descData,
   121  			Sequence:  sig.Sequence,
   122  		}
   123  	}
   124  
   125  	toJSON := &signing.SignatureDescriptors{Signatures: descs}
   126  
   127  	return codec.ProtoMarshalJSON(toJSON, nil)
   128  }
   129  
   130  func (g config) UnmarshalSignatureJSON(bz []byte) ([]signing.SignatureV2, error) {
   131  	var sigDescs signing.SignatureDescriptors
   132  	err := g.protoCodec.UnmarshalJSON(bz, &sigDescs)
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  
   137  	sigs := make([]signing.SignatureV2, len(sigDescs.Signatures))
   138  	for i, desc := range sigDescs.Signatures {
   139  		pubKey, _ := desc.PublicKey.GetCachedValue().(cryptotypes.PubKey)
   140  
   141  		data := signing.SignatureDataFromProto(desc.Data)
   142  
   143  		sigs[i] = signing.SignatureV2{
   144  			PubKey:   pubKey,
   145  			Data:     data,
   146  			Sequence: desc.Sequence,
   147  		}
   148  	}
   149  
   150  	return sigs, nil
   151  }