3

So, for my studies, I am supposed to interact with a contract function that has the following built in condition:

if (ecrecover(_h, _v, _r, _s) == msg.sender && _h == sha3(this))

I am supposed to provide _h, _v, _r and _s via contract transaction so that the statement equals true.

Our uni has a test server node which we can connect to via mist --rpc and we can also open a web3 provider via http to that node.

I know how to sign messages in web3 and how to extract r, s and v so that ecrecover returns my address. But I can only get the right signature if I use the ethereum signature prefix and thus the condition _h == sha3(this) will always fail. I don't know what to do. I've been trying to somehow access my private key so I can use ethereumjs-util to sign the message but I can't get it.

How can I get a signature with my testnet address that doesn't automatically add the prefix??!

jeff
  • 2,550
  • 2
  • 18
  • 40
Suzuko
  • 31
  • 2

1 Answers1

3

From Web3 JavaScript-API docs:

After the hex prefix, characters correspond to ECDSA values like this:

r = signature[0:64]
s = signature[64:128]
v = signature[128:130]

Note that if you are using ecrecover, v will be either "00" or "01". As a result, in order to use this value, you will have to parse it to an integer and then add 27. This will result in either a 27 or a 28.

Here's a working example I tested out using truffle:

Example.sol

pragma solidity ^0.4.0;

contract Example {
    function testRecovery(bytes32 h, uint8 v, bytes32 r, bytes32 s) returns (address) { 
        /* prefix might be needed for geth only
         * https://github.com/ethereum/go-ethereum/issues/3731
         */
        // bytes memory prefix = "\x19Ethereum Signed Message:\n32";
        // h = sha3(prefix, h);

        address addr = ecrecover(h, v, r, s);

        return addr;
    }
}

example.js (test)

var Example = artifacts.require('./Example.sol')

var Web3 = require('web3')
var web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'))

contract('Example', (accounts) => {
  var address = accounts[0]

  it('ecrecover result matches address', async function() {
    var instance = await Example.deployed()
    var contractAddress = instance.address

    var h = web3.sha3(contractAddress)
    var sig = web3.eth.sign(address, h).slice(2)
    var r = `0x${sig.slice(0, 64)}`
    var s = `0x${sig.slice(64, 128)}`
    var v = web3.toDecimal(sig.slice(128, 130)) + 27

    var result = await instance.testRecovery.call(h, v, r, s)
    assert.equal(result, address)
  })
})

Running test:

$ truffle test

Using network 'development'.

Compiling ./contracts/Example.sol...


  Contract: Example
    ✓ ecrecover result matches address (132ms)


  1 passing (147ms)

Related

Miguel Mota
  • 5,143
  • 29
  • 47