github.com/0xsequence/ethkit@v1.25.0/ethwallet/utils.go (about) 1 package ethwallet 2 3 import ( 4 "bytes" 5 "fmt" 6 7 "github.com/0xsequence/ethkit/ethcoder" 8 "github.com/0xsequence/ethkit/go-ethereum/common" 9 "github.com/0xsequence/ethkit/go-ethereum/crypto" 10 ) 11 12 func RecoverAddress(message, signature []byte) (common.Address, error) { 13 msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%v%s", len(message), message) 14 if len(signature) != 65 { 15 return common.Address{}, fmt.Errorf("signature is not of proper length") 16 } 17 return RecoverAddressFromDigest(crypto.Keccak256([]byte(msg)), signature) 18 } 19 20 func RecoverAddressFromDigest(digest, signature []byte) (common.Address, error) { 21 if len(digest) != 32 { 22 return common.Address{}, fmt.Errorf("digest is not of proper length (=32)") 23 } 24 if len(signature) != 65 { 25 return common.Address{}, fmt.Errorf("signature is not of proper length (=65)") 26 } 27 28 sig := make([]byte, 65) 29 copy(sig, signature) 30 31 if sig[64] > 1 { 32 sig[64] -= 27 // recovery ID 33 } 34 35 pubkey, err := crypto.SigToPub(digest, sig) 36 if err != nil { 37 return common.Address{}, err 38 } 39 address := crypto.PubkeyToAddress(*pubkey) 40 41 return address, nil 42 } 43 44 func IsValidEOASignature(address common.Address, digest, signature []byte) (bool, error) { 45 if len(digest) == 0 || len(signature) == 0 { 46 return false, fmt.Errorf("digest and signature must not be empty") 47 } 48 if len(signature) != 65 { 49 return false, fmt.Errorf("signature is not of proper length") 50 } 51 52 sig := make([]byte, 65) 53 copy(sig, signature) 54 55 if sig[64] > 1 { 56 sig[64] -= 27 // recovery ID 57 } 58 59 pubkey, err := crypto.SigToPub(digest, sig) 60 if err != nil { 61 return false, err 62 } 63 recoveredAddress := crypto.PubkeyToAddress(*pubkey) 64 if recoveredAddress == address { 65 return true, nil 66 } 67 return false, fmt.Errorf("invalid signature") 68 } 69 70 func IsValid191Signature(address common.Address, message, signature []byte) (bool, error) { 71 if len(message) == 0 || len(signature) == 0 { 72 return false, fmt.Errorf("message and signature must not be empty") 73 } 74 if len(signature) != 65 { 75 return false, fmt.Errorf("signature is not of proper length") 76 } 77 78 message191 := []byte("\x19Ethereum Signed Message:\n") 79 if !bytes.HasPrefix(message, message191) { 80 mlen := fmt.Sprintf("%d", len(message)) 81 message191 = append(message191, []byte(mlen)...) 82 message191 = append(message191, message...) 83 } else { 84 message191 = message 85 } 86 87 sig := make([]byte, 65) 88 copy(sig, signature) 89 90 hash := crypto.Keccak256(message191) 91 if sig[64] > 1 { 92 sig[64] -= 27 // recovery ID 93 } 94 95 pubkey, err := crypto.SigToPub(hash, sig) 96 if err != nil { 97 return false, err 98 } 99 recoveredAddress := crypto.PubkeyToAddress(*pubkey) 100 if recoveredAddress == address { 101 return true, nil 102 } 103 return false, fmt.Errorf("invalid signature") 104 } 105 106 // Validate the public key address of a signed message 107 func ValidateEthereumSignature(address string, message []byte, signatureHex string) (bool, error) { 108 sig, err := ethcoder.HexDecode(signatureHex) 109 if err != nil { 110 return false, err 111 } 112 return IsValid191Signature(common.HexToAddress(address), message, sig) 113 }