Web3.py – Recovering JavaScript Signed Messages in Python

javascriptpythonsignatureweb3.pyweb3js

Running into problems taking a signed message from Web3.js, and recovering the signing address in Web3.py.

Here is my code in JavaScript to create a signed message:

async function sign_message() {
    var message = "hi"
    var message_hash = web3.eth.accounts.hashMessage(message)
    //message_hash == 0x0d52783c4cbad7ebaf7eb943fc648f5282a52070442fc18d8dd16ddb2fcbaf66

    var accounts = await web3.eth.getAccounts()
    var signature = await web3.eth.personal.sign(message, accounts[0])
    //accounts[0] ~ 0x6d31165d5d932d571f3b44695653b46dcc327e84
    console.log(signature)
    //signature == 0x29887fe718fcc6e64b97d681f80e6fd485883a45ec0dbc0e35a3752acf1065655d73c9034cac3df0dc82da015abe42367f5e90fd499d872b19610a3ea9c176921b
}

Then here is trying to recover the address in Python:

>>> message = "hi"
>>> message_hash = defunct_hash_message(text=message)
>>> message_hash
HexBytes('0x0d52783c4cbad7ebaf7eb943fc648f5282a52070442fc18d8dd16ddb2fcbaf66')
>>> signature = '0x29887fe718fcc6e64b97d681f80e6fd485883a45ec0dbc0e35a3752acf1065655d73c9034cac3df0dc82da015abe42367f5e90fd499d872b19610a3ea9c176921b'
>>> w3.eth.account.recoverHash(message_hash, signature=signature)
'0x6F4630e882c48151D9e4E386F95009b6312717f4'

Note that the message_hash in both examples are the same, however recoverHash does not result in the correct Ethereum address.

I have used these two sources to try and help me debug the issue to no success:

How to properly sign a transction to be used by ecrecover?

Verifying personal.sign signature with pyethereum

Best Answer

This is what ended up working:

async function create_signature(message, accounts) {
    var hex = ''
    for(var i=0;i<message.length;i++) {
        hex += ''+message.charCodeAt(i).toString(16)
    }
    var hexMessage = "0x" + hex
    var signature = web3.eth.personal.sign(hexMessage, accounts[0])
    return signature
}

And on the Python side, we recovered the address like this:

def recover_address(message, signature):
    message_hash = defunct_hash_message(text=message)
    address = w3.eth.account.recoverHash(message_hash, signature=signature)
    return address

If anyone knows a better way to calculate the hexMessage in the JavaScript code, please respond with a comment!

Related Topic