Skip to content
This repository has been archived by the owner on Nov 30, 2021. It is now read-only.

keys: fix privkey derivation #554

Merged
merged 3 commits into from
Sep 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Bug fixes

* (app/ante) [\#550](https://github.com/ChainSafe/ethermint/pull/550) Update ante handler nonce verification to accept any nonce greater than or equal to the expected nonce to allow to successive transactions.
* (keys) [\#554](https://github.com/ChainSafe/ethermint/pull/554) Fix private key derivation.
* (app/ante) [\#550](https://github.com/ChainSafe/ethermint/pull/550) Update ante handler nonce verification to accept any nonce greater than or equal to the expected nonce to allow to successive transactions.

## [v0.2.0] - 2020-09-24

Expand Down
32 changes: 21 additions & 11 deletions crypto/algorithm.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import (

"github.com/pkg/errors"

"crypto/hmac"
"crypto/sha512"

"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcutil/hdkeychain"
"github.com/tyler-smith/go-bip39"

ethaccounts "github.com/ethereum/go-ethereum/accounts"
ethcrypto "github.com/ethereum/go-ethereum/crypto"

tmcrypto "github.com/tendermint/tendermint/crypto"
Expand Down Expand Up @@ -58,27 +58,37 @@ func EthermintKeygenFunc(bz []byte, algo keys.SigningAlgo) (tmcrypto.PrivKey, er
return PrivKeySecp256k1(bz), nil
}

func DeriveSecp256k1(mnemonic, bip39Passphrase, _ string) ([]byte, error) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hdpath wasn't being used to derive the key

// DeriveSecp256k1 derives and returns the eth_secp256k1 private key for the given mnemonic and HD path.
func DeriveSecp256k1(mnemonic, bip39Passphrase, path string) ([]byte, error) {
hdpath, err := ethaccounts.ParseDerivationPath(path)
if err != nil {
return nil, err
}

seed, err := bip39.NewSeedWithErrorChecking(mnemonic, bip39Passphrase)
if err != nil {
return nil, err
}

// HMAC the seed to produce the private key and chain code
mac := hmac.New(sha512.New, []byte("Bitcoin seed"))
_, err = mac.Write(seed)
masterKey, err := hdkeychain.NewMaster(seed, &chaincfg.MainNetParams)
if err != nil {
return nil, err
}

seed = mac.Sum(nil)
key := masterKey
for _, n := range hdpath {
key, err = key.Child(n)
if err != nil {
return nil, err
}
}

priv, err := ethcrypto.ToECDSA(seed[:32])
privateKey, err := key.ECPrivKey()
if err != nil {
return nil, err
}

derivedKey := PrivKeySecp256k1(ethcrypto.FromECDSA(priv))

privateKeyECDSA := privateKey.ToECDSA()
derivedKey := PrivKeySecp256k1(ethcrypto.FromECDSA(privateKeyECDSA))
return derivedKey, nil
}
34 changes: 29 additions & 5 deletions crypto/algorithm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@ import (

"github.com/stretchr/testify/require"

"github.com/ethereum/go-ethereum/common"
ethcrypto "github.com/ethereum/go-ethereum/crypto"

hdwallet "github.com/miguelmota/go-ethereum-hdwallet"

"github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
"github.com/cosmos/cosmos-sdk/tests"
sdk "github.com/cosmos/cosmos-sdk/types"

ethermint "github.com/cosmos/ethermint/types"
)

func TestEthermintKeygenFunc(t *testing.T) {
Expand Down Expand Up @@ -75,25 +79,45 @@ func TestKeyring(t *testing.T) {
require.Nil(t, info)

mockIn.Reset("password\npassword\n")
info, mnemonic, err := kr.CreateMnemonic("foo", keys.English, sdk.FullFundraiserPath, EthSecp256k1)
info, mnemonic, err := kr.CreateMnemonic("foo", keys.English, ethermint.BIP44HDPath, EthSecp256k1)
require.NoError(t, err)
require.NotEmpty(t, mnemonic)
require.Equal(t, "foo", info.GetName())
require.Equal(t, "local", info.GetType().String())
require.Equal(t, EthSecp256k1, info.GetAlgo())

params := *hd.NewFundraiserParams(0, sdk.CoinType, 0)
params := *hd.NewFundraiserParams(0, ethermint.Bip44CoinType, 0)
hdPath := params.String()

bz, err := DeriveKey(mnemonic, keys.DefaultBIP39Passphrase, hdPath, EthSecp256k1)
bz, err := DeriveKey(mnemonic, keys.DefaultBIP39Passphrase, hdPath, keys.Secp256k1)
require.NoError(t, err)
require.NotEmpty(t, bz)

bz, err = DeriveKey(mnemonic, keys.DefaultBIP39Passphrase, hdPath, keys.Secp256k1)
bz, err = DeriveSecp256k1(mnemonic, keys.DefaultBIP39Passphrase, hdPath)
require.NoError(t, err)
require.NotEmpty(t, bz)

bz, err = DeriveKey(mnemonic, keys.DefaultBIP39Passphrase, hdPath, keys.SigningAlgo(""))
require.Error(t, err)
require.Empty(t, bz)

bz, err = DeriveSecp256k1(mnemonic, keys.DefaultBIP39Passphrase, "/wrong/hdPath")
require.Error(t, err)
require.Empty(t, bz)

bz, err = DeriveKey(mnemonic, keys.DefaultBIP39Passphrase, hdPath, EthSecp256k1)
require.NoError(t, err)
require.NotEmpty(t, bz)

privkey := PrivKeySecp256k1(bz)
addr := common.BytesToAddress(privkey.PubKey().Address().Bytes())

wallet, err := hdwallet.NewFromMnemonic(mnemonic)
require.NoError(t, err)

path := hdwallet.MustParseDerivationPath(hdPath)

account, err := wallet.Derive(path, false)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used this library to test the correctness with ethereum

require.NoError(t, err)
require.Equal(t, addr.String(), account.Address.String())
}
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ module github.com/cosmos/ethermint
go 1.14

require (
github.com/allegro/bigcache v1.2.1 // indirect
github.com/aristanetworks/goarista v0.0.0-20200331225509-2cc472e8fbd6 // indirect
github.com/btcsuite/btcd v0.20.1-beta
github.com/btcsuite/btcutil v1.0.2
github.com/cespare/cp v1.1.1 // indirect
github.com/cosmos/cosmos-sdk v0.39.1
github.com/deckarep/golang-set v1.7.1 // indirect
Expand All @@ -13,9 +14,9 @@ require (
github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.4.2
github.com/mattn/go-colorable v0.1.7 // indirect
github.com/miguelmota/go-ethereum-hdwallet v0.0.0-20200123000308-a60dcd172b4c
github.com/pkg/errors v0.9.1
github.com/prometheus/tsdb v0.9.1 // indirect
github.com/rjeczalik/notify v0.9.2 // indirect
github.com/spf13/afero v1.2.2 // indirect
github.com/spf13/cobra v1.0.0
github.com/spf13/viper v1.7.1
Expand Down
Loading