github.com/okex/exchain@v1.8.0/libs/tendermint/crypto/encoding/amino/amino.go (about)

     1  package cryptoamino
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"reflect"
     7  
     8  	"github.com/okex/exchain/libs/tendermint/crypto"
     9  	"github.com/okex/exchain/libs/tendermint/crypto/ed25519"
    10  	"github.com/okex/exchain/libs/tendermint/crypto/multisig"
    11  	"github.com/okex/exchain/libs/tendermint/crypto/secp256k1"
    12  	"github.com/okex/exchain/libs/tendermint/crypto/sr25519"
    13  	"github.com/tendermint/go-amino"
    14  )
    15  
    16  var cdc = amino.NewCodec()
    17  
    18  // nameTable is used to map public key concrete types back
    19  // to their registered amino names. This should eventually be handled
    20  // by amino. Example usage:
    21  // nameTable[reflect.TypeOf(ed25519.PubKeyEd25519{})] = ed25519.PubKeyAminoName
    22  var nameTable = make(map[reflect.Type]string, 3)
    23  
    24  func init() {
    25  	// NOTE: It's important that there be no conflicts here,
    26  	// as that would change the canonical representations,
    27  	// and therefore change the address.
    28  	// TODO: Remove above note when
    29  	// https://github.com/tendermint/go-amino/issues/9
    30  	// is resolved
    31  	RegisterAmino(cdc)
    32  
    33  	// TODO: Have amino provide a way to go from concrete struct to route directly.
    34  	// Its currently a private API
    35  	nameTable[reflect.TypeOf(ed25519.PubKeyEd25519{})] = ed25519.PubKeyAminoName
    36  	nameTable[reflect.TypeOf(sr25519.PubKeySr25519{})] = sr25519.PubKeyAminoName
    37  	nameTable[reflect.TypeOf(secp256k1.PubKeySecp256k1{})] = secp256k1.PubKeyAminoName
    38  	nameTable[reflect.TypeOf(multisig.PubKeyMultisigThreshold{})] = multisig.PubKeyMultisigThresholdAminoRoute
    39  }
    40  
    41  // PubkeyAminoName returns the amino route of a pubkey
    42  // cdc is currently passed in, as eventually this will not be using
    43  // a package level codec.
    44  func PubkeyAminoName(cdc *amino.Codec, key crypto.PubKey) (string, bool) {
    45  	route, found := nameTable[reflect.TypeOf(key)]
    46  	return route, found
    47  }
    48  
    49  // RegisterAmino registers all crypto related types in the given (amino) codec.
    50  func RegisterAmino(cdc *amino.Codec) {
    51  	// These are all written here instead of
    52  	cdc.RegisterInterface((*crypto.PubKey)(nil), nil)
    53  	cdc.RegisterConcrete(ed25519.PubKeyEd25519{},
    54  		ed25519.PubKeyAminoName, nil)
    55  	cdc.RegisterConcrete(sr25519.PubKeySr25519{},
    56  		sr25519.PubKeyAminoName, nil)
    57  	cdc.RegisterConcrete(secp256k1.PubKeySecp256k1{},
    58  		secp256k1.PubKeyAminoName, nil)
    59  	cdc.RegisterConcrete(multisig.PubKeyMultisigThreshold{},
    60  		multisig.PubKeyMultisigThresholdAminoRoute, nil)
    61  
    62  	cdc.RegisterInterface((*crypto.PrivKey)(nil), nil)
    63  	cdc.RegisterConcrete(ed25519.PrivKeyEd25519{},
    64  		ed25519.PrivKeyAminoName, nil)
    65  	cdc.RegisterConcrete(sr25519.PrivKeySr25519{},
    66  		sr25519.PrivKeyAminoName, nil)
    67  	cdc.RegisterConcrete(secp256k1.PrivKeySecp256k1{},
    68  		secp256k1.PrivKeyAminoName, nil)
    69  }
    70  
    71  // RegisterKeyType registers an external key type to allow decoding it from bytes
    72  func RegisterKeyType(o interface{}, name string) {
    73  	cdc.RegisterConcrete(o, name, nil)
    74  	nameTable[reflect.TypeOf(o)] = name
    75  }
    76  
    77  // PrivKeyFromBytes unmarshals private key bytes and returns a PrivKey
    78  func PrivKeyFromBytes(privKeyBytes []byte) (privKey crypto.PrivKey, err error) {
    79  	err = cdc.UnmarshalBinaryBare(privKeyBytes, &privKey)
    80  	return
    81  }
    82  
    83  // PubKeyFromBytes unmarshals public key bytes and returns a PubKey
    84  func PubKeyFromBytes(pubKeyBytes []byte) (pubKey crypto.PubKey, err error) {
    85  	err = cdc.UnmarshalBinaryBare(pubKeyBytes, &pubKey)
    86  	return
    87  }
    88  
    89  // hard code here for performance
    90  var typePubKeySecp256k1Prefix = []byte{0xeb, 0x5a, 0xe9, 0x87}
    91  var typePubKeyEd25519Prefix = []byte{0x16, 0x24, 0xde, 0x64}
    92  var typePubKeySr25519Prefix = []byte{0x0d, 0xfb, 0x10, 0x05}
    93  
    94  const typePrefixAndSizeLen = 4 + 1
    95  const aminoTypePrefix = 4
    96  
    97  // unmarshalPubKeyFromAminoFast does a fast path for amino decodes.
    98  func unmarshalPubKeyFromAminoFast(data []byte) (crypto.PubKey, error) {
    99  	if len(data) < aminoTypePrefix {
   100  		return nil, errors.New("pubkey raw data size error")
   101  	}
   102  	if data[0] == 0x00 {
   103  		return nil, errors.New("unmarshal pubkey with disamb do not implement")
   104  	}
   105  
   106  	prefix := data[0:aminoTypePrefix]
   107  	data = data[aminoTypePrefix:]
   108  
   109  	if bytes.Compare(typePubKeySecp256k1Prefix, prefix) == 0 {
   110  		sub, err := amino.DecodeByteSliceWithoutCopy(&data)
   111  		if err != nil {
   112  			return nil, err
   113  		}
   114  		if len(sub) != secp256k1.PubKeySecp256k1Size && len(data) != 0 {
   115  			return nil, errors.New("pubkey secp256k1 size error")
   116  		}
   117  		pubKey := secp256k1.PubKeySecp256k1{}
   118  		copy(pubKey[:], sub)
   119  		return pubKey, nil
   120  	} else if bytes.Compare(typePubKeyEd25519Prefix, prefix) == 0 {
   121  		sub, err := amino.DecodeByteSliceWithoutCopy(&data)
   122  		if err != nil {
   123  			return nil, err
   124  		}
   125  		if len(sub) != ed25519.PubKeyEd25519Size && len(data) != 0 {
   126  			return nil, errors.New("pubkey ed25519 size error")
   127  		}
   128  		pubKey := ed25519.PubKeyEd25519{}
   129  		copy(pubKey[:], sub)
   130  		return pubKey, nil
   131  	} else if bytes.Compare(typePubKeySr25519Prefix, prefix) == 0 {
   132  		sub, err := amino.DecodeByteSliceWithoutCopy(&data)
   133  		if err != nil {
   134  			return nil, err
   135  		}
   136  		if len(sub) != sr25519.PubKeySr25519Size && len(data) != 0 {
   137  			return nil, errors.New("pubkey sr25519 size error")
   138  		}
   139  		pubKey := sr25519.PubKeySr25519{}
   140  		copy(pubKey[:], sub)
   141  		return pubKey, nil
   142  	} else {
   143  		return nil, errors.New("unmarshal pubkey with unknown type")
   144  	}
   145  }
   146  
   147  // UnmarshalPubKeyFromAmino decode pubkey from amino bytes,
   148  // bytes should start with type prefix
   149  func UnmarshalPubKeyFromAmino(cdc *amino.Codec, data []byte) (crypto.PubKey, error) {
   150  	var pubkey crypto.PubKey
   151  	var err error
   152  	pubkey, err = unmarshalPubKeyFromAminoFast(data)
   153  	if err != nil {
   154  		var pubkeyTmp crypto.PubKey
   155  		err = cdc.UnmarshalBinaryBare(data, &pubkeyTmp)
   156  		pubkey = pubkeyTmp
   157  	}
   158  	return pubkey, err
   159  }
   160  
   161  func MarshalPubKeyToAmino(cdc *amino.Codec, key crypto.PubKey) (data []byte, err error) {
   162  	switch key.(type) {
   163  	case secp256k1.PubKeySecp256k1:
   164  		data = make([]byte, 0, secp256k1.PubKeySecp256k1Size+typePrefixAndSizeLen)
   165  		data = append(data, typePubKeySecp256k1Prefix...)
   166  		data = append(data, byte(secp256k1.PubKeySecp256k1Size))
   167  		keyData := key.(secp256k1.PubKeySecp256k1)
   168  		data = append(data, keyData[:]...)
   169  		return data, nil
   170  	case ed25519.PubKeyEd25519:
   171  		data = make([]byte, 0, ed25519.PubKeyEd25519Size+typePrefixAndSizeLen)
   172  		data = append(data, typePubKeyEd25519Prefix...)
   173  		data = append(data, byte(ed25519.PubKeyEd25519Size))
   174  		keyData := key.(ed25519.PubKeyEd25519)
   175  		data = append(data, keyData[:]...)
   176  		return data, nil
   177  	case sr25519.PubKeySr25519:
   178  		data = make([]byte, 0, sr25519.PubKeySr25519Size+typePrefixAndSizeLen)
   179  		data = append(data, typePubKeySr25519Prefix...)
   180  		data = append(data, byte(sr25519.PubKeySr25519Size))
   181  		keyData := key.(sr25519.PubKeySr25519)
   182  		data = append(data, keyData[:]...)
   183  		return data, nil
   184  	}
   185  	data, err = cdc.MarshalBinaryBare(key)
   186  	if err != nil {
   187  		return nil, err
   188  	}
   189  	return data, nil
   190  }
   191  
   192  func MarshalPubKeyAminoTo(cdc *amino.Codec, key crypto.PubKey, buf *bytes.Buffer) error {
   193  	switch keyData := key.(type) {
   194  	case secp256k1.PubKeySecp256k1:
   195  		buf.Write(typePubKeySecp256k1Prefix)
   196  		buf.WriteByte(byte(secp256k1.PubKeySecp256k1Size))
   197  		buf.Write(keyData[:])
   198  		return nil
   199  	case ed25519.PubKeyEd25519:
   200  		buf.Write(typePubKeyEd25519Prefix)
   201  		buf.WriteByte(byte(ed25519.PubKeyEd25519Size))
   202  		buf.Write(keyData[:])
   203  		return nil
   204  	case sr25519.PubKeySr25519:
   205  		buf.Write(typePubKeySr25519Prefix)
   206  		buf.WriteByte(byte(sr25519.PubKeySr25519Size))
   207  		buf.Write(keyData[:])
   208  		return nil
   209  	}
   210  	data, err := cdc.MarshalBinaryBare(key)
   211  	if err != nil {
   212  		return err
   213  	}
   214  	buf.Write(data)
   215  	return nil
   216  }
   217  
   218  func PubKeyAminoSize(pubKey crypto.PubKey, cdc *amino.Codec) int {
   219  	switch k := pubKey.(type) {
   220  	case secp256k1.PubKeySecp256k1:
   221  		return amino.PrefixBytesLen + k.AminoSize(cdc)
   222  	case ed25519.PubKeyEd25519:
   223  		return amino.PrefixBytesLen + k.AminoSize(cdc)
   224  	case sr25519.PubKeySr25519:
   225  		return amino.PrefixBytesLen + k.AminoSize(cdc)
   226  	}
   227  
   228  	if sizer, ok := pubKey.(amino.Sizer); ok {
   229  		var typePrefix [8]byte
   230  		tpl, err := cdc.GetTypePrefix(pubKey, typePrefix[:])
   231  		if err != nil {
   232  			return 0
   233  		}
   234  		return tpl + sizer.AminoSize(cdc)
   235  	} else {
   236  		encodedPubKey, err := cdc.MarshalBinaryBare(pubKey)
   237  		if err != nil {
   238  			return 0
   239  		}
   240  		return len(encodedPubKey)
   241  	}
   242  }