1

I generated a signed message using ethers.js. Here's how I did that:

const provider = new ethers.providers.Web3Provider(web3Provider.provider);
const signer = provider.getSigner();
await signer.signMessage("hexcowboy")

Now I have a message signed by 0x37121F74d25262011AdD8cc8D13E6923AEb699d8 with the message hexcowboy and the signed message being 0x27876c5cc1be67e8313633ab0f72ace790886c88a664df1ca0b858c1834782002a0ae1e44fdb3fe7586eec431c115205a36a05bbd31c6c2bce04605825e91cfe1b.

I know my message signature is valid because ether.js can recover my public key from it:

import { utils } from 'ethers';
const output = utils.verifyMessage("hexcowboy", "0x27876c5cc1be67e8313633ab0f72ace790886c88a664df1ca0b858c1834782002a0ae1e44fdb3fe7586eec431c115205a36a05bbd31c6c2bce04605825e91cfe1b");
console.log(output);

When I try to recover the public key from this message using Go Ethereum, I'm not getting the correct public key using SigToPub.

func VerifyMessage(ctx context.Context, message string, signedMessage string) (string, error) {
    // Hash the unsigned message
    hash := crypto.Keccak256Hash([]byte(message))

    // Get the bytes of the signed message
    decodedMessage := hexutil.MustDecode(signedMessage)
    decodedMessage[64] = 0

    test, err := crypto.SigToPub(hash.Bytes(), decodedMessage)
    if err != nil {
        return "", err
    }

    fmt.Println(crypto.PubkeyToAddress(*test)) // 0xDd874aAD8bAf218e4DfAd2b59E2798E775e48eB5

    return "", nil
}

What do I need to do to recover an address from an ethers.js signed message in Go Ethereum?

1 Answer 1

2

Solved my answer. I wasn't aware I needed to add the prefix for EIP-191 signed messages. Here is my working code:

func VerifyMessage(ctx context.Context, message string, signedMessage string) (string, error) {
    // Hash the unsigned message using EIP-191
    hashedMessage := []byte("\x19Ethereum Signed Message:\n" + strconv.Itoa(len(message)) + message)
    hash := crypto.Keccak256Hash(hashedMessage)

    // Get the bytes of the signed message
    decodedMessage := hexutil.MustDecode(signedMessage)

    // Handles cases where EIP-115 is not implemented (most wallets don't implement it)
    if decodedMessage[64] == 27 || decodedMessage[64] == 28 {
        decodedMessage[64] -= 27
    }

    // Recover a public key from the signed message
    sigPublicKeyECDSA, err := crypto.SigToPub(hash.Bytes(), decodedMessage)
    if sigPublicKeyECDSA == nil {
        err = errors.New("Could not get a public get from the message signature")
    }
    if err != nil {
        return "", err
    }

    return crypto.PubkeyToAddress(*sigPublicKeyECDSA).String(), nil
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.