0

I have this transaction:

{
  "blockHash": "0x163ad564b32bf17db9262391c2c9a5f191e4fd0b098ae5ce9d2e3e7dcde4bd70",
  "blockNumber": "0x2",
  "from": "0x55d40a83b8445c004df5964ce4a0e261b599c01a",
  "gas": "0x76c0",
  "gasPrice": "0x9184e72a000",
  "hash": "0x5e97c5377da7864e5b82784c9e5335a2e075adfec3b075f5f2e5705733aacf8b",
  "input": "0x",
  "nonce": "0x8",
  "to": "0x589724c5abf2bce219726477cf0a60fa09321380",
  "transactionIndex": "0x0",
  "value": "0x1",
  "v": "0x1c",
  "r": "0xfe084488847df1cf427f72784c4b1ba86526ed5f8ef0feb6bc51caf450d66e8b",
  "s": "0x6226e5f4dd0d948b7014199faf018c27862c56faad0b49197057816dee9a7fa8"
}

So I made two files from the data of the transaction above: msg (transaction hash) & sig (r + s + v-27).

[root .eth]# hexdump -C msg
00000000  5e 97 c5 37 7d a7 86 4e  5b 82 78 4c 9e 53 35 a2  |^..7}..N[.xL.S5.|
00000010  e0 75 ad fe c3 b0 75 f5  f2 e5 70 57 33 aa cf 8b  |.u....u...pW3...|
00000020
[root .eth]# hexdump -C sig
00000000  fe 08 44 88 84 7d f1 cf  42 7f 72 78 4c 4b 1b a8  |..D..}..B.rxLK..|
00000010  65 26 ed 5f 8e f0 fe b6  bc 51 ca f4 50 d6 6e 8b  |e&._.....Q..P.n.|
00000020  62 26 e5 f4 dd 0d 94 8b  70 14 19 9f af 01 8c 27  |b&......p......'|
00000030  86 2c 56 fa ad 0b 49 19  70 57 81 6d ee 9a 7f a8  |.,V...I.pW.m....|
00000040  01                                                |.|
00000041

Then I wrote a program in go to recover the public key:

[root@v48807 .eth]# cat recover-pk.go
package main

import (
  "io/ioutil"
  "fmt"
  "os"

        secp256k1 "github.com/ethereum/go-ethereum/crypto/secp256k1"
)

func check(e error) {
    if e != nil {
        panic(e)
    }
}

func main() {
        msg, err := ioutil.ReadFile("msg")
  check(err)

        sig, err := ioutil.ReadFile("sig")
  check(err)

  pkbin, err := secp256k1.RecoverPubkey(msg, sig)
  check(err)

        f, err := os.Create("pkbin")
  check(err)
  defer f.Close()
        n, err := f.Write(pkbin)
  check(err)
  fmt.Printf("wrote %d bytes\n", n)
}

Here is a dump of the resulting public key:

[root .eth]# hexdump -C pkbin
00000000  04 bc 63 e4 84 c2 ed 68  56 8d 20 74 b0 ff 2e a1  |..c....hV. t....|
00000010  b0 51 02 3d d9 c8 f2 4c  c0 c2 5d 93 f4 14 2b bc  |.Q.=...L..]...+.|
00000020  40 56 d9 4b 32 dc 1e 65  74 6b c7 0a 3e fe 2a ba  |@V.K2..etk..>.*.|
00000030  db d2 e3 74 d8 ad 9c fd  d1 0c f1 1b 12 74 ef df  |...t.........t..|
00000040  53                                                |S|
00000041

The problem is that this public key is a different from that that I generated in the first place:

[root .eth]# cat addr1/address
55d40a83b8445c004df5964ce4a0e261b599c01a
[root .eth]# hexdump -C addr1/pubo-bin
00000000  04 0c 2d 16 2c 3d 76 cd  47 de e5 84 c9 9e 08 80  |..-.,=v.G.......|
00000010  b4 f2 2a 38 3b 7e bc bb  f6 cc bb 25 4a fe 01 b6  |..*8;~.....%J...|
00000020  dd 37 de ee ee b1 06 9a  af 39 f0 e8 c4 6a f7 ca  |.7.......9...j..|
00000030  53 01 5f 8f 73 7e 57 cc  2b 7a 61 32 35 54 e7 9c  |S._.s~W.+za25T..|
00000040  26                                                |&|
00000041

As you can see, the ethereum address (file address) matches the one from was used to send the ether in the transaction in the beginning of the post.

I generated the keypair like this:

[root .eth]# cat genkey.sh
#!/usr/bin/env bash
openssl ecparam -name secp256k1 -genkey -noout | openssl ec -text -noout > keypair
cat keypair | grep pub -A 5 | tail -n +2 | tr -d '\n[:space:]:' | sed 's/^04//' > pub
cat keypair | grep priv -A 3 | tail -n +2 | tr -d '\n[:space:]:' | sed 's/^00//' > priv
cat pub | keccak-256sum -x -l | tr -d ' -' | tail -c 41 > address
cat priv | xxd -r -p > priv-bin
cat pub | xxd -r -p > pub-bin
#geth account import priv

So what might be the problem? Why the recovered public key doesn't match the original public key?

3

1 Answer 1

2

You are using wrong hash when recovering public key. You hashed the whole transaction including the signature, but this does not make much sense: hash that ought be signed cannot depend on the signature. You need to hash only those parts of the transaction that were known before the signing: "to", "value", "data", "nonce", "gas", and "gas price" (EIP-155 added "chain ID" to the list). Here is how these six values look in RLP encoding:

// ["0x08","0x09184e72a000","0x76c0","0x589724c5abf2bce219726477cf0a60fa09321380","0x01","0x"]
0xe2088609184e72a0008276c094589724c5abf2bce219726477cf0a60fa093213800180

Here is the hash of the above to be singed:

0x7eb00f90181255e010b43c944da6f9c7575e595467a710c0925263921ead9107

Here is your raw transaction with signature:

0xf865088609184e72a0008276c094589724c5abf2bce219726477cf0a60fa0932
  138001801ca0fe084488847df1cf427f72784c4b1ba86526ed5f8ef0feb6bc51
  caf450d66e8ba06226e5f4dd0d948b7014199faf018c27862c56faad0b491970
  57816dee9a7fa8

Here is the signature alone:

0xfe084488847df1cf427f72784c4b1ba86526ed5f8ef0feb6bc51caf450d66e8b
  6226e5f4dd0d948b7014199faf018c27862c56faad0b49197057816dee9a7fa8
  1c

And here is public key obtained from the signature and proper hash:

0x040c2d162c3d76cd47dee584c99e0880b4f22a383b7ebcbbf6ccbb254afe01b6
  dd37deeeeeb1069aaf39f0e8c46af7ca53015f8f737e57cc2b7a61323554e79c
  26

BTW, I used ABDK Toolkit to make all these calculations.

This site is temporarily in read-only mode and not accepting new answers.

Not the answer you're looking for? Browse other questions tagged .