9

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.

4

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

  • I just used hex for v here for clarity. Wanted to demonstrate that it was indeed coming straight from the signature. Still not sure what the issue is, so I'm updating my copy of geth just in case my troubles stem from a bug in the older, built-from-a-Github-commit copy I'm running – ryepdx Mar 19 '16 at 7:34
  • The lack of a "v" is probably just the way it works - for example, the standard DER encoding appears to just encode the r and s points, and throw away the "v". Like I say, just try them both. – Edmund Edgar Mar 19 '16 at 10:21
4

This gist is a good example how to use ecrecover. It uses assembly to filter out the r,s,v parts of a signature and fills it into the ecrecover function.

assembly {
            r := mload(add(sig, 32))
            s := mload(add(sig, 64))
            // Here we are loading the last 32 bytes, including 31 bytes
            // of 's'. There is no 'mload8' to do this.
            //
            // 'byte' is not working due to the Solidity parser, so lets
            // use the second best option, 'and'
            v := and(mload(add(sig, 65)), 255)
        }

Note also the v 27, 28 part that Edmund mentioned

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.