[Ethereum] How does one properly use ecrecover to verify Ethereum signatures

dappleecrecoversignaturesolidity

I've been searching to figure out what I'm doing wrong here, but I've had no luck yet. As far as I can tell, I'm using ecrecover correctly, but I can't seem to get back the signing Ethereum address.

Using a geth session, I've created and signed a hash, retrieving the r, v, and s values per the Javascript API:

> var foobar = web3.sha3('foobar')
undefined
> foobar
"38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e"
> var foo = eth.sign('0x803c84d8b64be30554e2edb9c61b50bc78a7231f', foobar).slice(2)
undefined
> var r = foo.slice(0, 64); var s = foo.slice(64, 128); var v = foo.slice(128);
> v
"00"
> r
"723841761d213b60ac1cbf063207cbeba6c2725bcaf7c189e63f13d93fc1dc07"
> s
"789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02"

I've then translated those values into a Solidity test:

import 'dapple/test.sol';

contract ECRecoverTest is Test {
  function testRecovery() {
    bytes32 foobar = 0x38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e;
    uint8 v = 0x00;
    bytes32 r = 0x723841761d213b60ac1cbf063207cbeba6c2725bcaf7c189e63f13d93fc1dc07;
    bytes32 s = 0x789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02;

    log_address(ecrecover(foobar, v, r, s));
  }
}

I expect to see my signing address (0x803c84d8b64be30554e2edb9c61b50bc78a7231f) getting logged, but all I see coming out of it is:

$ dapple test
Testing...
Using local solc installation...

ECRecoverTest
  test recovery
  LOG:  log_address
  LOG:    val: 0xb62f18e17054f66a817bd4295423adf9ed98873e
  Passed!

I've also tried converting the hash to ASCII before signing it and also prefixing the hex with "0x" just in case the issue was due to the eth.sign function not grokking that the data was to be treated as a hex value.

Any ideas? I've already looked at the test case in pyethereum to make sure I'm using it correctly, and I've seen the other question on this StackExchange. Just don't seem to be having much success, though.

Best Answer

I'm not sure if this is your only problem but at the very least, the v you're getting is wrong - it should be 27 or 28. Unfortunately a lot of signature functions won't give it to you, but you can just try both and see which one gives you the right address. No need to use hex for "v" - just literally feed it 27 or 28 as an int.

The other bit of trickiness that confused me for a while is that if you're going to hash bytes when you make the hash to pass to ecrecover, you have to make sure you were hashing bytes when you signed as well. I'm not sure if you're getting that right or not.

There's an example here if that helps: https://github.com/edmundedgar/realitykeys-examples-ethereum/tree/master/sponsor