Skip to content

Commit

Permalink
handle Ethereum signature recovery id (#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
dustinxie authored May 23, 2020
1 parent d7743d1 commit 5f1d9dd
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 2 deletions.
21 changes: 19 additions & 2 deletions crypto/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,26 @@ func KeystoreToPrivateKey(account accounts.Account, password string) (PrivateKey

// RecoverPubkey recovers the public key from signature
func RecoverPubkey(msg, sig []byte) (PublicKey, error) {
if pk, err := secp256k1.RecoverPubkey(msg, sig); err == nil {
return newSecp256k1PubKeyFromBytes(pk)
if pk, err := recoverSecp256k1(msg, sig); err == nil {
return pk, nil
}
// TODO: implement recover key for sm2
return nil, ErrInvalidKey
}

func recoverSecp256k1(msg, sig []byte) (PublicKey, error) {
if len(sig) >= secp256pubKeyLength && sig[secp256pubKeyLength-1] >= 27 {
// when an Ethereum signature is calculated, 27 is added to recovery id
// https://github.com/ethereum/go-ethereum/commit/b59c8399fbe42390a3d41e945d03b1f21c1a9b8d#diff-31c4aa3a4249d4755fc652d3e0087b98R226-R232
sig[secp256pubKeyLength-1] -= 27
defer func() {
sig[secp256pubKeyLength-1] += 27
}()
}

pk, err := secp256k1.RecoverPubkey(msg, sig)
if err != nil {
return nil, err
}
return newSecp256k1PubKeyFromBytes(pk)
}
11 changes: 11 additions & 0 deletions crypto/secp256k1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package crypto

import (
"crypto/ecdsa"
"encoding/hex"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -57,4 +58,14 @@ func TestSecp256k1(t *testing.T) {

sig[secp256pubKeyLength-1] = 2
require.False(pk.Verify(h[:], sig))

// test Ethereum signature with recovery id >= 27
ha, _ := hex.DecodeString("f93a97fae37fdadab6d49b74e3f3e4bee707ea2f007e08007bcc356cb283665b")
sig, _ = hex.DecodeString("5595906a47dfc107a78cc48b500f89ab2dec545ba86578295aed4a260ce9a98b335924e86f683832e313f1a5dda7826d9b59caf40dd22ce92716420a367dfaec1c")
require.EqualValues(28, sig[secp256pubKeyLength-1])
pk, err = RecoverPubkey(ha, sig)
require.NoError(err)
require.EqualValues(28, sig[secp256pubKeyLength-1])
require.Equal("53fbc28faf9a52dfe5f591948a23189e900381b5", hex.EncodeToString(pk.Hash()))

}

0 comments on commit 5f1d9dd

Please sign in to comment.