[Ethereum] Sign message with Metamask and verify with ethereumjs-utils

ethereumjsmetamask

Client side:

web3.eth.sign(address, hash); // generates signature

Server side:

const ethutils = require('ethereumjs-util');

const extractAddress = function(signature, hash){ //signature and hash from the client side
  const o = ethutils.fromRpcSig(signature);
  const hashBuffer = ethutils.toBuffer(hash);
  const publicKeyBuffer = ethutils.ecrecover(hashBuffer, o.v, o.r, o.s);
  const publicKeyHex = ethutils.bufferToHex(publicKeyBuffer);
  const addressBuffer = ethutils.pubToAddress(publicKeyHex);
  const addressHex = ethutils.bufferToHex(addressBuffer);
  return addressHex;
}

Addresses don't match. The code worked before (a couple of months ago).

Relevant discussions https://github.com/ethereumjs/ethereumjs-util/pull/67

Best Answer

Old issue, but this worked for me. I'm using web3@0.20.3.

1. With personal_sign (recommended)

Client side:

web3.personal.sign(web3.fromUtf8("dinosaur"), web3.eth.coinbase, console.log);

Server side:

const msg = 'dinosaur';

const msgBuffer = ethereumJsUtil.toBuffer(msg);
const msgHash = ethereumJsUtil.hashPersonalMessage(msgBuffer);
const signatureBuffer = ethereumJsUtil.toBuffer(signature);
const signatureParams = ethereumJsUtil.fromRpcSig(signatureBuffer);
const publicKey = ethereumJsUtil.ecrecover(
  msgHash,
  signatureParams.v,
  signatureParams.r,
  signatureParams.s
);
const addressBuffer = ethereumJsUtil.publicToAddress(publicKey);
const address = ethereumJsUtil.bufferToHex(addressBuffer);

console.log(address); // Prints my initial web3.eth.coinbase

2. With eth_sign

Client side:

web3.eth.sign(web3.eth.coinbase, web3.sha3("dinosaur"), console.log);

Server side:

const msg = 'dinosaur';

const msgHash = ethereumJsUtil.sha3(msg);
// The rest is the same as above
const signatureBuffer = ethereumJsUtil.toBuffer(signature);
const signatureParams = ethereumJsUtil.fromRpcSig(signatureBuffer);
const publicKey = ethereumJsUtil.ecrecover(
  msgHash,
  signatureParams.v,
  signatureParams.r,
  signatureParams.s
);
const addressBuffer = ethereumJsUtil.publicToAddress(publicKey);
const address = ethereumJsUtil.bufferToHex(addressBuffer);

console.log(address); // Prints my initial web3.eth.coinbase
Related Topic