Skip to content

Commit

Permalink
bump SDK commit (cosmos#324)
Browse files Browse the repository at this point in the history
* bump SDK commit

* crypto: Secp256k1 algorithm

* crypto: fix codec and derivation issues

* lint
  • Loading branch information
fedekunze authored Jun 8, 2020
1 parent a745e66 commit 5614adc
Show file tree
Hide file tree
Showing 11 changed files with 323 additions and 53 deletions.
16 changes: 11 additions & 5 deletions cmd/emintcli/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/input"
"github.com/cosmos/cosmos-sdk/crypto"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"

Expand All @@ -33,7 +34,7 @@ func unsafeExportEthKeyCommand() *cobra.Command {
func runExportCmd(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())

kb, err := keyring.NewKeyring(
keystore, err := keyring.New(
sdk.KeyringServiceName(),
viper.GetString(flags.FlagKeyringBackend),
viper.GetString(flags.FlagHome),
Expand All @@ -54,22 +55,27 @@ func runExportCmd(cmd *cobra.Command, args []string) error {
case keyring.BackendOS:
conf, err = input.GetConfirmation(
"**WARNING** this is an unsafe way to export your unencrypted private key, are you sure?",
inBuf)
inBuf, cmd.ErrOrStderr())
}
if err != nil || !conf {
return err
}

// Exports private key from keybase using password
privKey, err := kb.ExportPrivateKeyObject(args[0], decryptPassword)
// Exports private key from keyring using password
armored, err := keystore.ExportPrivKeyArmor(args[0], decryptPassword)
if err != nil {
return err
}

privKey, _, err := crypto.UnarmorDecryptPrivKey(armored, decryptPassword)
if err != nil {
return err
}

// Converts key to Ethermint secp256 implementation
emintKey, ok := privKey.(emintcrypto.PrivKeySecp256k1)
if !ok {
return fmt.Errorf("invalid private key type, must be Ethereum key: %T", privKey)
return fmt.Errorf("invalid private key type %T, must be Ethereum key PrivKeySecp256k1", privKey)
}

// Formats key for output
Expand Down
21 changes: 8 additions & 13 deletions cmd/emintcli/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ import (
"bufio"
"io"

"github.com/tendermint/tendermint/crypto"

"github.com/cosmos/cosmos-sdk/client/flags"
clientkeys "github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"

emintCrypto "github.com/cosmos/ethermint/crypto"
ethermintcrypto "github.com/cosmos/ethermint/crypto"

"github.com/spf13/cobra"
"github.com/spf13/viper"
Expand Down Expand Up @@ -52,29 +50,26 @@ func keyCommands() *cobra.Command {
return cmd
}

func getKeybase(transient bool, buf io.Reader) (keyring.Keybase, error) {
func getKeyring(transient bool, buf io.Reader) (keyring.Keyring, error) {
if transient {
return keyring.NewInMemory(keyring.WithKeygenFunc(ethermintKeygenFunc)), nil
return keyring.NewInMemory(ethermintcrypto.EthSeckp256k1Option), nil
}

return keyring.NewKeyring(
return keyring.New(
sdk.KeyringServiceName(),
viper.GetString(flags.FlagKeyringBackend),
viper.GetString(flags.FlagHome),
buf,
keyring.WithKeygenFunc(ethermintKeygenFunc))
keyring.Option(ethermintcrypto.EthSeckp256k1Option),
)
}

func runAddCmd(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
kb, err := getKeybase(viper.GetBool(flagDryRun), inBuf)
keystore, err := getKeyring(viper.GetBool(flagDryRun), inBuf)
if err != nil {
return err
}

return clientkeys.RunAddCmd(cmd, args, kb, inBuf)
}

func ethermintKeygenFunc(bz []byte, algo keyring.SigningAlgo) (crypto.PrivKey, error) {
return emintCrypto.PrivKeySecp256k1(bz), nil
return clientkeys.RunAddCmd(cmd, args, keystore, inBuf)
}
12 changes: 6 additions & 6 deletions cmd/emintd/genaccounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,19 @@ func AddGenesisAccountCmd(
Short: "Add a genesis account to genesis.json",
Long: `Add a genesis account to genesis.json. The provided account must specify
the account address or key name and a list of initial coins. If a key name is given,
the address will be looked up in the local Keybase. The list of initial tokens must
the address will be looked up in the local Keyring. The list of initial tokens must
contain valid denominations. Accounts may optionally be supplied with vesting parameters.
`,
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
config := ctx.Config
config.SetRoot(viper.GetString(cli.HomeFlag))
inBuf := bufio.NewReader(cmd.InOrStdin())

addr, err := sdk.AccAddressFromBech32(args[0])
inBuf := bufio.NewReader(cmd.InOrStdin())
if err != nil {
// attempt to lookup address from Keybase if no address was provided
kb, err := keyring.NewKeyring(
// attempt to lookup address from keyring if no address was provided
keystore, err := keyring.New(
sdk.KeyringServiceName(),
viper.GetString(flags.FlagKeyringBackend),
viper.GetString(flagClientHome),
Expand All @@ -65,9 +65,9 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa
return err
}

info, err := kb.Get(args[0])
info, err := keystore.Key(args[0])
if err != nil {
return fmt.Errorf("failed to get address from Keybase: %w", err)
return fmt.Errorf("failed to get address from Keyring: %w", err)
}

addr = info.GetAddress()
Expand Down
71 changes: 71 additions & 0 deletions crypto/algorithm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package crypto

import (
"crypto/hmac"
"crypto/sha512"

"github.com/tyler-smith/go-bip39"

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

"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
tmcrypto "github.com/tendermint/tendermint/crypto"
)

// EthSecp256k1Type uses the Ethereum secp256k1 ECDSA parameters.
const EthSecp256k1Type = hd.PubKeyType("ethsecp256k1")

var _ keyring.SignatureAlgo = ethSecp256k1{}

// EthSeckp256k1Option defines a keyring option for the ethereum Secp256k1 curve.
func EthSeckp256k1Option(options *keyring.Options) {
options.SupportedAlgos = append(options.SupportedAlgos, Secp256k1)
options.SupportedAlgosLedger = append(options.SupportedAlgosLedger, Secp256k1)
}

// Secp256k1 represents the Secp256k1 curve used in Ethereum.
var Secp256k1 = ethSecp256k1{}

type ethSecp256k1 struct{}

// Name returns the Secp256k1 PubKeyType.
func (s ethSecp256k1) Name() hd.PubKeyType {
return EthSecp256k1Type
}

// Derive derives and returns the secp256k1 private key for the given seed and HD path.
func (s ethSecp256k1) Derive() hd.DeriveFn {
return func(mnemonic string, bip39Passphrase, hdPath string) ([]byte, error) {
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)
if err != nil {
return nil, err
}

seed = mac.Sum(nil)

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

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

return derivedKey, nil
}
}

func (ethSecp256k1) Generate() hd.GenerateFn {
return func(bz []byte) tmcrypto.PrivKey {
var bzArr [32]byte
copy(bzArr[:], bz)
return PrivKeySecp256k1(bzArr[:])
}
}
34 changes: 34 additions & 0 deletions crypto/algorithm_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package crypto

import (
"strings"
"testing"

"github.com/stretchr/testify/require"

"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/tests"
sdk "github.com/cosmos/cosmos-sdk/types"
)

func TestKeyring(t *testing.T) {
dir, cleanup := tests.NewTestCaseDir(t)
mockIn := strings.NewReader("")
t.Cleanup(cleanup)

kr, err := keyring.New("ethermint", keyring.BackendTest, dir, mockIn, EthSeckp256k1Option)
require.NoError(t, err)

// fail in retrieving key
info, err := kr.Key("foo")
require.Error(t, err)
require.Nil(t, info)

mockIn.Reset("password\npassword\n")
info, mnemonic, err := kr.NewMnemonic("foo", keyring.English, sdk.FullFundraiserPath, Secp256k1)
require.NoError(t, err)
require.NotEmpty(t, mnemonic)
require.Equal(t, "foo", info.GetName())
require.Equal(t, "local", info.GetType().String())
require.Equal(t, EthSecp256k1Type, info.GetAlgo())
}
15 changes: 12 additions & 3 deletions crypto/codec.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
package crypto

import (
cryptoamino "github.com/tendermint/tendermint/crypto/encoding/amino"

"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
)

var cryptoCodec = codec.New()
// CryptoCodec defines the Ethermint crypto codec for amino encoding
var CryptoCodec = codec.New()

// Amino encoding names
const (
// Amino encoding names
PrivKeyAminoName = "crypto/PrivKeySecp256k1"
PubKeyAminoName = "crypto/PubKeySecp256k1"
)

func init() {
RegisterCodec(cryptoCodec)
// replace the keyring codec with the ethermint crypto codec to prevent
// amino panics because of unregistered Priv/PubKey
keyring.CryptoCdc = CryptoCodec
keyring.RegisterCodec(CryptoCodec)
cryptoamino.RegisterAmino(CryptoCodec)
RegisterCodec(CryptoCodec)
}

// RegisterCodec registers all the necessary types with amino for the given
Expand Down
4 changes: 2 additions & 2 deletions crypto/secp256k1.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (privkey PrivKeySecp256k1) PubKey() tmcrypto.PubKey {

// Bytes returns the raw ECDSA private key bytes.
func (privkey PrivKeySecp256k1) Bytes() []byte {
return cryptoCodec.MustMarshalBinaryBare(privkey)
return CryptoCodec.MustMarshalBinaryBare(privkey)
}

// Sign creates a recoverable ECDSA signature on the secp256k1 curve over the
Expand Down Expand Up @@ -87,7 +87,7 @@ func (key PubKeySecp256k1) Address() tmcrypto.Address {

// Bytes returns the raw bytes of the ECDSA public key.
func (key PubKeySecp256k1) Bytes() []byte {
bz, err := cryptoCodec.MarshalBinaryBare(key)
bz, err := CryptoCodec.MarshalBinaryBare(key)
if err != nil {
panic(err)
}
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ require (
github.com/aristanetworks/goarista v0.0.0-20200331225509-2cc472e8fbd6 // indirect
github.com/btcsuite/btcd v0.20.1-beta // indirect
github.com/cespare/cp v1.1.1 // indirect
github.com/cosmos/cosmos-sdk v0.34.4-0.20200403200637-7f78e61b93a5
github.com/cosmos/cosmos-sdk v0.34.4-0.20200409144707-d10de8aad955
github.com/deckarep/golang-set v1.7.1 // indirect
github.com/elastic/gosigar v0.10.3 // indirect
github.com/ethereum/go-ethereum v1.9.14
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect
github.com/gogo/protobuf v1.3.1
github.com/golangci/golangci-lint v1.23.8 // indirect
github.com/gorilla/mux v1.7.4
github.com/mattn/go-colorable v0.1.4 // indirect
github.com/onsi/ginkgo v1.11.0 // indirect
Expand All @@ -29,8 +30,7 @@ require (
github.com/tendermint/go-amino v0.15.1
github.com/tendermint/tendermint v0.33.3
github.com/tendermint/tm-db v0.5.1
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4
gopkg.in/yaml.v2 v2.3.0
)

replace github.com/cosmos/cosmos-sdk => github.com/cosmos/cosmos-sdk v0.34.4-0.20200403200637-7f78e61b93a5
Loading

0 comments on commit 5614adc

Please sign in to comment.