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?
Best Answer
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:
Here is the hash of the above to be singed:
Here is your raw transaction with signature:
Here is the signature alone:
And here is public key obtained from the signature and proper hash:
BTW, I used ABDK Toolkit to make all these calculations.