Adding support for Ledger Cosmos App v1.5 (#4227)

This PR adds support for the latest version of the Cosmos App (v.1.5).
The app is not been released yet by Ledger but the PR is backwards compatible.
We can later remove backwards compatibility and enforce v1.5 only.

When creating a new account, `gaiacli` now shows the account/index and address in the device and requires user confirmation.

Related PRs:
https://github.com/cosmos/ledger-cosmos-go/pull/3
https://github.com/cosmos/ledger-cosmos-go/pull/4
https://github.com/cosmos/ledger-cosmos-go/pull/5
https://github.com/cosmos/ledger-cosmos-go/pull/6

Changes in the app can be found here:
https://github.com/LedgerHQ/ledger-app-cosmos/pull/5
This commit is contained in:
Juan Leni 2019-04-30 10:58:21 +02:00 committed by Alessio Treglia
parent f0f7b7dab7
commit 1306a25e42
13 changed files with 254 additions and 61 deletions

View File

@ -0,0 +1 @@
#4227 Support for Ledger App v1.5

View File

@ -171,9 +171,10 @@ func runAddCmd(_ *cobra.Command, args []string) error {
account := uint32(viper.GetInt(flagAccount))
index := uint32(viper.GetInt(flagIndex))
// If we're using ledger, only thing we need is the path. So generate key and we're done.
// If we're using ledger, only thing we need is the path and the bech32 prefix.
if viper.GetBool(client.FlagUseLedger) {
info, err := kb.CreateLedger(name, keys.Secp256k1, account, index)
bech32PrefixAccAddr := sdk.GetConfig().GetBech32AccountAddrPrefix()
info, err := kb.CreateLedger(name, keys.Secp256k1, bech32PrefixAccAddr, account, index)
if err != nil {
return err
}

View File

@ -25,7 +25,7 @@ const (
FlagPublicKey = "pubkey"
// FlagBechPrefix defines a desired Bech32 prefix encoding for a key.
FlagBechPrefix = "bech"
// FlagBechPrefix defines a desired Bech32 prefix encoding for a key.
// FlagDevice indicates that the information should be shown in the device
FlagDevice = "device"
flagMultiSigThreshold = "multisig-threshold"
@ -48,7 +48,7 @@ consisting of all the keys provided by name and multisig threshold.`,
cmd.Flags().String(FlagBechPrefix, sdk.PrefixAccount, "The Bech32 prefix encoding for a key (acc|val|cons)")
cmd.Flags().BoolP(FlagAddress, "a", false, "Output the address only (overrides --output)")
cmd.Flags().BoolP(FlagPublicKey, "p", false, "Output the public key only (overrides --output)")
cmd.Flags().BoolP(FlagDevice, "d", false, "Output the address in the device")
cmd.Flags().BoolP(FlagDevice, "d", false, "Output the address in a ledger device")
cmd.Flags().Uint(flagMultiSigThreshold, 1, "K out of N required signatures")
cmd.Flags().BoolP(flagShowMultiSig, "m", false, "Output multisig pubkey constituents, threshold, and weights")
cmd.Flags().Bool(client.FlagIndentResponse, false, "Add indent to JSON response")

View File

@ -137,18 +137,19 @@ func (kb dbKeybase) Derive(name, mnemonic, bip39Passphrase, encryptPasswd string
// CreateLedger creates a new locally-stored reference to a Ledger keypair
// It returns the created key info and an error if the Ledger could not be queried
func (kb dbKeybase) CreateLedger(name string, algo SigningAlgo, account uint32, index uint32) (Info, error) {
func (kb dbKeybase) CreateLedger(name string, algo SigningAlgo, hrp string, account, index uint32) (Info, error) {
if algo != Secp256k1 {
return nil, ErrUnsupportedSigningAlgo
}
hdPath := hd.NewFundraiserParams(account, index)
priv, err := crypto.NewPrivKeyLedgerSecp256k1(*hdPath)
priv, _, err := crypto.NewPrivKeyLedgerSecp256k1(*hdPath, hrp)
if err != nil {
return nil, err
}
pub := priv.PubKey()
// Note: Once Cosmos App v1.3.1 is compulsory, it could be possible to check that pubkey and addr match
return kb.writeLedgerKey(name, pub, *hdPath), nil
}
@ -246,7 +247,7 @@ func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, pub t
case ledgerInfo:
linfo := info.(ledgerInfo)
priv, err = crypto.NewPrivKeyLedgerSecp256k1(linfo.Path)
priv, err = crypto.NewPrivKeyLedgerSecp256k1Unsafe(linfo.Path)
if err != nil {
return
}

View File

@ -38,7 +38,7 @@ func TestCreateAccountInvalidMnemonic(t *testing.T) {
func TestCreateLedgerUnsupportedAlgo(t *testing.T) {
kb := NewInMemory()
_, err := kb.CreateLedger("some_account", Ed25519, 0, 1)
_, err := kb.CreateLedger("some_account", Ed25519, "cosmos", 0, 1)
assert.Error(t, err)
assert.Equal(t, "unsupported signing algo: only secp256k1 is supported", err.Error())
}
@ -50,7 +50,7 @@ func TestCreateLedger(t *testing.T) {
// test_cover does not compile some dependencies so ledger is disabled
// test_unit may add a ledger mock
// both cases are acceptable
ledger, err := kb.CreateLedger("some_account", Secp256k1, 3, 1)
ledger, err := kb.CreateLedger("some_account", Secp256k1, "cosmos", 3, 1)
if err != nil {
assert.Error(t, err)

View File

@ -106,14 +106,14 @@ func (lkb lazyKeybase) Derive(name, mnemonic, bip39Passwd, encryptPasswd string,
return newDbKeybase(db).Derive(name, mnemonic, bip39Passwd, encryptPasswd, params)
}
func (lkb lazyKeybase) CreateLedger(name string, algo SigningAlgo, account uint32, index uint32) (info Info, err error) {
func (lkb lazyKeybase) CreateLedger(name string, algo SigningAlgo, hrp string, account, index uint32) (info Info, err error) {
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
if err != nil {
return nil, err
}
defer db.Close()
return newDbKeybase(db).CreateLedger(name, algo, account, index)
return newDbKeybase(db).CreateLedger(name, algo, hrp, account, index)
}
func (lkb lazyKeybase) CreateOffline(name string, pubkey crypto.PubKey) (info Info, err error) {

View File

@ -35,7 +35,7 @@ type Keybase interface {
Derive(name, mnemonic, bip39Passwd, encryptPasswd string, params hd.BIP44Params) (Info, error)
// CreateLedger creates, stores, and returns a new Ledger key reference
CreateLedger(name string, algo SigningAlgo, account uint32, index uint32) (info Info, err error)
CreateLedger(name string, algo SigningAlgo, hrp string, account, index uint32) (info Info, err error)
// CreateOffline creates, stores, and returns a new offline key reference
CreateOffline(name string, pubkey crypto.PubKey) (info Info, err error)

View File

@ -4,15 +4,17 @@ package crypto
import (
"fmt"
"github.com/btcsuite/btcd/btcec"
bip39 "github.com/cosmos/go-bip39"
"github.com/pkg/errors"
secp256k1 "github.com/tendermint/btcd/btcec"
"github.com/tendermint/tendermint/crypto"
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
"github.com/cosmos/cosmos-sdk/tests"
"github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/go-bip39"
secp256k1 "github.com/tendermint/btcd/btcec"
"github.com/tendermint/tendermint/crypto"
tmsecp256k1 "github.com/tendermint/tendermint/crypto/secp256k1"
)
// If ledger support (build tag) has been enabled, which implies a CGO dependency,
@ -31,6 +33,8 @@ func (mock LedgerSECP256K1Mock) Close() error {
return nil
}
// GetPublicKeySECP256K1 mocks a ledger device
// as per the original API, it returns an uncompressed key
func (mock LedgerSECP256K1Mock) GetPublicKeySECP256K1(derivationPath []uint32) ([]byte, error) {
if derivationPath[0] != 44 {
return nil, errors.New("Invalid derivation path")
@ -56,6 +60,28 @@ func (mock LedgerSECP256K1Mock) GetPublicKeySECP256K1(derivationPath []uint32) (
return pubkeyObject.SerializeUncompressed(), nil
}
// GetAddressPubKeySECP256K1 mocks a ledger device
// as per the original API, it returns a compressed key and a bech32 address
func (mock LedgerSECP256K1Mock) GetAddressPubKeySECP256K1(derivationPath []uint32, hrp string) ([]byte, string, error) {
pk, err := mock.GetPublicKeySECP256K1(derivationPath)
if err != nil {
return nil, "", err
}
// re-serialize in the 33-byte compressed format
cmp, err := btcec.ParsePubKey(pk[:], btcec.S256())
if err != nil {
return nil, "", fmt.Errorf("error parsing public key: %v", err)
}
var compressedPublicKey tmsecp256k1.PubKeySecp256k1
copy(compressedPublicKey[:], cmp.SerializeCompressed())
// Generate the bech32 addr using existing tmcrypto/etc.
addr := types.AccAddress(compressedPublicKey.Address()).String()
return pk, addr, err
}
func (mock LedgerSECP256K1Mock) SignSECP256K1(derivationPath []uint32, message []byte) ([]byte, error) {
path := hd.NewParams(derivationPath[0], derivationPath[1], derivationPath[2], derivationPath[3] != 0, derivationPath[4])
seed, err := bip39.NewSeedWithErrorChecking(tests.TestMnemonic, "")

View File

@ -5,12 +5,11 @@ import (
"os"
"github.com/btcsuite/btcd/btcec"
"github.com/pkg/errors"
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
"github.com/cosmos/cosmos-sdk/types"
"github.com/pkg/errors"
tmbtcec "github.com/tendermint/btcd/btcec"
tmcrypto "github.com/tendermint/tendermint/crypto"
tmsecp256k1 "github.com/tendermint/tendermint/crypto/secp256k1"
@ -28,13 +27,15 @@ type (
// dependencies when Ledger support is potentially not enabled.
discoverLedgerFn func() (LedgerSECP256K1, error)
// LedgerSECP256K1 reflects an interface a Ledger API must implement for
// the SECP256K1 scheme.
// LedgerSECP256K1 reflects an interface a Ledger API must implement for SECP256K1
LedgerSECP256K1 interface {
Close() error
// Returns an uncompressed pubkey
GetPublicKeySECP256K1([]uint32) ([]byte, error)
// Returns a compressed pubkey and bech32 address (requires user confirmation)
GetAddressPubKeySECP256K1([]uint32, string) ([]byte, string, error)
// Signs a message (requires user confirmation)
SignSECP256K1([]uint32, []byte) ([]byte, error)
ShowAddressSECP256K1([]uint32, string) error
}
// PrivKeyLedgerSecp256k1 implements PrivKey, calling the ledger nano we
@ -48,16 +49,19 @@ type (
}
)
// NewPrivKeyLedgerSecp256k1 will generate a new key and store the public key
// for later use.
func NewPrivKeyLedgerSecp256k1(path hd.BIP44Params) (tmcrypto.PrivKey, error) {
// NewPrivKeyLedgerSecp256k1Unsafe will generate a new key and store the public key for later use.
//
// This function is marked as unsafe as it will retrieve a pubkey without user verification.
// It can only be used to verify a pubkey but never to create new accounts/keys. In that case,
// please refer to NewPrivKeyLedgerSecp256k1
func NewPrivKeyLedgerSecp256k1Unsafe(path hd.BIP44Params) (tmcrypto.PrivKey, error) {
device, err := getLedgerDevice()
if err != nil {
return nil, err
}
defer warnIfErrors(device.Close)
pubKey, err := getPubKey(device, path)
pubKey, err := getPubKeyUnsafe(device, path)
if err != nil {
return nil, err
}
@ -65,24 +69,21 @@ func NewPrivKeyLedgerSecp256k1(path hd.BIP44Params) (tmcrypto.PrivKey, error) {
return PrivKeyLedgerSecp256k1{pubKey, path}, nil
}
// LedgerShowAddress triggers a ledger device to show the corresponding address.
func LedgerShowAddress(path hd.BIP44Params, expectedPubKey tmcrypto.PubKey) error {
// NewPrivKeyLedgerSecp256k1 will generate a new key and store the public key for later use.
// The request will require user confirmation and will show account and index in the device
func NewPrivKeyLedgerSecp256k1(path hd.BIP44Params, hrp string) (tmcrypto.PrivKey, string, error) {
device, err := getLedgerDevice()
if err != nil {
return err
return nil, "", err
}
defer warnIfErrors(device.Close)
pubKey, err := getPubKey(device, path)
pubKey, addr, err := getPubKeyAddrSafe(device, path, hrp)
if err != nil {
return err
return nil, "", err
}
if pubKey != expectedPubKey {
return fmt.Errorf("pubkey does not match, Check this is the same device")
}
return device.ShowAddressSECP256K1(path.DerivationPath(), types.Bech32PrefixAccAddr)
return PrivKeyLedgerSecp256k1{pubKey, path}, addr, nil
}
// PubKey returns the cached public key.
@ -101,6 +102,35 @@ func (pkl PrivKeyLedgerSecp256k1) Sign(message []byte) ([]byte, error) {
return sign(device, pkl, message)
}
// LedgerShowAddress triggers a ledger device to show the corresponding address.
func LedgerShowAddress(path hd.BIP44Params, expectedPubKey tmcrypto.PubKey) error {
device, err := getLedgerDevice()
if err != nil {
return err
}
defer warnIfErrors(device.Close)
pubKey, err := getPubKeyUnsafe(device, path)
if err != nil {
return err
}
if pubKey != expectedPubKey {
return fmt.Errorf("the key's pubkey does not match with the one retrieved from Ledger. Check that the HD path and device are the correct ones")
}
pubKey2, _, err := getPubKeyAddrSafe(device, path, types.Bech32PrefixAccAddr)
if err != nil {
return err
}
if pubKey2 != expectedPubKey {
return fmt.Errorf("the key's pubkey does not match with the one retrieved from Ledger. Check that the HD path and device are the correct ones")
}
return nil
}
// ValidateKey allows us to verify the sanity of a public key after loading it
// from disk.
func (pkl PrivKeyLedgerSecp256k1) ValidateKey() error {
@ -162,7 +192,7 @@ func getLedgerDevice() (LedgerSECP256K1, error) {
}
func validateKey(device LedgerSECP256K1, pkl PrivKeyLedgerSecp256k1) error {
pub, err := getPubKey(device, pkl.Path)
pub, err := getPubKeyUnsafe(device, pkl.Path)
if err != nil {
return err
}
@ -194,10 +224,15 @@ func sign(device LedgerSECP256K1, pkl PrivKeyLedgerSecp256k1, msg []byte) ([]byt
return convertDERtoBER(sig)
}
// getPubKey reads the pubkey the ledger itself
// getPubKeyUnsafe reads the pubkey from a ledger device
//
// This function is marked as unsafe as it will retrieve a pubkey without user verification
// It can only be used to verify a pubkey but never to create new accounts/keys. In that case,
// please refer to getPubKeyAddrSafe
//
// since this involves IO, it may return an error, which is not exposed
// in the PubKey interface, so this function allows better error handling
func getPubKey(device LedgerSECP256K1, path hd.BIP44Params) (tmcrypto.PubKey, error) {
func getPubKeyUnsafe(device LedgerSECP256K1, path hd.BIP44Params) (tmcrypto.PubKey, error) {
publicKey, err := device.GetPublicKeySECP256K1(path.DerivationPath())
if err != nil {
return nil, fmt.Errorf("please open Cosmos app on the Ledger device - error: %v", err)
@ -214,3 +249,27 @@ func getPubKey(device LedgerSECP256K1, path hd.BIP44Params) (tmcrypto.PubKey, er
return compressedPublicKey, nil
}
// getPubKeyAddr reads the pubkey and the address from a ledger device.
// This function is marked as Safe as it will require user confirmation and
// account and index will be shown in the device.
//
// Since this involves IO, it may return an error, which is not exposed
// in the PubKey interface, so this function allows better error handling.
func getPubKeyAddrSafe(device LedgerSECP256K1, path hd.BIP44Params, hrp string) (tmcrypto.PubKey, string, error) {
publicKey, addr, err := device.GetAddressPubKeySECP256K1(path.DerivationPath(), hrp)
if err != nil {
return nil, "", fmt.Errorf("address %s rejected", addr)
}
// re-serialize in the 33-byte compressed format
cmp, err := btcec.ParsePubKey(publicKey[:], btcec.S256())
if err != nil {
return nil, "", fmt.Errorf("error parsing public key: %v", err)
}
var compressedPublicKey tmsecp256k1.PubKeySecp256k1
copy(compressedPublicKey[:], cmp.SerializeCompressed())
return compressedPublicKey, addr, nil
}

View File

@ -19,27 +19,31 @@ func TestLedgerErrorHandling(t *testing.T) {
// first, try to generate a key, must return an error
// (no panic)
path := *hd.NewParams(44, 555, 0, false, 0)
_, err := NewPrivKeyLedgerSecp256k1(path)
_, err := NewPrivKeyLedgerSecp256k1Unsafe(path)
require.Error(t, err)
}
func TestPublicKey(t *testing.T) {
func TestPublicKeyUnsafe(t *testing.T) {
path := *hd.NewFundraiserParams(0, 0)
priv, err := NewPrivKeyLedgerSecp256k1(path)
priv, err := NewPrivKeyLedgerSecp256k1Unsafe(path)
require.Nil(t, err, "%s", err)
require.NotNil(t, priv)
require.Equal(t, "eb5ae98721034fef9cd7c4c63588d3b03feb5281b9d232cba34d6f3d71aee59211ffbfe1fe87",
fmt.Sprintf("%x", priv.PubKey().Bytes()),
"Is your device using test mnemonic: %s ?", tests.TestMnemonic)
pubKeyAddr, err := sdk.Bech32ifyAccPub(priv.PubKey())
require.NoError(t, err)
require.Equal(t, "cosmospub1addwnpepqd87l8xhcnrrtzxnkql7k55ph8fr9jarf4hn6udwukfprlalu8lgw0urza0",
pubKeyAddr, "Is your device using test mnemonic: %s ?", tests.TestMnemonic)
require.Equal(t, "5075624b6579536563703235366b317b303334464546394344374334433633353838443342303"+
"3464542353238314239443233324342413334443646334437314145453539323131464642464531464538377d",
fmt.Sprintf("%x", priv.PubKey()))
addr := sdk.AccAddress(priv.PubKey().Address()).String()
require.Equal(t, "cosmos1w34k53py5v5xyluazqpq65agyajavep2rflq6h",
addr, "Is your device using test mnemonic: %s ?", tests.TestMnemonic)
}
func TestPublicKeyHDPath(t *testing.T) {
func TestPublicKeyUnsafeHDPath(t *testing.T) {
expectedAnswers := []string{
"cosmospub1addwnpepqd87l8xhcnrrtzxnkql7k55ph8fr9jarf4hn6udwukfprlalu8lgw0urza0",
"cosmospub1addwnpepqfsdqjr68h7wjg5wacksmqaypasnra232fkgu5sxdlnlu8j22ztxvlqvd65",
@ -62,7 +66,7 @@ func TestPublicKeyHDPath(t *testing.T) {
path := *hd.NewFundraiserParams(0, i)
fmt.Printf("Checking keys at %v\n", path)
priv, err := NewPrivKeyLedgerSecp256k1(path)
priv, err := NewPrivKeyLedgerSecp256k1Unsafe(path)
require.Nil(t, err, "%s", err)
require.NotNil(t, priv)
@ -94,6 +98,104 @@ func TestPublicKeyHDPath(t *testing.T) {
}
}
func TestPublicKeySafe(t *testing.T) {
path := *hd.NewFundraiserParams(0, 0)
priv, addr, err := NewPrivKeyLedgerSecp256k1(path, "cosmos")
require.Nil(t, err, "%s", err)
require.NotNil(t, priv)
require.Equal(t, "eb5ae98721034fef9cd7c4c63588d3b03feb5281b9d232cba34d6f3d71aee59211ffbfe1fe87",
fmt.Sprintf("%x", priv.PubKey().Bytes()),
"Is your device using test mnemonic: %s ?", tests.TestMnemonic)
pubKeyAddr, err := sdk.Bech32ifyAccPub(priv.PubKey())
require.NoError(t, err)
require.Equal(t, "cosmospub1addwnpepqd87l8xhcnrrtzxnkql7k55ph8fr9jarf4hn6udwukfprlalu8lgw0urza0",
pubKeyAddr, "Is your device using test mnemonic: %s ?", tests.TestMnemonic)
require.Equal(t, "cosmos1w34k53py5v5xyluazqpq65agyajavep2rflq6h",
addr, "Is your device using test mnemonic: %s ?", tests.TestMnemonic)
addr2 := sdk.AccAddress(priv.PubKey().Address()).String()
require.Equal(t, addr, addr2)
}
func TestPublicKeyHDPath(t *testing.T) {
expectedPubKeys := []string{
"cosmospub1addwnpepqd87l8xhcnrrtzxnkql7k55ph8fr9jarf4hn6udwukfprlalu8lgw0urza0",
"cosmospub1addwnpepqfsdqjr68h7wjg5wacksmqaypasnra232fkgu5sxdlnlu8j22ztxvlqvd65",
"cosmospub1addwnpepqw3xwqun6q43vtgw6p4qspq7srvxhcmvq4jrx5j5ma6xy3r7k6dtxmrkh3d",
"cosmospub1addwnpepqvez9lrp09g8w7gkv42y4yr5p6826cu28ydrhrujv862yf4njmqyyjr4pjs",
"cosmospub1addwnpepq06hw3enfrtmq8n67teytcmtnrgcr0yntmyt25kdukfjkerdc7lqg32rcz7",
"cosmospub1addwnpepqg3trf2gd0s2940nckrxherwqhgmm6xd5h4pcnrh4x7y35h6yafmcpk5qns",
"cosmospub1addwnpepqdm6rjpx6wsref8wjn7ym6ntejet430j4szpngfgc20caz83lu545vuv8hp",
"cosmospub1addwnpepqvdhtjzy2wf44dm03jxsketxc07vzqwvt3vawqqtljgsr9s7jvydjmt66ew",
"cosmospub1addwnpepqwystfpyxwcava7v3t7ndps5xzu6s553wxcxzmmnxevlzvwrlqpzz695nw9",
"cosmospub1addwnpepqw970u6gjqkccg9u3rfj99857wupj2z9fqfzy2w7e5dd7xn7kzzgkgqch0r",
}
expectedAddrs := []string{
"cosmos1w34k53py5v5xyluazqpq65agyajavep2rflq6h",
"cosmos19ewxwemt6uahejvwf44u7dh6tq859tkyvarh2q",
"cosmos1a07dzdjgjsntxpp75zg7cgatgq0udh3pcdcxm3",
"cosmos1qvw52lmn9gpvem8welghrkc52m3zczyhlqjsl7",
"cosmos17m78ka80fqkkw2c4ww0v4xm5nsu2drgrlm8mn2",
"cosmos1ferh9ll9c452d2p8k2v7heq084guygkn43up9e",
"cosmos10vf3sxmjg96rqq36axcphzfsl74dsntuehjlw5",
"cosmos1cq83av8cmnar79h0rg7duh9gnr7wkh228a7fxg",
"cosmos1dszhfrt226jy5rsre7e48vw9tgwe90uerfyefa",
"cosmos1734d7qsylzrdt05muhqqtpd90j8mp4y6rzch8l",
}
const numIters = 10
privKeys := make([]tmcrypto.PrivKey, numIters)
// Check with device
for i := uint32(0); i < 10; i++ {
path := *hd.NewFundraiserParams(0, i)
fmt.Printf("Checking keys at %v\n", path)
priv, addr, err := NewPrivKeyLedgerSecp256k1(path, "cosmos")
require.Nil(t, err, "%s", err)
require.NotNil(t, addr)
require.NotNil(t, priv)
addr2 := sdk.AccAddress(priv.PubKey().Address()).String()
require.Equal(t, addr2, addr)
require.Equal(t,
expectedAddrs[i], addr,
"Is your device using test mnemonic: %s ?", tests.TestMnemonic)
// Check other methods
require.NoError(t, priv.(PrivKeyLedgerSecp256k1).ValidateKey())
tmp := priv.(PrivKeyLedgerSecp256k1)
(&tmp).AssertIsPrivKeyInner()
pubKeyAddr, err := sdk.Bech32ifyAccPub(priv.PubKey())
require.NoError(t, err)
require.Equal(t,
expectedPubKeys[i], pubKeyAddr,
"Is your device using test mnemonic: %s ?", tests.TestMnemonic)
// Store and restore
serializedPk := priv.Bytes()
require.NotNil(t, serializedPk)
require.True(t, len(serializedPk) >= 50)
privKeys[i] = priv
}
// Now check equality
for i := 0; i < 10; i++ {
for j := 0; j < 10; j++ {
require.Equal(t, i == j, privKeys[i].Equals(privKeys[j]))
require.Equal(t, i == j, privKeys[j].Equals(privKeys[i]))
}
}
}
func getFakeTx(accountNumber uint32) []byte {
tmp := fmt.Sprintf(
`{"account_number":"%d","chain_id":"1234","fee":{"amount":[{"amount":"150","denom":"atom"}],"gas":"5000"},"memo":"memo","msgs":[[""]],"sequence":"6"}`,
@ -109,7 +211,7 @@ func TestSignaturesHD(t *testing.T) {
path := *hd.NewFundraiserParams(account, account/5)
fmt.Printf("Checking signature at %v --- PLEASE REVIEW AND ACCEPT IN THE DEVICE\n", path)
priv, err := NewPrivKeyLedgerSecp256k1(path)
priv, err := NewPrivKeyLedgerSecp256k1Unsafe(path)
require.Nil(t, err, "%s", err)
pub := priv.PubKey()
@ -124,7 +226,7 @@ func TestSignaturesHD(t *testing.T) {
func TestRealLedgerSecp256k1(t *testing.T) {
msg := getFakeTx(50)
path := *hd.NewFundraiserParams(0, 0)
priv, err := NewPrivKeyLedgerSecp256k1(path)
priv, err := NewPrivKeyLedgerSecp256k1Unsafe(path)
require.Nil(t, err, "%s", err)
pub := priv.PubKey()

8
go.mod
View File

@ -7,8 +7,7 @@ require (
github.com/bgentry/speakeasy v0.1.0
github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d
github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8
github.com/cosmos/ledger-cosmos-go v0.9.11
github.com/cosmos/ledger-go v0.9.1 // indirect
github.com/cosmos/ledger-cosmos-go v0.10.2
github.com/fortytw2/leaktest v1.3.0 // indirect
github.com/go-logfmt/logfmt v0.4.0 // indirect
github.com/gogo/protobuf v1.1.1
@ -27,7 +26,7 @@ require (
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95 // indirect
github.com/otiai10/mint v1.2.3 // indirect
github.com/pelletier/go-toml v1.2.0
github.com/pkg/errors v0.8.0
github.com/pkg/errors v0.8.1
github.com/prometheus/client_golang v0.9.2 // indirect
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 // indirect
github.com/prometheus/common v0.2.0 // indirect
@ -41,13 +40,12 @@ require (
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.3
github.com/spf13/viper v1.0.3
github.com/stretchr/testify v1.2.2
github.com/stretchr/testify v1.3.0
github.com/syndtr/goleveldb v0.0.0-20180708030551-c4c61651e9e3 // indirect
github.com/tendermint/btcd v0.1.1
github.com/tendermint/go-amino v0.14.1
github.com/tendermint/iavl v0.12.1
github.com/tendermint/tendermint v0.31.5
github.com/zondax/hid v0.9.0 // indirect
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793
google.golang.org/grpc v1.19.0 // indirect
gopkg.in/yaml.v2 v2.2.2 // indirect

10
go.sum
View File

@ -28,11 +28,12 @@ github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJ
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8 h1:Iwin12wRQtyZhH6FV3ykFcdGNlYEzoeR0jN8Vn+JWsI=
github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y=
github.com/cosmos/ledger-cosmos-go v0.9.11 h1:bkcIKqaM6evicjkSP+Le8HDLXt9P+MqGRnGiMUC20m4=
github.com/cosmos/ledger-cosmos-go v0.9.11/go.mod h1:RWldjvUf4Hfi46ti/8etBH3eQ2rOqqz2hstdzROQSHo=
github.com/cosmos/ledger-cosmos-go v0.10.2 h1:B8JlCtl6otXi5PxY3Y7OF+HLhjLYvsemo4nl23wPQ9Y=
github.com/cosmos/ledger-cosmos-go v0.10.2/go.mod h1:TOLCJf4/WyTm7uw3OKurqANyQ66yoJEH9D14o0cpRlU=
github.com/cosmos/ledger-go v0.9.1 h1:bRIamtlWShVk1THw52NdCPHxtBxKnauglSB23mH1/w8=
github.com/cosmos/ledger-go v0.9.1/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
@ -100,6 +101,8 @@ github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@ -134,9 +137,12 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.0.3 h1:z5LPUc2iz8VLT5Cw1UyrESG6FUUnOGecYGY08BLKSuc=
github.com/spf13/viper v1.0.3/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/syndtr/goleveldb v0.0.0-20180708030551-c4c61651e9e3 h1:sAlSBRDl4psFR3ysKXRSE8ss6Mt90+ma1zRTroTNBJA=
github.com/syndtr/goleveldb v0.0.0-20180708030551-c4c61651e9e3/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s=

View File

@ -1,12 +1,11 @@
package client
import (
"github.com/spf13/cobra"
"github.com/tendermint/go-amino"
sdkclient "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/cosmos/cosmos-sdk/x/mint/client/cli"
sdkclient "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/cosmos/cosmos-sdk/x/mint/client/cli"
"github.com/spf13/cobra"
"github.com/tendermint/go-amino"
)
type ModuleClient struct {