From 8c98c4fdf46aafc3b9d8690902ad38b8835a636a Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 13 Sep 2017 12:41:54 +0200 Subject: [PATCH] Add nano ledger to key manager --- keys/cryptostore/generator.go | 18 ++++++++++++++++++ nano/keys.go | 24 ++++++++++++++++-------- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/keys/cryptostore/generator.go b/keys/cryptostore/generator.go index 1f162ec08..c1984fc82 100644 --- a/keys/cryptostore/generator.go +++ b/keys/cryptostore/generator.go @@ -4,6 +4,7 @@ import ( "github.com/pkg/errors" crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/go-crypto/nano" ) var ( @@ -11,6 +12,8 @@ var ( GenEd25519 Generator = GenFunc(genEd25519) // GenSecp256k1 produces Secp256k1 private keys GenSecp256k1 Generator = GenFunc(genSecp256) + // GenLedger used Ed25519 keys stored on nano ledger s with cosmos app + GenLedger Generator = GenFunc(genLedger) ) // Generator determines the type of private key the keystore creates @@ -33,12 +36,25 @@ func genSecp256(secret []byte) crypto.PrivKey { return crypto.GenPrivKeySecp256k1FromSecret(secret).Wrap() } +// secret is completely ignored for the ledger... +// just for interface compatibility +func genLedger(secret []byte) crypto.PrivKey { + key, err := nano.NewPrivKeyLedger() + if err != nil { + // TODO: cleaner error handling + panic(err) + } + return key +} + func getGenerator(algo string) (Generator, error) { switch algo { case crypto.NameEd25519: return GenEd25519, nil case crypto.NameSecp256k1: return GenSecp256k1, nil + case nano.NameLedger: + return GenLedger, nil default: return nil, errors.Errorf("Cannot generate keys for algorithm: %s", algo) } @@ -50,6 +66,8 @@ func getGeneratorByType(typ byte) (Generator, error) { return GenEd25519, nil case crypto.TypeSecp256k1: return GenSecp256k1, nil + case nano.TypeLedger: + return GenLedger, nil default: return nil, errors.Errorf("Cannot generate keys for algorithm: %X", typ) } diff --git a/nano/keys.go b/nano/keys.go index 6b337e8b7..2ab4d59a8 100644 --- a/nano/keys.go +++ b/nano/keys.go @@ -12,6 +12,11 @@ import ( wire "github.com/tendermint/go-wire" ) +const ( + NameLedger = "ledger" + TypeLedger = 0x10 +) + var device *ledger.Ledger // getLedger gets a copy of the device, and caches it @@ -48,7 +53,10 @@ func signLedger(device *ledger.Ledger, msg []byte) (pk crypto.PubKey, sig crypto // PrivKeyLedger implements PrivKey, calling the ledger nano // we cache the PubKey from the first call to use it later type PrivKeyLedger struct { - pubKey crypto.PubKey + // PubKey should be private, but we want to encode it via go-wire + // so we can view the address later, even without having the ledger + // attached + CachedPubKey crypto.PubKey } func NewPrivKeyLedger() (crypto.PrivKey, error) { @@ -82,8 +90,8 @@ func (pk *PrivKeyLedger) Sign(msg []byte) crypto.Signature { } // if we have no pubkey yet, store it for future queries - if pk.pubKey.Empty() { - pk.pubKey = pub + if pk.CachedPubKey.Empty() { + pk.CachedPubKey = pub } return sig } @@ -103,17 +111,17 @@ func (pk *PrivKeyLedger) PubKey() crypto.PubKey { // in the PubKey interface, so this function allows better error handling func (pk *PrivKeyLedger) getPubKey() (key crypto.PubKey, err error) { // if we have no pubkey, set it - if pk.pubKey.Empty() { + if pk.CachedPubKey.Empty() { dev, err := getLedger() if err != nil { return key, errors.WithMessage(err, "Can't connect to ledger") } - pk.pubKey, _, err = signLedger(dev, []byte{0}) + pk.CachedPubKey, _, err = signLedger(dev, []byte{0}) if err != nil { return key, errors.WithMessage(err, "Can't sign with app") } } - return pk.pubKey, nil + return pk.CachedPubKey, nil } // Equals fulfils PrivKey Interface @@ -219,11 +227,11 @@ func (pk PubKeyLedger) Equals(other crypto.PubKey) bool { func init() { crypto.PrivKeyMapper. - RegisterImplementation(&PrivKeyLedger{}, "ledger", 0x10). + RegisterImplementation(&PrivKeyLedger{}, NameLedger, TypeLedger). RegisterImplementation(MockPrivKeyLedger{}, "mock-ledger", 0x11) crypto.PubKeyMapper. - RegisterImplementation(PubKeyLedger{}, "ledger", 0x10) + RegisterImplementation(PubKeyLedger{}, NameLedger, TypeLedger) } // Wrap fulfils interface for PrivKey struct