diff --git a/amino.go b/amino.go index b78a15ed9..2af765434 100644 --- a/amino.go +++ b/amino.go @@ -19,8 +19,6 @@ func RegisterAmino(cdc *amino.Codec) { cdc.RegisterInterface((*PubKey)(nil), nil) cdc.RegisterConcrete(PubKeyEd25519{}, "tendermint/PubKeyEd25519", nil) - cdc.RegisterConcrete(PubKeyLedgerEd25519{}, - "tendermint/PubKeyLedgerEd25519", nil) cdc.RegisterConcrete(PubKeySecp256k1{}, "tendermint/PubKeySecp256k1", nil) @@ -31,8 +29,6 @@ func RegisterAmino(cdc *amino.Codec) { "tendermint/PrivKeySecp256k1", nil) cdc.RegisterConcrete(PrivKeyLedgerSecp256k1{}, "tendermint/PrivKeyLedgerSecp256k1", nil) - cdc.RegisterConcrete(PrivKeyLedgerEd25519{}, - "tendermint/PrivKeyLedgerEd25519", nil) cdc.RegisterInterface((*Signature)(nil), nil) cdc.RegisterConcrete(SignatureEd25519{}, diff --git a/ledger_ed25519.go b/ledger_ed25519.go deleted file mode 100644 index 2110b8871..000000000 --- a/ledger_ed25519.go +++ /dev/null @@ -1,156 +0,0 @@ -package crypto - -import ( - "fmt" - "github.com/pkg/errors" - - // "github.com/tendermint/ed25519" - ledger "github.com/zondax/ledger-goclient" -) - -func pubkeyLedgerEd25519(device *ledger.Ledger, path DerivationPath) (pub PubKey, err error) { - key, err := device.GetPublicKeyED25519(path) - if err != nil { - return pub, fmt.Errorf("Error fetching public key: %v", err) - } - var p PubKeyLedgerEd25519 - copy(p[:], key[0:32]) - return p, err -} - -func signLedgerEd25519(device *ledger.Ledger, path DerivationPath, msg []byte) (sig Signature, err error) { - bsig, err := device.SignED25519(path, msg) - if err != nil { - return sig, err - } - sig = SignatureEd25519FromBytes(bsig) - return sig, nil -} - -// PrivKeyLedgerEd25519 implements PrivKey, calling the ledger nano -// we cache the PubKey from the first call to use it later -type PrivKeyLedgerEd25519 struct { - // PubKey should be private, but we want to encode it via go-amino - // so we can view the address later, even without having the ledger - // attached - CachedPubKey PubKey - Path DerivationPath -} - -// NewPrivKeyLedgerEd25519 will generate a new key and store the -// public key for later use. -func NewPrivKeyLedgerEd25519(path DerivationPath) (PrivKey, error) { - var pk PrivKeyLedgerEd25519 - pk.Path = path - // getPubKey will cache the pubkey for later use, - // this allows us to return an error early if the ledger - // is not plugged in - _, err := pk.getPubKey() - return &pk, err -} - -// ValidateKey allows us to verify the sanity of a key -// after loading it from disk -func (pk PrivKeyLedgerEd25519) ValidateKey() error { - // getPubKey will return an error if the ledger is not - // properly set up... - pub, err := pk.forceGetPubKey() - if err != nil { - return err - } - // verify this matches cached address - if !pub.Equals(pk.CachedPubKey) { - return errors.New("Cached key does not match retrieved key") - } - return nil -} - -// AssertIsPrivKeyInner fulfils PrivKey Interface -func (pk *PrivKeyLedgerEd25519) AssertIsPrivKeyInner() {} - -// Bytes fulfils PrivKey Interface - but it stores the cached pubkey so we can verify -// the same key when we reconnect to a ledger -func (pk PrivKeyLedgerEd25519) Bytes() []byte { - bin, err := cdc.MarshalBinaryBare(pk) - if err != nil { - panic(err) - } - return bin -} - -// Sign calls the ledger and stores the PubKey for future use -// -// XXX/TODO: panics if there is an error communicating with the ledger. -// -// Communication is checked on NewPrivKeyLedger and PrivKeyFromBytes, -// returning an error, so this should only trigger if the privkey is held -// in memory for a while before use. -func (pk PrivKeyLedgerEd25519) Sign(msg []byte) Signature { - // oh, I wish there was better error handling - dev, err := getLedger() - if err != nil { - panic(err) - } - - sig, err := signLedgerEd25519(dev, pk.Path, msg) - if err != nil { - panic(err) - } - - pub, err := pubkeyLedgerEd25519(dev, pk.Path) - if err != nil { - panic(err) - } - - // if we have no pubkey yet, store it for future queries - if pk.CachedPubKey == nil { - pk.CachedPubKey = pub - } else if !pk.CachedPubKey.Equals(pub) { - panic("Stored key does not match signing key") - } - return sig -} - -// PubKey returns the stored PubKey -// TODO: query the ledger if not there, once it is not volatile -func (pk PrivKeyLedgerEd25519) PubKey() PubKey { - key, err := pk.getPubKey() - if err != nil { - panic(err) - } - return key -} - -// getPubKey reads the pubkey from cache or from the ledger itself -// 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 (pk PrivKeyLedgerEd25519) getPubKey() (key PubKey, err error) { - // if we have no pubkey, set it - if pk.CachedPubKey == nil { - pk.CachedPubKey, err = pk.forceGetPubKey() - } - return pk.CachedPubKey, err -} - -// forceGetPubKey is like getPubKey but ignores any cached key -// and ensures we get it from the ledger itself. -func (pk PrivKeyLedgerEd25519) forceGetPubKey() (key PubKey, err error) { - dev, err := getLedger() - if err != nil { - return key, errors.New(fmt.Sprintf("Cannot connect to Ledger device - error: %v", err)) - } - key, err = pubkeyLedgerEd25519(dev, pk.Path) - if err != nil { - return key, errors.New(fmt.Sprintf("Please open Cosmos app on the Ledger device - error: %v", err)) - } - return key, err -} - -// Equals fulfils PrivKey Interface - makes sure both keys refer to the -// same -func (pk PrivKeyLedgerEd25519) Equals(other PrivKey) bool { - if ledger, ok := other.(*PrivKeyLedgerEd25519); ok { - return pk.CachedPubKey.Equals(ledger.CachedPubKey) - } - return false -} diff --git a/ledger_pub_key.go b/ledger_pub_key.go deleted file mode 100644 index 0a5222577..000000000 --- a/ledger_pub_key.go +++ /dev/null @@ -1,68 +0,0 @@ -package crypto - -import ( - "bytes" - "crypto/sha512" - "fmt" - - "github.com/tendermint/ed25519" - "github.com/tendermint/ed25519/extra25519" - "golang.org/x/crypto/ripemd160" -) - -var _ PubKey = PubKeyLedgerEd25519{} - -// Implements PubKeyInner -type PubKeyLedgerEd25519 [32]byte - -func (pubKey PubKeyLedgerEd25519) Address() Address { - // append type byte - hasher := ripemd160.New() - hasher.Write(pubKey.Bytes()) // does not error - return Address(hasher.Sum(nil)) -} - -func (pubKey PubKeyLedgerEd25519) Bytes() []byte { - bz, err := cdc.MarshalBinaryBare(pubKey) - if err != nil { - panic(err) - } - return bz -} - -func (pubKey PubKeyLedgerEd25519) VerifyBytes(msg []byte, sig_ Signature) bool { - // must verify sha512 hash of msg, no padding, for Ledger compatibility - sig, ok := sig_.(SignatureEd25519) - if !ok { - return false - } - pubKeyBytes := [32]byte(pubKey) - sigBytes := [64]byte(sig) - h := sha512.New() - h.Write(msg) - digest := h.Sum(nil) - return ed25519.Verify(&pubKeyBytes, digest, &sigBytes) -} - -// For use with golang/crypto/nacl/box -// If error, returns nil. -func (pubKey PubKeyLedgerEd25519) ToCurve25519() *[32]byte { - keyCurve25519, pubKeyBytes := new([32]byte), [32]byte(pubKey) - ok := extra25519.PublicKeyToCurve25519(keyCurve25519, &pubKeyBytes) - if !ok { - return nil - } - return keyCurve25519 -} - -func (pubKey PubKeyLedgerEd25519) String() string { - return fmt.Sprintf("PubKeyLedgerEd25519{%X}", pubKey[:]) -} - -func (pubKey PubKeyLedgerEd25519) Equals(other PubKey) bool { - if otherEd, ok := other.(PubKeyLedgerEd25519); ok { - return bytes.Equal(pubKey[:], otherEd[:]) - } else { - return false - } -} diff --git a/ledger_test.go b/ledger_test.go index a0ea35837..dda3d3d3d 100644 --- a/ledger_test.go +++ b/ledger_test.go @@ -46,44 +46,6 @@ func TestRealLedgerSecp256k1(t *testing.T) { assert.Equal(t, pub, bpub) } -func TestRealLedgerEd25519(t *testing.T) { - - if os.Getenv("WITH_LEDGER") == "" { - t.Skip("Set WITH_LEDGER to run code on real ledger") - } - msg := []byte("kuhehfeohg") - - path := DerivationPath{44, 60, 0, 0, 0} - - priv, err := NewPrivKeyLedgerEd25519(path) - require.Nil(t, err, "%+v", err) - pub := priv.PubKey() - sig := priv.Sign(msg) - - valid := pub.VerifyBytes(msg, sig) - assert.True(t, valid) - - // now, let's serialize the key and make sure it still works - bs := priv.Bytes() - priv2, err := PrivKeyFromBytes(bs) - require.Nil(t, err, "%+v", err) - - // make sure we get the same pubkey when we load from disk - pub2 := priv2.PubKey() - require.Equal(t, pub, pub2) - - // signing with the loaded key should match the original pubkey - sig = priv2.Sign(msg) - valid = pub.VerifyBytes(msg, sig) - assert.True(t, valid) - - // make sure pubkeys serialize properly as well - bs = pub.Bytes() - bpub, err := PubKeyFromBytes(bs) - require.NoError(t, err) - assert.Equal(t, pub, bpub) -} - // TestRealLedgerErrorHandling calls. These tests assume // the ledger is not plugged in.... func TestRealLedgerErrorHandling(t *testing.T) {