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 }