ethereumjs / ethereumjs-util

Project is in active development and has been moved to the EthereumJS monorepo.
https://github.com/ethereumjs/ethereumjs-monorepo
Mozilla Public License 2.0
608 stars 274 forks source link

Validate input/output against of ecsign/ecrecover in line with the Yellowpaper #20

Closed axic closed 8 years ago

axic commented 8 years ago

In Appendix F:

We declare that a signature is invalid unless the following is true: 0 < r < secp256k1n ∧ 0 < s < secp256k1n ∧ v ∈ {27, 28}

wanderer commented 8 years ago

that should be caught by seckp256k1's verify I believe

axic commented 8 years ago

@wanderer r & s should I reckon, but v has a limitation set by the yellowpaper (the valid range should be 27 to 30 according to it)

wanderer commented 8 years ago

We always subtract 27 from seckp so we can think of v as 0 or 1 but v is valid if its 0, 1, 2 or 3 in seckp256k1. I wonder if this is a mistake in the YP.

croqaz commented 8 years ago

Hei guys, I have 1 question:

How can I simulate ecrecover function in Solidity? I know the function exists, but it doesn't seem to return the same result as your ecrecover.

Node example:

var ethUtils = require('ethereumjs-util');
var privkey = new Buffer('3c9229289a6125f7fdf1885a77bb12c37a8d3b4962d936f7e3084dece32a3ca1', 'hex');
var data = ethUtils.sha3('a');
var vrs = ethUtils.ecsign(data, privkey);
var pubkey = ethUtils.ecrecover(data, vrs.v, vrs.r, vrs.s);
// Check !
var check1 = pubkey.toString('hex') ==
    ethUtils.privateToPublic(privkey).toString('hex');
var check2 = ethUtils.publicToAddress(pubkey).toString('hex') ==
    ethUtils.privateToAddress(privkey).toString('hex');
// Check is ok !

Now, I'm trying this in Solidity:

// Sending ::
// "3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb",
// 27
// "5caec23c6aa80c772fef1a52655cbb46ed5e017573b054ba8d3fa61d9d26df98",
// "48a8a544478726b4b2140b444831c2f0bbd97c819e1344482190c2ad265865ca"
contract Test {
    function check(bytes32 data, uint8 v, bytes32 r, bytes32 s) returns(address) {
      return ecrecover(data, v, r, s);
    }
}
// Result: "0x0000000000000000000000003432313261323563316330316664333562656266"

Any ideas how I can compare the result? Also, the private key that I used, is from your tests; How can I obtain it from the keyfile, or from GETH ?

Thank you !!

axic commented 8 years ago

@croqaz Solidity's ecrecover returns an address and not a public key.

Re: the private keys. You can use ethereumjs-wallet (or probably keythereum supports that too?) to convert back-and-forth between keyfiles and private keys.

axic commented 8 years ago

With https://github.com/ethereumjs/ethereumjs-util/pull/27 merged we check for v = {27,28}