When I sign a string using the following code I get back a different address to the one I signed with. The address returned is different for different strings.

const util = require('ethereumjs-util')
const msg = web3.sha3('hello!');
const sig = web3.eth.sign(web3.eth.accounts[0], msg);
const {v, r, s} = util.fromRpcSig(sig);

const pubKey  = util.ecrecover(util.toBuffer(msg), v, r, s);
const addrBuf = util.pubToAddress(pubKey);
const addr    = util.bufferToHex(addrBuf);

I took the code from the answer to a question I asked previously here Getting an address from ethereumjs-utils erecover.

I asked a question here: Secp256k1 bindings are not compiled. Pure JS implementation will be used about a possibly relevant error. The comments suggested that it should be harmless though.

  • Can you please post exact versions of the packages you use (npm list). I think there were a bug in some of the testrpc dependencies. May 13, 2017 at 11:42
  • @maxtaldykin pastebin.com/v2ydwkgy this is what I got
    – Joe
    May 15, 2017 at 10:58
  • @maxtaldykin I am using macOS sierra version 10.12.4 not sure where to find the testrpc version
    – Joe
    May 16, 2017 at 9:14
  • @maxtaldykin I got an error imgur.com/a/JTyU4
    – Joe
    May 16, 2017 at 9:29

1 Answer 1


Geth adds prefix to the message before siginig it in web3.eth.sign (see JSON-PRC spec). Without this it can be possible to trick user to sign transaction (more here).

So, the correct code to sign message with web3.eth.sign and recover address with ethereumjs-util.ecrecover or (Solidity's ecrecover) should add the prefix explicitly.

const util = require('ethereumjs-util')

const msg = new Buffer('hello');
const sig = web3.eth.sign(web3.eth.accounts[0], '0x' + msg.toString('hex'));
const res = util.fromRpcSig(sig);

const prefix = new Buffer("\x19Ethereum Signed Message:\n");
const prefixedMsg = util.sha3(
  Buffer.concat([prefix, new Buffer(String(msg.length)), msg])

const pubKey  = util.ecrecover(prefixedMsg, res.v, res.r, res.s);
const addrBuf = util.pubToAddress(pubKey);
const addr    = util.bufferToHex(addrBuf);

console.log(web3.eth.accounts[0],  addr);

There is misleading inconsistency with ethereumjs-testrpc as it does not prefix message before signing it in web3.eth.sign.

  • It seems meteor will only allow node versions of 4.x
    – Joe
    Mar 3, 2017 at 9:35
  • 2
    It worked! Thank you so much I've been struggling with this for ages
    – Joe
    May 16, 2017 at 11:55
  • sorry just a small thing... the ecrecover address is all lower case but the original address has some caps. Does this make a difference?
    – Joe
    May 16, 2017 at 12:07
  • never mind its answered here ethereum.stackexchange.com/questions/2045/…
    – Joe
    May 16, 2017 at 12:08
  • How on earth did you find this?! I've been looking forever. Nov 16, 2017 at 4:23

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.