diff --git a/client/keys/show.go b/client/keys/show.go index 2cb3c457f2ec..9f658bebced5 100644 --- a/client/keys/show.go +++ b/client/keys/show.go @@ -134,7 +134,7 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) { return nil } - return ledger.ShowAddress(*hdpath, info.GetPubKey(), sdk.GetConfig().GetBech32AccountAddrPrefix()) + return ledger.ShowAddress(hdpath, info.GetPubKey(), sdk.GetConfig().GetBech32AccountAddrPrefix()) } return nil diff --git a/crypto/codec/amino_test.go b/crypto/codec/amino_test.go new file mode 100644 index 000000000000..97d76c2a2a76 --- /dev/null +++ b/crypto/codec/amino_test.go @@ -0,0 +1,18 @@ +package codec + +import "os" + +// nolint: govet +func ExamplePrintRegisteredTypes() { + amino.PrintTypes(os.Stdout) + // Output: + // | Type | Name | Prefix | Length | Notes | + // | ---- | ---- | ------ | ----- | ------ | + // | PubKey | tendermint/PubKeySr25519 | 0x0DFB1005 | variable | | + // | PubKey | tendermint/PubKeyEd25519 | 0x1624DE64 | variable | | + // | PubKey | tendermint/PubKeySecp256k1 | 0xEB5AE987 | variable | | + // | LegacyAminoPubKey | tendermint/PubKeyMultisigThreshold | 0x22C1F7E2 | variable | | + // | PrivKey | tendermint/PrivKeySr25519 | 0x2F82D78B | variable | | + // | PrivKey | tendermint/PrivKeyEd25519 | 0xA3288910 | variable | | + // | PrivKey | tendermint/PrivKeySecp256k1 | 0xE1B0F79B | variable | | +} diff --git a/crypto/hd/hd.pb.go b/crypto/hd/hd.pb.go new file mode 100644 index 000000000000..884487a44555 --- /dev/null +++ b/crypto/hd/hd.pb.go @@ -0,0 +1,458 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: cosmos/base/hd/v1beta1/hd.proto + +package hd + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// BIP44Params wraps BIP 44 params (5 level BIP 32 path). +// To receive a canonical string representation ala +// m / purpose' / coinType' / account' / change / addressIndex +// call String() on a BIP44Params instance. +type BIP44Params struct { + Purpose uint32 `protobuf:"varint,1,opt,name=purpose,proto3" json:"purpose,omitempty"` + CoinType uint32 `protobuf:"varint,2,opt,name=coin_type,json=coinType,proto3" json:"coin_type,omitempty"` + Account uint32 `protobuf:"varint,3,opt,name=account,proto3" json:"account,omitempty"` + Change bool `protobuf:"varint,4,opt,name=change,proto3" json:"change,omitempty"` + AddressIndex uint32 `protobuf:"varint,5,opt,name=address_index,json=addressIndex,proto3" json:"address_index,omitempty"` +} + +func (m *BIP44Params) Reset() { *m = BIP44Params{} } +func (*BIP44Params) ProtoMessage() {} +func (*BIP44Params) Descriptor() ([]byte, []int) { + return fileDescriptor_2b1a395a5fd792cd, []int{0} +} +func (m *BIP44Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *BIP44Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_BIP44Params.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *BIP44Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_BIP44Params.Merge(m, src) +} +func (m *BIP44Params) XXX_Size() int { + return m.Size() +} +func (m *BIP44Params) XXX_DiscardUnknown() { + xxx_messageInfo_BIP44Params.DiscardUnknown(m) +} + +var xxx_messageInfo_BIP44Params proto.InternalMessageInfo + +func (m *BIP44Params) GetPurpose() uint32 { + if m != nil { + return m.Purpose + } + return 0 +} + +func (m *BIP44Params) GetCoinType() uint32 { + if m != nil { + return m.CoinType + } + return 0 +} + +func (m *BIP44Params) GetAccount() uint32 { + if m != nil { + return m.Account + } + return 0 +} + +func (m *BIP44Params) GetChange() bool { + if m != nil { + return m.Change + } + return false +} + +func (m *BIP44Params) GetAddressIndex() uint32 { + if m != nil { + return m.AddressIndex + } + return 0 +} + +func init() { + proto.RegisterType((*BIP44Params)(nil), "cosmos.base.hd.v1beta1.BIP44Params") +} + +func init() { proto.RegisterFile("cosmos/base/hd/v1beta1/hd.proto", fileDescriptor_2b1a395a5fd792cd) } + +var fileDescriptor_2b1a395a5fd792cd = []byte{ + // 271 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x34, 0x90, 0xb1, 0x4e, 0xc3, 0x30, + 0x10, 0x86, 0x63, 0x28, 0xa5, 0x18, 0xba, 0x44, 0xa8, 0xb2, 0x40, 0x72, 0x2b, 0x90, 0x50, 0x17, + 0x62, 0x55, 0x74, 0x62, 0x42, 0xdd, 0xba, 0x55, 0x15, 0x13, 0x4b, 0xe5, 0xd8, 0x56, 0x1c, 0xa1, + 0xe4, 0xac, 0xd8, 0x41, 0xe4, 0x2d, 0x18, 0x19, 0xe1, 0x6d, 0x18, 0x3b, 0x32, 0xa2, 0xe4, 0x45, + 0x50, 0x12, 0x77, 0xb2, 0xff, 0xff, 0xbe, 0x6f, 0xb8, 0xc3, 0x53, 0x01, 0x36, 0x03, 0xcb, 0x62, + 0x6e, 0x15, 0xd3, 0x92, 0xbd, 0x2d, 0x62, 0xe5, 0xf8, 0x82, 0x69, 0x19, 0x99, 0x02, 0x1c, 0x84, + 0x93, 0x1e, 0x88, 0x5a, 0x20, 0xd2, 0x32, 0xf2, 0xc0, 0xd5, 0x65, 0x02, 0x09, 0x74, 0x08, 0x6b, + 0x7f, 0x3d, 0x7d, 0xf3, 0x8d, 0xf0, 0xf9, 0x6a, 0xbd, 0x59, 0x2e, 0x37, 0xbc, 0xe0, 0x99, 0x0d, + 0x09, 0x3e, 0x35, 0x65, 0x61, 0xc0, 0x2a, 0x82, 0x66, 0x68, 0x3e, 0xde, 0x1e, 0x62, 0x78, 0x8d, + 0xcf, 0x04, 0xa4, 0xf9, 0xce, 0x55, 0x46, 0x91, 0xa3, 0x6e, 0x36, 0x6a, 0x8b, 0xe7, 0xca, 0xa8, + 0x56, 0xe3, 0x42, 0x40, 0x99, 0x3b, 0x72, 0xdc, 0x6b, 0x3e, 0x86, 0x13, 0x3c, 0x14, 0x9a, 0xe7, + 0x89, 0x22, 0x83, 0x19, 0x9a, 0x8f, 0xb6, 0x3e, 0x85, 0xb7, 0x78, 0xcc, 0xa5, 0x2c, 0x94, 0xb5, + 0xbb, 0x34, 0x97, 0xea, 0x9d, 0x9c, 0x74, 0xde, 0x85, 0x2f, 0xd7, 0x6d, 0xf7, 0x38, 0xf8, 0xfc, + 0x9a, 0x06, 0xab, 0xa7, 0x9f, 0x9a, 0xa2, 0x7d, 0x4d, 0xd1, 0x5f, 0x4d, 0xd1, 0x47, 0x43, 0x83, + 0x7d, 0x43, 0x83, 0xdf, 0x86, 0x06, 0x2f, 0x77, 0x49, 0xea, 0x74, 0x19, 0x47, 0x02, 0x32, 0xe6, + 0xef, 0xd2, 0x3f, 0xf7, 0x56, 0xbe, 0x32, 0x51, 0x54, 0xc6, 0x01, 0xd3, 0x32, 0x1e, 0x76, 0xcb, + 0x3e, 0xfc, 0x07, 0x00, 0x00, 0xff, 0xff, 0x1d, 0x56, 0x0b, 0xa8, 0x3d, 0x01, 0x00, 0x00, +} + +func (m *BIP44Params) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *BIP44Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BIP44Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.AddressIndex != 0 { + i = encodeVarintHd(dAtA, i, uint64(m.AddressIndex)) + i-- + dAtA[i] = 0x28 + } + if m.Change { + i-- + if m.Change { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } + if m.Account != 0 { + i = encodeVarintHd(dAtA, i, uint64(m.Account)) + i-- + dAtA[i] = 0x18 + } + if m.CoinType != 0 { + i = encodeVarintHd(dAtA, i, uint64(m.CoinType)) + i-- + dAtA[i] = 0x10 + } + if m.Purpose != 0 { + i = encodeVarintHd(dAtA, i, uint64(m.Purpose)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintHd(dAtA []byte, offset int, v uint64) int { + offset -= sovHd(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *BIP44Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Purpose != 0 { + n += 1 + sovHd(uint64(m.Purpose)) + } + if m.CoinType != 0 { + n += 1 + sovHd(uint64(m.CoinType)) + } + if m.Account != 0 { + n += 1 + sovHd(uint64(m.Account)) + } + if m.Change { + n += 2 + } + if m.AddressIndex != 0 { + n += 1 + sovHd(uint64(m.AddressIndex)) + } + return n +} + +func sovHd(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozHd(x uint64) (n int) { + return sovHd(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *BIP44Params) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHd + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: BIP44Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BIP44Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Purpose", wireType) + } + m.Purpose = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHd + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Purpose |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CoinType", wireType) + } + m.CoinType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHd + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CoinType |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Account", wireType) + } + m.Account = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHd + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Account |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Change", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHd + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Change = bool(v != 0) + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AddressIndex", wireType) + } + m.AddressIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHd + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.AddressIndex |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipHd(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthHd + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthHd + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipHd(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowHd + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowHd + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowHd + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthHd + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupHd + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthHd + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthHd = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowHd = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupHd = fmt.Errorf("proto: unexpected end of group") +) diff --git a/crypto/hd/hdpath.go b/crypto/hd/hdpath.go index 04469d730591..d97ff3e551c5 100644 --- a/crypto/hd/hdpath.go +++ b/crypto/hd/hdpath.go @@ -12,18 +12,6 @@ import ( "github.com/btcsuite/btcd/btcec" ) -// BIP44Params wraps BIP 44 params (5 level BIP 32 path). -// To receive a canonical string representation ala -// m / purpose' / coinType' / account' / change / addressIndex -// call String() on a BIP44Params instance. -type BIP44Params struct { - Purpose uint32 `json:"purpose"` - CoinType uint32 `json:"coinType"` - Account uint32 `json:"account"` - Change bool `json:"change"` - AddressIndex uint32 `json:"addressIndex"` -} - // NewParams creates a BIP 44 parameter object from the params: // m / purpose' / coinType' / account' / change / addressIndex func NewParams(purpose, coinType, account uint32, change bool, addressIdx uint32) *BIP44Params { diff --git a/crypto/keyring/keyring.go b/crypto/keyring/keyring.go index d3220b5b43ef..ef1f9e3080d0 100644 --- a/crypto/keyring/keyring.go +++ b/crypto/keyring/keyring.go @@ -352,7 +352,7 @@ func (ks keystore) SaveLedgerKey(uid string, algo SignatureAlgo, hrp string, coi hdPath := hd.NewFundraiserParams(account, coinType, index) - priv, _, err := ledger.NewPrivKeySecp256k1(*hdPath, hrp) + priv, _, err := ledger.NewPrivKeySecp256k1(hdPath, hrp) if err != nil { return nil, err } @@ -546,7 +546,7 @@ func SignWithLedger(info Info, msg []byte) (sig []byte, pub types.PubKey, err er return } - priv, err := ledger.NewPrivKeySecp256k1Unsafe(*path) + priv, err := ledger.NewPrivKeySecp256k1Unsafe(path) if err != nil { return } diff --git a/crypto/keys/ed25519/ed25519.go b/crypto/keys/ed25519/ed25519.go index 17368c4b12ff..0a3c36547aa8 100644 --- a/crypto/keys/ed25519/ed25519.go +++ b/crypto/keys/ed25519/ed25519.go @@ -77,7 +77,7 @@ func (privKey *PrivKey) PubKey() cryptotypes.PubKey { // Equals - you probably don't need to use this. // Runs in constant time based on length of the keys. -func (privKey *PrivKey) Equals(other cryptotypes.LedgerPrivKey) bool { +func (privKey *PrivKey) Equals(other cryptotypes.PrivKey) bool { if privKey.Type() != other.Type() { return false } diff --git a/crypto/keys/secp256k1/secp256k1.go b/crypto/keys/secp256k1/secp256k1.go index eebe72a45242..4907415c8702 100644 --- a/crypto/keys/secp256k1/secp256k1.go +++ b/crypto/keys/secp256k1/secp256k1.go @@ -42,7 +42,7 @@ func (privKey *PrivKey) PubKey() cryptotypes.PubKey { // Equals - you probably don't need to use this. // Runs in constant time based on length of the -func (privKey *PrivKey) Equals(other cryptotypes.LedgerPrivKey) bool { +func (privKey *PrivKey) Equals(other cryptotypes.PrivKey) bool { return privKey.Type() == other.Type() && subtle.ConstantTimeCompare(privKey.Bytes(), other.Bytes()) == 1 } diff --git a/crypto/ledger/amino.go b/crypto/ledger/amino.go deleted file mode 100644 index 0e717a9604f0..000000000000 --- a/crypto/ledger/amino.go +++ /dev/null @@ -1,19 +0,0 @@ -package ledger - -import ( - "github.com/cosmos/cosmos-sdk/codec" - cryptoAmino "github.com/cosmos/cosmos-sdk/crypto/codec" -) - -var cdc = codec.NewLegacyAmino() - -func init() { - RegisterAmino(cdc) - cryptoAmino.RegisterCrypto(cdc) -} - -// RegisterAmino registers all go-crypto related types in the given (amino) codec. -func RegisterAmino(cdc *codec.LegacyAmino) { - cdc.RegisterConcrete(PrivKeyLedgerSecp256k1{}, - "tendermint/PrivKeyLedgerSecp256k1", nil) -} diff --git a/crypto/ledger/encode_test.go b/crypto/ledger/encode_test.go index 447891fde768..914f87593ead 100644 --- a/crypto/ledger/encode_test.go +++ b/crypto/ledger/encode_test.go @@ -1,63 +1,46 @@ -package ledger +package ledger_test import ( - "os" "testing" + proto "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/require" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + hd "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/crypto/ledger" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" ) type byter interface { Bytes() []byte } -func checkAminoJSON(t *testing.T, src interface{}, dst interface{}, isNil bool) { +func checkProtoJSON(t *testing.T, src proto.Message, dst proto.Message) { + cdc := simapp.MakeTestEncodingConfig().Marshaler + // Marshal to JSON bytes. js, err := cdc.MarshalJSON(src) require.Nil(t, err, "%+v", err) - if isNil { - require.Equal(t, string(js), `null`) - } else { - require.Contains(t, string(js), `"type":`) - require.Contains(t, string(js), `"value":`) - } + require.Contains(t, string(js), `"A0/vnNfExjWI07A/61KBudIyy6NNbz1xruWSEf+/4f6H"`) // The pubkey bytes as base64. // Unmarshal. err = cdc.UnmarshalJSON(js, dst) require.Nil(t, err, "%+v", err) } -// nolint: govet -func ExamplePrintRegisteredTypes() { - cdc.PrintTypes(os.Stdout) - // | Type | Name | Prefix | Length | Notes | - // | ---- | ---- | ------ | ----- | ------ | - // | PrivKeyLedgerSecp256k1 | tendermint/PrivKeyLedgerSecp256k1 | 0x10CAB393 | variable | | - // | PubKey | tendermint/PubKeyEd25519 | 0x1624DE64 | variable | | - // | PubKey | tendermint/PubKeySr25519 | 0x0DFB1005 | variable | | - // | PubKey | tendermint/PubKeySecp256k1 | 0xEB5AE987 | variable | | - // | PubKeyMultisigThreshold | tendermint/PubKeyMultisigThreshold | 0x22C1F7E2 | variable | | - // | PrivKey | tendermint/PrivKeyEd25519 | 0xA3288910 | variable | | - // | PrivKey | tendermint/PrivKeySr25519 | 0x2F82D78B | variable | | - // | PrivKey | tendermint/PrivKeySecp256k1 | 0xE1B0F79B | variable | | -} - -func TestNilEncodings(t *testing.T) { - - // Check nil Signature. - var a, b []byte - checkAminoJSON(t, &a, &b, true) - require.EqualValues(t, a, b) - - // Check nil PubKey. - var c, d cryptotypes.PubKey - checkAminoJSON(t, &c, &d, true) - require.EqualValues(t, c, d) - - // Check nil PrivKey. - var e, f cryptotypes.PrivKey - checkAminoJSON(t, &e, &f, true) - require.EqualValues(t, e, f) - +func TestEncodings(t *testing.T) { + // Check PrivKey. + path := hd.NewFundraiserParams(0, sdk.CoinType, 0) + priv1, err := ledger.NewPrivKeySecp256k1Unsafe(path) + require.NoError(t, err) + var priv2 ledger.PrivKey + checkProtoJSON(t, priv1, &priv2) + require.EqualValues(t, priv1, &priv2) + + // Check PubKey. + pub1 := priv1.PubKey() + var pub2 secp256k1.PubKey + checkProtoJSON(t, pub1, &pub2) + require.EqualValues(t, pub1, &pub2) } diff --git a/crypto/ledger/keys.pb.go b/crypto/ledger/keys.pb.go new file mode 100644 index 000000000000..fee0208ef0b3 --- /dev/null +++ b/crypto/ledger/keys.pb.go @@ -0,0 +1,393 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: cosmos/crypto/ledger/secp256k1/v1beta1/keys.proto + +package ledger + +import ( + fmt "fmt" + hd "github.com/cosmos/cosmos-sdk/crypto/hd" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// PrivKey defines a Ledger hardware wallet secp256k1 private key. +type PrivKey struct { + // path is the derivation path used to generate the private key. + Path *hd.BIP44Params `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` + // cached_pub_key is an utility field used to cache the key's public key, + // so that we don't need to query the Ledger each time we need to access + // the public key. + CachedPubKey []byte `protobuf:"bytes,2,opt,name=cached_pub_key,json=cachedPubKey,proto3" json:"cached_pub_key,omitempty"` +} + +func (m *PrivKey) Reset() { *m = PrivKey{} } +func (m *PrivKey) String() string { return proto.CompactTextString(m) } +func (*PrivKey) ProtoMessage() {} +func (*PrivKey) Descriptor() ([]byte, []int) { + return fileDescriptor_88e789035e83c74f, []int{0} +} +func (m *PrivKey) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PrivKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PrivKey.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PrivKey) XXX_Merge(src proto.Message) { + xxx_messageInfo_PrivKey.Merge(m, src) +} +func (m *PrivKey) XXX_Size() int { + return m.Size() +} +func (m *PrivKey) XXX_DiscardUnknown() { + xxx_messageInfo_PrivKey.DiscardUnknown(m) +} + +var xxx_messageInfo_PrivKey proto.InternalMessageInfo + +func (m *PrivKey) GetPath() *hd.BIP44Params { + if m != nil { + return m.Path + } + return nil +} + +func (m *PrivKey) GetCachedPubKey() []byte { + if m != nil { + return m.CachedPubKey + } + return nil +} + +func init() { + proto.RegisterType((*PrivKey)(nil), "cosmos.crypto.ledger.secp256k1.v1beta1.PrivKey") +} + +func init() { + proto.RegisterFile("cosmos/crypto/ledger/secp256k1/v1beta1/keys.proto", fileDescriptor_88e789035e83c74f) +} + +var fileDescriptor_88e789035e83c74f = []byte{ + // 251 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x32, 0x4c, 0xce, 0x2f, 0xce, + 0xcd, 0x2f, 0xd6, 0x4f, 0x2e, 0xaa, 0x2c, 0x28, 0xc9, 0xd7, 0xcf, 0x49, 0x4d, 0x49, 0x4f, 0x2d, + 0xd2, 0x2f, 0x4e, 0x4d, 0x2e, 0x30, 0x32, 0x35, 0xcb, 0x36, 0xd4, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, + 0x49, 0x34, 0xd4, 0xcf, 0x4e, 0xad, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x52, 0x83, + 0x68, 0xd1, 0x83, 0x68, 0xd1, 0x83, 0x68, 0xd1, 0x83, 0x6b, 0xd1, 0x83, 0x6a, 0x91, 0x92, 0x87, + 0x1a, 0x9d, 0x94, 0x58, 0x9c, 0xaa, 0x9f, 0x91, 0x02, 0x37, 0x2a, 0x23, 0x05, 0x62, 0x90, 0x52, + 0x06, 0x17, 0x7b, 0x40, 0x51, 0x66, 0x99, 0x77, 0x6a, 0xa5, 0x90, 0x39, 0x17, 0x4b, 0x41, 0x62, + 0x49, 0x86, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0xb7, 0x91, 0xb2, 0x1e, 0xd4, 0x0a, 0x90, 0x56, 0xbd, + 0x8c, 0x14, 0x98, 0x91, 0x7a, 0x4e, 0x9e, 0x01, 0x26, 0x26, 0x01, 0x89, 0x45, 0x89, 0xb9, 0xc5, + 0x41, 0x60, 0x0d, 0x42, 0x2a, 0x5c, 0x7c, 0xc9, 0x89, 0xc9, 0x19, 0xa9, 0x29, 0xf1, 0x05, 0xa5, + 0x49, 0xf1, 0xd9, 0xa9, 0x95, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0x3c, 0x41, 0x3c, 0x10, 0xd1, 0x80, + 0xd2, 0x24, 0xef, 0xd4, 0x4a, 0x27, 0x97, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, + 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, + 0x88, 0xd2, 0x4a, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x87, 0x05, 0x05, + 0x98, 0xd2, 0x2d, 0x4e, 0xc9, 0x46, 0x0d, 0x95, 0x24, 0x36, 0xb0, 0xb3, 0x8d, 0x01, 0x01, 0x00, + 0x00, 0xff, 0xff, 0x7b, 0x15, 0x09, 0xe9, 0x34, 0x01, 0x00, 0x00, +} + +func (m *PrivKey) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PrivKey) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PrivKey) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.CachedPubKey) > 0 { + i -= len(m.CachedPubKey) + copy(dAtA[i:], m.CachedPubKey) + i = encodeVarintKeys(dAtA, i, uint64(len(m.CachedPubKey))) + i-- + dAtA[i] = 0x12 + } + if m.Path != nil { + { + size, err := m.Path.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintKeys(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintKeys(dAtA []byte, offset int, v uint64) int { + offset -= sovKeys(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *PrivKey) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Path != nil { + l = m.Path.Size() + n += 1 + l + sovKeys(uint64(l)) + } + l = len(m.CachedPubKey) + if l > 0 { + n += 1 + l + sovKeys(uint64(l)) + } + return n +} + +func sovKeys(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozKeys(x uint64) (n int) { + return sovKeys(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *PrivKey) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowKeys + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PrivKey: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PrivKey: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Path", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowKeys + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthKeys + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthKeys + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Path == nil { + m.Path = &hd.BIP44Params{} + } + if err := m.Path.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CachedPubKey", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowKeys + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthKeys + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthKeys + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CachedPubKey = append(m.CachedPubKey[:0], dAtA[iNdEx:postIndex]...) + if m.CachedPubKey == nil { + m.CachedPubKey = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipKeys(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthKeys + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthKeys + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipKeys(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowKeys + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowKeys + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowKeys + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthKeys + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupKeys + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthKeys + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthKeys = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowKeys = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupKeys = fmt.Errorf("proto: unexpected end of group") +) diff --git a/crypto/ledger/ledger_secp256k1.go b/crypto/ledger/ledger_secp256k1.go index 659181d30648..cdb406daeab8 100644 --- a/crypto/ledger/ledger_secp256k1.go +++ b/crypto/ledger/ledger_secp256k1.go @@ -5,6 +5,7 @@ import ( "os" "github.com/btcsuite/btcd/btcec" + proto "github.com/gogo/protobuf/proto" "github.com/pkg/errors" tmbtcec "github.com/tendermint/btcd/btcec" @@ -36,16 +37,6 @@ type ( // Signs a message (requires user confirmation) SignSECP256K1([]uint32, []byte) ([]byte, error) } - - // PrivKeyLedgerSecp256k1 implements PrivKey, calling the ledger nano we - // cache the PubKey from the first call to use it later. - PrivKeyLedgerSecp256k1 struct { - // CachedPubKey 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 types.PubKey - Path hd.BIP44Params - } ) // NewPrivKeySecp256k1Unsafe will generate a new key and store the public key for later use. @@ -53,7 +44,7 @@ type ( // 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 NewPrivKeySecp256k1 -func NewPrivKeySecp256k1Unsafe(path hd.BIP44Params) (types.LedgerPrivKey, error) { +func NewPrivKeySecp256k1Unsafe(path *hd.BIP44Params) (types.PrivKey, error) { device, err := getDevice() if err != nil { return nil, err @@ -65,12 +56,12 @@ func NewPrivKeySecp256k1Unsafe(path hd.BIP44Params) (types.LedgerPrivKey, error) return nil, err } - return PrivKeyLedgerSecp256k1{pubKey, path}, nil + return &PrivKey{CachedPubKey: pubKey.Bytes(), Path: path}, nil } // NewPrivKeySecp256k1 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 NewPrivKeySecp256k1(path hd.BIP44Params, hrp string) (types.LedgerPrivKey, string, error) { +func NewPrivKeySecp256k1(path *hd.BIP44Params, hrp string) (types.PrivKey, string, error) { device, err := getDevice() if err != nil { return nil, "", err @@ -82,16 +73,18 @@ func NewPrivKeySecp256k1(path hd.BIP44Params, hrp string) (types.LedgerPrivKey, return nil, "", err } - return PrivKeyLedgerSecp256k1{pubKey, path}, addr, nil + return &PrivKey{CachedPubKey: pubKey.Bytes(), Path: path}, addr, nil } +var _ types.PrivKey = &PrivKey{} // Assert interface implementation. + // PubKey returns the cached public key. -func (pkl PrivKeyLedgerSecp256k1) PubKey() types.PubKey { - return pkl.CachedPubKey +func (pkl *PrivKey) PubKey() types.PubKey { + return &secp256k1.PubKey{Key: pkl.CachedPubKey} } // Sign returns a secp256k1 signature for the corresponding message -func (pkl PrivKeyLedgerSecp256k1) Sign(message []byte) ([]byte, error) { +func (pkl *PrivKey) Sign(message []byte) ([]byte, error) { device, err := getDevice() if err != nil { return nil, err @@ -102,7 +95,7 @@ func (pkl PrivKeyLedgerSecp256k1) Sign(message []byte) ([]byte, error) { } // ShowAddress triggers a ledger device to show the corresponding address. -func ShowAddress(path hd.BIP44Params, expectedPubKey types.PubKey, +func ShowAddress(path *hd.BIP44Params, expectedPubKey types.PubKey, accountAddressPrefix string) error { device, err := getDevice() if err != nil { @@ -133,35 +126,37 @@ func ShowAddress(path hd.BIP44Params, expectedPubKey types.PubKey, // ValidateKey allows us to verify the sanity of a public key after loading it // from disk. -func (pkl PrivKeyLedgerSecp256k1) ValidateKey() error { +func (pkl PrivKey) ValidateKey() error { device, err := getDevice() if err != nil { return err } defer warnIfErrors(device.Close) - return validateKey(device, pkl) + return validateKey(device, &pkl) } -// AssertIsPrivKeyInner implements the PrivKey interface. It performs a no-op. -func (pkl *PrivKeyLedgerSecp256k1) AssertIsPrivKeyInner() {} - // Bytes implements the PrivKey interface. It stores the cached public key so // we can verify the same key when we reconnect to a ledger. -func (pkl PrivKeyLedgerSecp256k1) Bytes() []byte { - return cdc.MustMarshalBinaryBare(pkl) +func (pkl *PrivKey) Bytes() []byte { + bz, err := proto.Marshal(pkl) + if err != nil { + panic(err) + } + + return bz } // Equals implements the PrivKey interface. It makes sure two private keys // refer to the same public key. -func (pkl PrivKeyLedgerSecp256k1) Equals(other types.LedgerPrivKey) bool { - if otherKey, ok := other.(PrivKeyLedgerSecp256k1); ok { - return pkl.CachedPubKey.Equals(otherKey.CachedPubKey) +func (pkl *PrivKey) Equals(other types.PrivKey) bool { + if otherKey, ok := other.(*PrivKey); ok { + return pkl.PubKey().Equals(otherKey.PubKey()) } return false } -func (pkl PrivKeyLedgerSecp256k1) Type() string { return "PrivKeyLedgerSecp256k1" } +func (pkl *PrivKey) Type() string { return "PrivKey" } // warnIfErrors wraps a function and writes a warning to stderr. This is required // to avoid ignoring errors when defer is used. Using defer may result in linter warnings. @@ -193,14 +188,14 @@ func getDevice() (SECP256K1, error) { return device, nil } -func validateKey(device SECP256K1, pkl PrivKeyLedgerSecp256k1) error { +func validateKey(device SECP256K1, pkl *PrivKey) error { pub, err := getPubKeyUnsafe(device, pkl.Path) if err != nil { return err } // verify this matches cached address - if !pub.Equals(pkl.CachedPubKey) { + if !pub.Equals(pkl.PubKey()) { return fmt.Errorf("cached key does not match retrieved key") } @@ -212,7 +207,7 @@ func validateKey(device SECP256K1, pkl PrivKeyLedgerSecp256k1) error { // Communication is checked on NewPrivKeyLedger and PrivKeyFromBytes, returning // an error, so this should only trigger if the private key is held in memory // for a while before use. -func sign(device SECP256K1, pkl PrivKeyLedgerSecp256k1, msg []byte) ([]byte, error) { +func sign(device SECP256K1, pkl *PrivKey, msg []byte) ([]byte, error) { err := validateKey(device, pkl) if err != nil { return nil, err @@ -234,7 +229,7 @@ func sign(device SECP256K1, pkl PrivKeyLedgerSecp256k1, msg []byte) ([]byte, err // // 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 getPubKeyUnsafe(device SECP256K1, path hd.BIP44Params) (types.PubKey, error) { +func getPubKeyUnsafe(device SECP256K1, path *hd.BIP44Params) (types.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) @@ -258,7 +253,7 @@ func getPubKeyUnsafe(device SECP256K1, path hd.BIP44Params) (types.PubKey, error // // 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 SECP256K1, path hd.BIP44Params, hrp string) (types.PubKey, string, error) { +func getPubKeyAddrSafe(device SECP256K1, path *hd.BIP44Params, hrp string) (types.PubKey, string, error) { publicKey, addr, err := device.GetAddressPubKeySECP256K1(path.DerivationPath(), hrp) if err != nil { return nil, "", fmt.Errorf("address %s rejected", addr) diff --git a/crypto/ledger/ledger_test.go b/crypto/ledger/ledger_test.go index 5fe9da8f55f3..59ee1aac8cdb 100644 --- a/crypto/ledger/ledger_test.go +++ b/crypto/ledger/ledger_test.go @@ -1,13 +1,15 @@ -package ledger +package ledger_test import ( "fmt" "testing" + proto "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/require" - cryptoAmino "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/crypto/ledger" "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/testutil" sdk "github.com/cosmos/cosmos-sdk/types" @@ -16,19 +18,19 @@ import ( func TestErrorHandling(t *testing.T) { // first, try to generate a key, must return an error // (no panic) - path := *hd.NewParams(44, 555, 0, false, 0) - _, err := NewPrivKeySecp256k1Unsafe(path) + path := hd.NewParams(44, 555, 0, false, 0) + _, err := ledger.NewPrivKeySecp256k1Unsafe(path) require.Error(t, err) } func TestPublicKeyUnsafe(t *testing.T) { - path := *hd.NewFundraiserParams(0, sdk.CoinType, 0) - priv, err := NewPrivKeySecp256k1Unsafe(path) + path := hd.NewFundraiserParams(0, sdk.CoinType, 0) + priv, err := ledger.NewPrivKeySecp256k1Unsafe(path) require.NoError(t, err) require.NotNil(t, priv) - require.Equal(t, "eb5ae98721034fef9cd7c4c63588d3b03feb5281b9d232cba34d6f3d71aee59211ffbfe1fe87", - fmt.Sprintf("%x", cdc.Amino.MustMarshalBinaryBare(priv.PubKey())), + require.Equal(t, "034fef9cd7c4c63588d3b03feb5281b9d232cba34d6f3d71aee59211ffbfe1fe87", + fmt.Sprintf("%x", priv.PubKey().Bytes()), "Is your device using test mnemonic: %s ?", testutil.TestMnemonic) pubKeyAddr, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, priv.PubKey()) @@ -57,21 +59,20 @@ func TestPublicKeyUnsafeHDPath(t *testing.T) { const numIters = 10 - privKeys := make([]types.LedgerPrivKey, numIters) + privKeys := make([]types.PrivKey, numIters) // Check with device for i := uint32(0); i < 10; i++ { - path := *hd.NewFundraiserParams(0, sdk.CoinType, i) + path := hd.NewFundraiserParams(0, sdk.CoinType, i) t.Logf("Checking keys at %v\n", path) - priv, err := NewPrivKeySecp256k1Unsafe(path) + priv, err := ledger.NewPrivKeySecp256k1Unsafe(path) require.NoError(t, err) require.NotNil(t, priv) // Check other methods - tmp := priv.(PrivKeyLedgerSecp256k1) + tmp := priv.(*ledger.PrivKey) require.NoError(t, tmp.ValidateKey()) - (&tmp).AssertIsPrivKeyInner() pubKeyAddr, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, priv.PubKey()) require.NoError(t, err) @@ -82,7 +83,7 @@ func TestPublicKeyUnsafeHDPath(t *testing.T) { // Store and restore serializedPk := priv.Bytes() require.NotNil(t, serializedPk) - require.True(t, len(serializedPk) >= 50) + require.True(t, len(serializedPk) >= 40) privKeys[i] = priv } @@ -97,16 +98,16 @@ func TestPublicKeyUnsafeHDPath(t *testing.T) { } func TestPublicKeySafe(t *testing.T) { - path := *hd.NewFundraiserParams(0, sdk.CoinType, 0) - priv, addr, err := NewPrivKeySecp256k1(path, "cosmos") + path := hd.NewFundraiserParams(0, sdk.CoinType, 0) + priv, addr, err := ledger.NewPrivKeySecp256k1(path, "cosmos") require.NoError(t, err) require.NotNil(t, priv) - require.Nil(t, ShowAddress(path, priv.PubKey(), sdk.GetConfig().GetBech32AccountAddrPrefix())) + require.Nil(t, ledger.ShowAddress(path, priv.PubKey(), sdk.GetConfig().GetBech32AccountAddrPrefix())) - require.Equal(t, "eb5ae98721034fef9cd7c4c63588d3b03feb5281b9d232cba34d6f3d71aee59211ffbfe1fe87", - fmt.Sprintf("%x", cdc.Amino.MustMarshalBinaryBare(priv.PubKey())), + require.Equal(t, "034fef9cd7c4c63588d3b03feb5281b9d232cba34d6f3d71aee59211ffbfe1fe87", + fmt.Sprintf("%x", priv.PubKey().Bytes()), "Is your device using test mnemonic: %s ?", testutil.TestMnemonic) pubKeyAddr, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, priv.PubKey()) @@ -150,14 +151,14 @@ func TestPublicKeyHDPath(t *testing.T) { const numIters = 10 - privKeys := make([]types.LedgerPrivKey, numIters) + privKeys := make([]types.PrivKey, numIters) // Check with device for i := uint32(0); i < 10; i++ { - path := *hd.NewFundraiserParams(0, sdk.CoinType, i) + path := hd.NewFundraiserParams(0, sdk.CoinType, i) t.Logf("Checking keys at %s\n", path) - priv, addr, err := NewPrivKeySecp256k1(path, "cosmos") + priv, addr, err := ledger.NewPrivKeySecp256k1(path, "cosmos") require.NoError(t, err) require.NotNil(t, addr) require.NotNil(t, priv) @@ -169,9 +170,8 @@ func TestPublicKeyHDPath(t *testing.T) { "Is your device using test mnemonic: %s ?", testutil.TestMnemonic) // Check other methods - tmp := priv.(PrivKeyLedgerSecp256k1) + tmp := priv.(*ledger.PrivKey) require.NoError(t, tmp.ValidateKey()) - (&tmp).AssertIsPrivKeyInner() pubKeyAddr, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, priv.PubKey()) require.NoError(t, err) @@ -182,7 +182,7 @@ func TestPublicKeyHDPath(t *testing.T) { // Store and restore serializedPk := priv.Bytes() require.NotNil(t, serializedPk) - require.True(t, len(serializedPk) >= 50) + require.True(t, len(serializedPk) >= 40) privKeys[i] = priv } @@ -208,10 +208,10 @@ func TestSignaturesHD(t *testing.T) { for account := uint32(0); account < 100; account += 30 { msg := getFakeTx(account) - path := *hd.NewFundraiserParams(account, sdk.CoinType, account/5) + path := hd.NewFundraiserParams(account, sdk.CoinType, account/5) t.Logf("Checking signature at %v --- PLEASE REVIEW AND ACCEPT IN THE DEVICE\n", path) - priv, err := NewPrivKeySecp256k1Unsafe(path) + priv, err := ledger.NewPrivKeySecp256k1Unsafe(path) require.NoError(t, err) pub := priv.PubKey() @@ -225,8 +225,8 @@ func TestSignaturesHD(t *testing.T) { func TestRealDeviceSecp256k1(t *testing.T) { msg := getFakeTx(50) - path := *hd.NewFundraiserParams(0, sdk.CoinType, 0) - priv, err := NewPrivKeySecp256k1Unsafe(path) + path := hd.NewFundraiserParams(0, sdk.CoinType, 0) + priv, err := ledger.NewPrivKeySecp256k1Unsafe(path) require.NoError(t, err) pub := priv.PubKey() @@ -237,12 +237,14 @@ func TestRealDeviceSecp256k1(t *testing.T) { require.True(t, valid) // now, let's serialize the public key and make sure it still works - bs := cdc.Amino.MustMarshalBinaryBare(priv.PubKey()) - pub2, err := cryptoAmino.PubKeyFromBytes(bs) + bs, err := proto.Marshal(priv.PubKey()) + require.NoError(t, err) + var pub2 secp256k1.PubKey + err = proto.Unmarshal(bs, &pub2) require.Nil(t, err, "%+v", err) // make sure we get the same pubkey when we load from disk - require.Equal(t, pub, pub2) + require.Equal(t, pub, &pub2) // signing with the loaded key should match the original pubkey sig, err = priv.Sign(msg) @@ -251,8 +253,10 @@ func TestRealDeviceSecp256k1(t *testing.T) { require.True(t, valid) // make sure pubkeys serialize properly as well - bs = cdc.Amino.MustMarshalBinaryBare(pub) - bpub, err := cryptoAmino.PubKeyFromBytes(bs) + bs, err = proto.Marshal(pub) + require.NoError(t, err) + var bpub secp256k1.PubKey + err = proto.Unmarshal(bs, &bpub) require.NoError(t, err) - require.Equal(t, pub, bpub) + require.Equal(t, pub, &bpub) } diff --git a/crypto/types/types.go b/crypto/types/types.go index eccdba73813d..228a4c61a811 100644 --- a/crypto/types/types.go +++ b/crypto/types/types.go @@ -16,28 +16,17 @@ type PubKey interface { Type() string } -// LedgerPrivKey defines a private key that is not a proto message. For now, -// LedgerSecp256k1 keys are not converted to proto.Message yet, this is why -// they use LedgerPrivKey instead of PrivKey. All other keys must use PrivKey -// instead of LedgerPrivKey. -// TODO https://github.com/cosmos/cosmos-sdk/issues/7357. -type LedgerPrivKey interface { +// PrivKey defines a private key and extends proto.Message. +type PrivKey interface { + proto.Message + Bytes() []byte Sign(msg []byte) ([]byte, error) PubKey() PubKey - Equals(LedgerPrivKey) bool + Equals(PrivKey) bool Type() string } -// PrivKey defines a private key and extends proto.Message. For now, it extends -// LedgerPrivKey (see godoc for LedgerPrivKey). Ultimately, we should remove -// LedgerPrivKey and add its methods here directly. -// TODO https://github.com/cosmos/cosmos-sdk/issues/7357. -type PrivKey interface { - proto.Message - LedgerPrivKey -} - type ( Address = tmcrypto.Address ) diff --git a/proto/cosmos/base/hd/v1beta1/hd.proto b/proto/cosmos/base/hd/v1beta1/hd.proto new file mode 100644 index 000000000000..1d4439142e0d --- /dev/null +++ b/proto/cosmos/base/hd/v1beta1/hd.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; +package cosmos.base.hd.v1beta1; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/crypto/hd"; + +// BIP44Params wraps BIP 44 params (5 level BIP 32 path). +// To receive a canonical string representation ala +// m / purpose' / coinType' / account' / change / addressIndex +// call String() on a BIP44Params instance. +message BIP44Params { + option (gogoproto.goproto_stringer) = false; + + uint32 purpose = 1; + uint32 coin_type = 2; + uint32 account = 3; + bool change = 4; + uint32 address_index = 5; +} diff --git a/proto/cosmos/crypto/ledger/secp256k1/v1beta1/keys.proto b/proto/cosmos/crypto/ledger/secp256k1/v1beta1/keys.proto new file mode 100644 index 000000000000..a86354d42025 --- /dev/null +++ b/proto/cosmos/crypto/ledger/secp256k1/v1beta1/keys.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; +package cosmos.crypto.ledger.secp256k1.v1beta1; + +option go_package = "github.com/cosmos/cosmos-sdk/crypto/ledger"; + +import "cosmos/base/hd/v1beta1/hd.proto"; + +// PrivKey defines a Ledger hardware wallet secp256k1 private key. +message PrivKey { + // path is the derivation path used to generate the private key. + cosmos.base.hd.v1beta1.BIP44Params path = 1; + + // cached_pub_key is an utility field used to cache the key's public key, + // so that we don't need to query the Ledger each time we need to access + // the public key. + bytes cached_pub_key = 2; +}