15

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. – max taldykin May 13 '17 at 11:42
  • @maxtaldykin pastebin.com/v2ydwkgy this is what I got – Joe May 15 '17 at 10:58
  • @maxtaldykin I am using macOS sierra version 10.12.4 not sure where to find the testrpc version – Joe May 16 '17 at 9:14
  • @maxtaldykin I got an error imgur.com/a/JTyU4 – Joe May 16 '17 at 9:29
9
+50

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 '17 at 9:35
  • 2
    It worked! Thank you so much I've been struggling with this for ages – Joe May 16 '17 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 '17 at 12:07
  • never mind its answered here ethereum.stackexchange.com/questions/2045/… – Joe May 16 '17 at 12:08
  • How on earth did you find this?! I've been looking forever. – Justin Thomas Nov 16 '17 at 4:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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