github.com/InjectiveLabs/sdk-go@v1.53.0/chain/peggy/types/ethereum_signer.go (about) 1 package types 2 3 import ( 4 "crypto/ecdsa" 5 "fmt" 6 "math/big" 7 8 "cosmossdk.io/errors" 9 "github.com/ethereum/go-ethereum/common" 10 "github.com/ethereum/go-ethereum/crypto" 11 ) 12 13 const ( 14 signaturePrefix = "\x19Ethereum Signed Message:\n32" 15 ) 16 17 // NewEthereumSignature creates a new signuature over a given byte array 18 func NewEthereumSignature(hash common.Hash, privateKey *ecdsa.PrivateKey) ([]byte, error) { 19 if privateKey == nil { 20 return nil, errors.Wrap(ErrEmpty, "private key") 21 } 22 protectedHash := crypto.Keccak256Hash(append([]uint8(signaturePrefix), hash[:]...)) 23 return crypto.Sign(protectedHash.Bytes(), privateKey) 24 } 25 26 // decodeSignature was duplicated from go-ethereum with slight modifications 27 func decodeSignature(sig []byte) (r, s *big.Int, v byte) { 28 if len(sig) != crypto.SignatureLength { 29 panic(fmt.Sprintf("wrong size for signature: got %d, want %d", len(sig), crypto.SignatureLength)) 30 } 31 r = new(big.Int).SetBytes(sig[:32]) 32 s = new(big.Int).SetBytes(sig[32:64]) 33 if sig[64] == 27 || sig[64] == 28 { 34 v = sig[64] - 27 35 } else { 36 v = sig[64] 37 } 38 return r, s, v 39 } 40 41 // ValidateEthereumSignature takes a message, an associated signature and public key and 42 // returns an error if the signature isn't valid 43 func EthAddressFromSignature(hash common.Hash, signature []byte) (common.Address, error) { 44 if len(signature) < 65 { 45 return common.Address{}, errors.Wrap(ErrInvalid, "signature too short") 46 } 47 48 r, s, v := decodeSignature(signature) 49 if !crypto.ValidateSignatureValues(v, r, s, true) { 50 return common.Address{}, errors.Wrap(ErrInvalid, "Signature values failed validation") 51 } 52 53 // To verify signature 54 // - use crypto.SigToPub to get the public key 55 // - use crypto.PubkeyToAddress to get the address 56 // - compare this to the address given. 57 58 // for backwards compatibility reasons the V value of an Ethereum sig is presented 59 // as 27 or 28, internally though it should be a 0-3 value due to changed formats. 60 // It seems that go-ethereum expects this to be done before sigs actually reach it's 61 // internal validation functions. In order to comply with this requirement we check 62 // the sig an dif it's in standard format we correct it. If it's in go-ethereum's expected 63 // format already we make no changes. 64 // 65 // We could attempt to break or otherwise exit early on obviously invalid values for this 66 // byte, but that's a task best left to go-ethereum 67 if signature[64] == 27 || signature[64] == 28 { 68 signature[64] -= 27 69 } 70 71 protectedHash := crypto.Keccak256Hash(append([]byte(signaturePrefix), hash[:]...)) 72 73 pubkey, err := crypto.SigToPub(protectedHash.Bytes(), signature) 74 if err != nil { 75 return common.Address{}, errors.Wrap(err, "signature to public key") 76 } 77 78 addr := crypto.PubkeyToAddress(*pubkey) 79 80 return addr, nil 81 } 82 83 // ValidateEthereumSignature takes a message, an associated signature and public key and 84 // returns an error if the signature isn't valid 85 func ValidateEthereumSignature(hash common.Hash, signature []byte, ethAddress common.Address) error { 86 addr, err := EthAddressFromSignature(hash, signature) 87 88 if err != nil { 89 return errors.Wrap(err, "") 90 } 91 92 if addr != ethAddress { 93 return errors.Wrap(ErrInvalid, "signature not matching") 94 } 95 96 return nil 97 }