Ethereum Signature Verification – Why Signature Is Not Matching?

cryptographyecrecoverprivate-keysignature

What I want to achieve is sign a message and then verify the signature whether verified by same address or not.

Contract to Invoke ecrecover method to verify the address

contract MyAuth {      
    function verify( bytes32 hash, uint8 v, bytes32 r, bytes32 s) 
        constant returns(address returnAddress) {
        returnAddress = ecrecover(hash, v, r, s);
    }
}

Java Script Code

var cMyAuthAddress="0x09343c5EBB988315E117E1Cd6EE501AF02412cFB"; // Contract address

var cMyAuthABI="<ABI data>"; // Contract ABI
var cDeployed=web3.eth.contract(JSON.parse(cMyAuthABI)).at(cMyAuthAddress);

var msg = web3.sha3('This my test data');

console.log('Message Hash: '+ msg); // Generated message hash
console.log("Account Used to Sign: "+ web3.eth.accounts[0]);
var state=web3.personal.unlockAccount(web3.eth.accounts[0], '<account password>', 1000); // Unlocking the account to perform the operation
console.log('Account State: '+ state);

var signature = web3.eth.sign(web3.eth.accounts[0], msg); // Signing the messge

console.log('Signature: '+ signature);

var r = signature.slice(0, 66)
var s = '0x' + signature.slice(66, 130)
var v = '0x' + signature.slice(130, 132)
v = web3.toDecimal(v);

console.log("V: "+ v);
console.log("R: "+ r);
console.log("S: "+ s);

if(v<27 || v>28){
    v+=27;
    console.log("Updated V: "+ v);
}

var finalAddress=cDeployed.verify.call(msg,v,r,s)

console.log("Final Address: "+ finalAddress);

Output

Message Hash:
0x1c6f4ab842fb95857783a0177eafb0133b3a626c89877a8bf4e2d07987aa1422
Account Used to Sign: 0x890bd380e472df5b8bab22075c6a5d4f0b84415c
Account State: true
Signature:
0xb8b01f46f147bd5e8f84343719ca7492164f80af5f60370c433e2e096ae52fec76d2bbe0e454b2a07e4100e8463d98286ec6e849cbcf6e24f66f7d579fc8654f1c
V: 28
R:
0xb8b01f46f147bd5e8f84343719ca7492164f80af5f60370c433e2e096ae52fec
S:
0x76d2bbe0e454b2a07e4100e8463d98286ec6e849cbcf6e24f66f7d579fc8654f
Decimal V: 28
Final Address: 0x0609b9fae476d8b844716e3a0a6a3b5b7a5a2cdf

You can clearly see the final address listed is not matching the one used to sign it the message.

Note: I am trying this on my private blockchain.

Question: Which step needs to be corrected to achieve the desired result (i.e. Final address should match to the Account address used to
sign in this case which is
0x890bd380e472df5b8bab22075c6a5d4f0b84415c)?

Tried using ethereumjs-util with the baove generated signature value but faced same result.

  var ethUtils = require('ethereumjs-util'); 
  let tSig = ethUtils.fromRpcSig(signature);
  let pubKey = ethUtils.ecrecover(
    ethUtils.sha3("This my test data"),
    tSig.v,
    tSig.r,
    tSig.s);
  let foundAddr = '0x' + ethUtils.pubToAddress(pubKey).toString('hex');
  console.log("Final Address 2: "+ finalAddress);

Output is Final Address 2: 0x0609b9fae476d8b844716e3a0a6a3b5b7a5a2cdf" (i.e. the same address)

Best Answer

You need to prefix the message with the string "\x19Ethereum Signed Message:\n" and the length of the message

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

And then use the prefixed string in ecrecover.

code taken from answer here https://ethereum.stackexchange.com/a/12684/