1

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":

e60580830493e09478c215f61ed07929e0084233a3e86bc011bea1328084760a8c2a820a508080

It's "signing hash" is:

749a36ed5f7c67b1f5eb83a46b0dd6447e9ac050a3f469354fcc4691781a385c

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

f1308d673d1cf8014370fffb43f36d5e866e405b2b5cecb3025bfb98ae47b18e21fa07c66b31423414c38611038c4c35387db8510757f65b7a632a2d48b0276e

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);
console.log(msg.toString('hex'));
var msgHash = ethutil.sha3(msg);
console.log(msgHash.toString('hex'));
var publicKey = ethutil.ecrecover(msgHash, (v & 1) + 27, r, s);
console.log(publicKey.toString('hex'));
1

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.