I'm trying to understand Ethereum transaction signing, but for some reason I'm unable to verify the signature.

I have a test account, 0xb2c899884790aa9e256a2d4b2256ca3319e64e32, its public key is e7ab22c376286ccb0616888217bc41ec31eafb090fb77900a3946e39eb5c7fa374c8d5fe191f8001d287e678567bc8058eb49729780d2ac9090ffccbc506a754

I take the following valid transaction:

  "blockHash": "0x3deebc8e1fe36af7f1268ff077cc086c0653fe6fd67aa200608a7379390365f0",
  "blockNumber": "0x613",
  "from": "0xb2c899884790aa9e256a2d4b2256ca3319e64e32",
  "gas": "0x493e0",
  "gasPrice": "0x0",
  "hash": "0x6831112de9dc553de7bb111591cabe0c79b5af8c6395c1bc5411ca2fda539735",
  "input": "0x760a8c2a",
  "nonce": "0x5",
  "to": "0x78c215f61ed07929e0084233a3e86bc011bea132",
  "transactionIndex": "0x0",
  "value": "0x0",
  "v": "0x14c3",
  "r": "0xbddab1b3292ac1102c470d738640bbf91a56a9bbc99a6fc88250800b2b21e25b",
  "s": "0x1959b4b59d0c8552766294459912862a2ca8a62e0b64eab98a4b5be75e910cec"

Or in raw form: f8660580830493e09478c215f61ed07929e0084233a3e86bc011bea1328084760a8c2a8214c3a0bddab1b3292ac1102c470d738640bbf91a56a9bbc99a6fc88250800b2b21e25ba01959b4b59d0c8552766294459912862a2ca8a62e0b64eab98a4b5be75e910cec

According to EIP 155, I need to hash all 9 values, replacing v=chainId (2640), r=0 and s=0. So I come up with the following "signing data":


It's "signing hash" is:


Which, when fed through ecrecover, gives the following public key:


Which obviously does not match the actual public key.

What am I doing wrong?

My test code:

var ethutil = require('ethereumjs-util');
var raw = Buffer.from('f8660580830493e09478c215f61ed07929e0084233a3e86bc011bea1328084760a8c2a8214c3a0bddab1b3292ac1102c470d738640bbf91a56a9bbc99a6fc88250800b2b21e25ba01959b4b59d0c8552766294459912862a2ca8a62e0b64eab98a4b5be75e910cec','hex');
var data = ethutil.rlp.decode(raw);
var v = ethutil.bufferToInt(data[6]);
var r = data[7];
var s = data[8];
var chainId = Math.floor((v - 35) / 2);
data[6] = ethutil.intToBuffer(chainId);
data[7] = Buffer.from('');
data[8] = Buffer.from('');
var msg = ethutil.rlp.encode(data);
var msgHash = ethutil.sha3(msg);
var publicKey = ethutil.ecrecover(msgHash, (v & 1) + 27, r, s);

Try replacing the 2nd to last line with:

var publicKey = ethutil.ecrecover(msgHash, (v & 1 ^ 1) + 27, r, s);

Most of your code looks correct to me but the parity of the 2nd argument to ecrecover must be the same as the parity of the v value. So if the v value starts with the value 27, you can go through your calculation and check that your code would set the 2nd argument to 28. That is wrong, and it can be fixed by xoring the value with 1.

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.