github.com/InjectiveLabs/sdk-go@v1.53.0/chain/crypto/ethsecp256k1/ethsecp256k1.go (about)

     1  package ethsecp256k1
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/ecdsa"
     6  	"crypto/subtle"
     7  	"fmt"
     8  
     9  	"cosmossdk.io/errors"
    10  	tmcrypto "github.com/cometbft/cometbft/crypto"
    11  	"github.com/cosmos/cosmos-sdk/codec"
    12  	cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
    13  	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
    14  	ethcrypto "github.com/ethereum/go-ethereum/crypto"
    15  	"github.com/ethereum/go-ethereum/crypto/secp256k1"
    16  )
    17  
    18  const (
    19  	// PrivKeySize defines the size of the PrivKey bytes
    20  	PrivKeySize = 32
    21  	// PubKeySize defines the size of the PubKey bytes
    22  	PubKeySize = 33
    23  	// KeyType is the string constant for the Secp256k1 algorithm
    24  	KeyType = "eth_secp256k1"
    25  )
    26  
    27  // Amino encoding names
    28  const (
    29  	// PrivKeyName defines the amino encoding name for the EthSecp256k1 private key
    30  	PrivKeyName = "injective/PrivKeyEthSecp256k1"
    31  	// PubKeyName defines the amino encoding name for the EthSecp256k1 public key
    32  	PubKeyName = "injective/PubKeyEthSecp256k1"
    33  )
    34  
    35  // ----------------------------------------------------------------------------
    36  // secp256k1 Private Key
    37  
    38  var (
    39  	_ cryptotypes.PrivKey  = &PrivKey{}
    40  	_ codec.AminoMarshaler = &PrivKey{}
    41  )
    42  
    43  // GenerateKey generates a new random private key. It returns an error upon
    44  // failure.
    45  func GenerateKey() (*PrivKey, error) {
    46  	priv, err := ethcrypto.GenerateKey()
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	return &PrivKey{
    52  		Key: ethcrypto.FromECDSA(priv),
    53  	}, nil
    54  }
    55  
    56  // Bytes returns the byte representation of the ECDSA Private Key.
    57  func (privKey *PrivKey) Bytes() []byte {
    58  	return privKey.Key
    59  }
    60  
    61  // PubKey returns the ECDSA private key's public key.
    62  func (privKey PrivKey) PubKey() cryptotypes.PubKey {
    63  	ecdsaPrivKey := privKey.ToECDSA()
    64  
    65  	return &PubKey{
    66  		Key: ethcrypto.CompressPubkey(&ecdsaPrivKey.PublicKey),
    67  	}
    68  }
    69  
    70  // Equals returns true if two ECDSA private keys are equal and false otherwise.
    71  func (privKey *PrivKey) Equals(other cryptotypes.LedgerPrivKey) bool {
    72  	return privKey.Type() == other.Type() && subtle.ConstantTimeCompare(privKey.Bytes(), other.Bytes()) == 1
    73  }
    74  
    75  // Type returns eth_secp256k1
    76  func (privKey *PrivKey) Type() string {
    77  	return KeyType
    78  }
    79  
    80  // MarshalAmino overrides Amino binary marshalling.
    81  func (privKey PrivKey) MarshalAmino() ([]byte, error) {
    82  	return privKey.Key, nil
    83  }
    84  
    85  // UnmarshalAmino overrides Amino binary marshalling.
    86  func (privKey *PrivKey) UnmarshalAmino(bz []byte) error {
    87  	if len(bz) != PrivKeySize {
    88  		return fmt.Errorf("invalid privkey size, expected %d got %d", PrivKeySize, len(bz))
    89  	}
    90  	privKey.Key = bz
    91  
    92  	return nil
    93  }
    94  
    95  // MarshalAminoJSON overrides Amino JSON marshalling.
    96  func (privKey PrivKey) MarshalAminoJSON() ([]byte, error) {
    97  	// When we marshal to Amino JSON, we don't marshal the "key" field itself,
    98  	// just its contents (i.e. the key bytes).
    99  	return privKey.MarshalAmino()
   100  }
   101  
   102  // UnmarshalAminoJSON overrides Amino JSON marshalling.
   103  func (privKey *PrivKey) UnmarshalAminoJSON(bz []byte) error {
   104  	return privKey.UnmarshalAmino(bz)
   105  }
   106  
   107  // Sign creates a recoverable ECDSA signature on the secp256k1 curve over the
   108  // Keccak256 hash of the provided message. The produced signature is 65 bytes
   109  // where the last byte contains the recovery ID.
   110  func (privKey PrivKey) Sign(msg []byte) ([]byte, error) {
   111  	return ethcrypto.Sign(ethcrypto.Keccak256Hash(msg).Bytes(), privKey.ToECDSA())
   112  }
   113  
   114  // ToECDSA returns the ECDSA private key as a reference to ecdsa.PrivateKey type.
   115  // The function will panic if the private key is invalid.
   116  func (privKey PrivKey) ToECDSA() *ecdsa.PrivateKey {
   117  	key, err := ethcrypto.ToECDSA(privKey.Bytes())
   118  	if err != nil {
   119  		panic(err)
   120  	}
   121  	return key
   122  }
   123  
   124  // ----------------------------------------------------------------------------
   125  // secp256k1 Public Key
   126  
   127  var (
   128  	_ cryptotypes.PubKey   = &PubKey{}
   129  	_ codec.AminoMarshaler = &PubKey{}
   130  )
   131  
   132  // Address returns the address of the ECDSA public key.
   133  // The function will panic if the public key is invalid.
   134  func (pubKey PubKey) Address() tmcrypto.Address {
   135  	pubk, err := ethcrypto.DecompressPubkey(pubKey.Key)
   136  	if err != nil {
   137  		if pubk, err = ethcrypto.UnmarshalPubkey(pubKey.Key); err != nil {
   138  			panic(err)
   139  		}
   140  	}
   141  
   142  	return tmcrypto.Address(ethcrypto.PubkeyToAddress(*pubk).Bytes())
   143  }
   144  
   145  // Bytes returns the raw bytes of the ECDSA public key.
   146  func (pubKey PubKey) Bytes() []byte {
   147  	return pubKey.Key
   148  }
   149  
   150  // String implements the fmt.Stringer interface.
   151  func (pubKey *PubKey) String() string {
   152  	return fmt.Sprintf("EthPubKeySecp256k1{%X}", pubKey.Key)
   153  }
   154  
   155  // Type returns eth_secp256k1
   156  func (pubKey *PubKey) Type() string {
   157  	return KeyType
   158  }
   159  
   160  // Equals returns true if the pubkey type is the same and their bytes are deeply equal.
   161  func (pubKey *PubKey) Equals(other cryptotypes.PubKey) bool {
   162  	return pubKey.Type() == other.Type() && bytes.Equal(pubKey.Bytes(), other.Bytes())
   163  }
   164  
   165  // MarshalAmino overrides Amino binary marshalling.
   166  func (pubKey PubKey) MarshalAmino() ([]byte, error) {
   167  	return pubKey.Key, nil
   168  }
   169  
   170  // UnmarshalAmino overrides Amino binary marshalling.
   171  func (pubKey *PubKey) UnmarshalAmino(bz []byte) error {
   172  	if len(bz) != PubKeySize {
   173  		return errors.Wrapf(sdkerrors.ErrInvalidPubKey, "invalid pubkey size, expected %d, got %d", PubKeySize, len(bz))
   174  	}
   175  	pubKey.Key = bz
   176  
   177  	return nil
   178  }
   179  
   180  // MarshalAminoJSON overrides Amino JSON marshalling.
   181  func (pubKey PubKey) MarshalAminoJSON() ([]byte, error) {
   182  	// When we marshal to Amino JSON, we don't marshal the "key" field itself,
   183  	// just its contents (i.e. the key bytes).
   184  	return pubKey.MarshalAmino()
   185  }
   186  
   187  // UnmarshalAminoJSON overrides Amino JSON marshalling.
   188  func (pubKey *PubKey) UnmarshalAminoJSON(bz []byte) error {
   189  	return pubKey.UnmarshalAmino(bz)
   190  }
   191  
   192  // VerifySignature verifies that the ECDSA public key created a given signature over
   193  // the provided message. It will calculate the Keccak256 hash of the message
   194  // prior to verification.
   195  func (pubKey PubKey) VerifySignature(msg, sig []byte) bool {
   196  	if len(sig) == 65 {
   197  		// remove recovery ID if contained in the signature
   198  		sig = sig[:64]
   199  	}
   200  
   201  	// the signature needs to be in [R || S] format when provided to VerifySignature
   202  	return secp256k1.VerifySignature(pubKey.Key, ethcrypto.Keccak256Hash(msg).Bytes(), sig)
   203  }