From 78f7d46817a86a4c5821c9757e76e581cd5b6944 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 21 Jan 2021 16:39:59 +0100 Subject: [PATCH 01/70] Optimize secp256k1 hashing --- crypto/keys/secp256k1/keys.pb.go | 5 +++-- crypto/keys/secp256k1/secp256k1.go | 7 ++----- types/errors/handle.go | 12 ++++++++++++ x/auth/types/account.go | 1 + 4 files changed, 18 insertions(+), 7 deletions(-) create mode 100644 types/errors/handle.go diff --git a/crypto/keys/secp256k1/keys.pb.go b/crypto/keys/secp256k1/keys.pb.go index afcbab54b05d..5329805b85fe 100644 --- a/crypto/keys/secp256k1/keys.pb.go +++ b/crypto/keys/secp256k1/keys.pb.go @@ -5,11 +5,12 @@ package secp256k1 import ( fmt "fmt" - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" io "io" math "math" math_bits "math/bits" + + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" ) // Reference imports to suppress errors if they are not otherwise used. diff --git a/crypto/keys/secp256k1/secp256k1.go b/crypto/keys/secp256k1/secp256k1.go index eebe72a45242..231a895a6103 100644 --- a/crypto/keys/secp256k1/secp256k1.go +++ b/crypto/keys/secp256k1/secp256k1.go @@ -151,12 +151,9 @@ func (pubKey *PubKey) Address() crypto.Address { panic("length of pubkey is incorrect") } - hasherSHA256 := sha256.New() - hasherSHA256.Write(pubKey.Key) // does not error - sha := hasherSHA256.Sum(nil) - + sha := sha256.Sum256(pubKey.Key) hasherRIPEMD160 := ripemd160.New() - hasherRIPEMD160.Write(sha) // does not error + hasherRIPEMD160.Write(sha[:]) // does not error return crypto.Address(hasherRIPEMD160.Sum(nil)) } diff --git a/types/errors/handle.go b/types/errors/handle.go new file mode 100644 index 000000000000..a0b7c86771a6 --- /dev/null +++ b/types/errors/handle.go @@ -0,0 +1,12 @@ +package errors + +import "fmt" + +// Panic panics on error +// Should be only used with interface methods, which require return error, but the +// error is always nil +func Panic(err) { + if err != nil { + panic(fmt.Errorf("Logic error - this should never happen. %w", err)) + } +} diff --git a/x/auth/types/account.go b/x/auth/types/account.go index eb9939ffce10..653f89bcac4a 100644 --- a/x/auth/types/account.go +++ b/x/auth/types/account.go @@ -48,6 +48,7 @@ func ProtoBaseAccount() AccountI { } // NewBaseAccountWithAddress - returns a new base account with a given address +// leaving AccountNumber and Sequence to zero. func NewBaseAccountWithAddress(addr sdk.AccAddress) *BaseAccount { return &BaseAccount{ Address: addr.String(), From d9d677b2929561c94112d8175673990c723b15fe Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Fri, 22 Jan 2021 15:41:04 +0100 Subject: [PATCH 02/70] Add ADR-028 related functions --- types/address/README.md | 7 +++++ types/address/hash.go | 68 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 types/address/README.md create mode 100644 types/address/hash.go diff --git a/types/address/README.md b/types/address/README.md new file mode 100644 index 000000000000..ebc647ec0f2b --- /dev/null +++ b/types/address/README.md @@ -0,0 +1,7 @@ +# Account + +This package defines Cosmos SDK address related functions. + +## References + ++ [ADR-028](../../docs/architecture/adr-028-public-key-addresses.md) diff --git a/types/address/hash.go b/types/address/hash.go new file mode 100644 index 000000000000..6d980c842ad8 --- /dev/null +++ b/types/address/hash.go @@ -0,0 +1,68 @@ +package address + +import ( + "crypto/sha256" + "reflect" + "sort" + "unsafe" + + "github.com/cosmos/cosmos-sdk/types/errors" +) + +/* + TODO + + I still need to think how to organize it. + Ideally, I wanted to Addressable Account abstraction + - so all kinds of accounts which could be addressable (base, multisig, module...) + + Other idea is to leave away this abstraction, and only implement the related functions, + which would take more +*/ + +// BaseLen is the length of generated addresses constructed by BaseAddress. +const BaseLen = sha256.Size + +type Addressable interface { + Address() []byte +} + +func MkBase(typ string, key []byte) []byte { + hasher := sha256.New() + hasher.Write(unsafeStrToByteArray(typ)) + th := hasher.Sum(nil) + + hasher.Reset() + _, err := hasher.Write(th) + errors.Panic(err) + _, err = hasher.Write(key) + errors.Panic(err) + return hasher.Sum(nil) +} + +func MkComposed(typ string, subAddresses []Addressable) []byte { + as := make([][]byte, len(subAddresses)) + totalLen := 0 + for i := range subAddresses { + as[i] = subAddresses[i].Address() + totalLen += len(as[i]) + } + + sort.Slice(as, func(i, j int) { byte.Compare(as[i], as[j]) <= 0 }) + key := make(key, totalLen) + offset := 0 + for i := range as { + key = copy(key[offset:], as[i]) + offset += len(as[i]) + } + return MkBase(typ, key) +} + +// unsafeStrToByteArray uses unsafe to convert string into byte array. Returned array +// cannot be altered after this functions is called +func unsafeStrToByteArray(s string) []byte { + sh := *(*reflect.SliceHeader)(unsafe.Pointer(&s)) + sh.Cap = sh.Len + bs := *(*[]byte)(unsafe.Pointer(&sh)) + return bs +} From 5eb4e971d57704912bdf73401ae68cb183b1ff48 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Fri, 22 Jan 2021 15:41:15 +0100 Subject: [PATCH 03/70] Update ed25519 --- crypto/keys/ed25519/ed25519.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crypto/keys/ed25519/ed25519.go b/crypto/keys/ed25519/ed25519.go index 17368c4b12ff..c757d13bd1a3 100644 --- a/crypto/keys/ed25519/ed25519.go +++ b/crypto/keys/ed25519/ed25519.go @@ -6,11 +6,13 @@ import ( "fmt" "io" + proto "github.com/gogo/protobuf/proto" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/tmhash" "github.com/cosmos/cosmos-sdk/codec" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/types/address" "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -155,6 +157,7 @@ func (pubKey *PubKey) Address() crypto.Address { if len(pubKey.Key) != PubKeySize { panic("pubkey is incorrect size") } + address.MkBase(proto.MessageName(pubkey), pubKey.Key) return crypto.Address(tmhash.SumTruncated(pubKey.Key)) } From 90a0a397f303b3473e02f4bdbd42e1cc9b42e10f Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 27 Jan 2021 13:20:43 +0100 Subject: [PATCH 04/70] fix errors/handle --- types/errors/handle.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/errors/handle.go b/types/errors/handle.go index a0b7c86771a6..e4094a1ae618 100644 --- a/types/errors/handle.go +++ b/types/errors/handle.go @@ -5,8 +5,8 @@ import "fmt" // Panic panics on error // Should be only used with interface methods, which require return error, but the // error is always nil -func Panic(err) { +func Panic(err error) { if err != nil { - panic(fmt.Errorf("Logic error - this should never happen. %w", err)) + panic(fmt.Errorf("logic error - this should never happen. %w", err)) } } From 8394e3967030257ae5cc78a9b7255daa0a16458b Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 27 Jan 2021 18:53:14 +0100 Subject: [PATCH 05/70] fix build --- types/address/hash.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/types/address/hash.go b/types/address/hash.go index 6d980c842ad8..688c1af3c3ab 100644 --- a/types/address/hash.go +++ b/types/address/hash.go @@ -1,6 +1,7 @@ package address import ( + "bytes" "crypto/sha256" "reflect" "sort" @@ -48,11 +49,11 @@ func MkComposed(typ string, subAddresses []Addressable) []byte { totalLen += len(as[i]) } - sort.Slice(as, func(i, j int) { byte.Compare(as[i], as[j]) <= 0 }) - key := make(key, totalLen) + sort.Slice(as, func(i, j int) bool { return bytes.Compare(as[i], as[j]) <= 0 }) + key := make([]byte, totalLen) offset := 0 for i := range as { - key = copy(key[offset:], as[i]) + copy(key[offset:], as[i]) offset += len(as[i]) } return MkBase(typ, key) From 48b584d8721e6c0e315b0fcbd34d9fe0bb326e08 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 27 Jan 2021 18:54:48 +0100 Subject: [PATCH 06/70] fix build --- crypto/keys/ed25519/ed25519.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/keys/ed25519/ed25519.go b/crypto/keys/ed25519/ed25519.go index c757d13bd1a3..b781beb059f3 100644 --- a/crypto/keys/ed25519/ed25519.go +++ b/crypto/keys/ed25519/ed25519.go @@ -157,7 +157,7 @@ func (pubKey *PubKey) Address() crypto.Address { if len(pubKey.Key) != PubKeySize { panic("pubkey is incorrect size") } - address.MkBase(proto.MessageName(pubkey), pubKey.Key) + address.MkBase(proto.MessageName(pubKey), pubKey.Key) return crypto.Address(tmhash.SumTruncated(pubKey.Key)) } From d84264262582813aac100c1dafcf2ea0af0edfec Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 28 Jan 2021 00:14:51 +0100 Subject: [PATCH 07/70] Add tests and update function names --- crypto/keys/ed25519/ed25519.go | 4 +--- crypto/keys/ed25519/ed25519_test.go | 7 +++++++ types/address/hash.go | 23 +++++++---------------- types/address/hash_test.go | 24 ++++++++++++++++++++++++ 4 files changed, 39 insertions(+), 19 deletions(-) create mode 100644 types/address/hash_test.go diff --git a/crypto/keys/ed25519/ed25519.go b/crypto/keys/ed25519/ed25519.go index b781beb059f3..2597f8951ac7 100644 --- a/crypto/keys/ed25519/ed25519.go +++ b/crypto/keys/ed25519/ed25519.go @@ -8,7 +8,6 @@ import ( proto "github.com/gogo/protobuf/proto" "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/crypto/tmhash" "github.com/cosmos/cosmos-sdk/codec" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -157,8 +156,7 @@ func (pubKey *PubKey) Address() crypto.Address { if len(pubKey.Key) != PubKeySize { panic("pubkey is incorrect size") } - address.MkBase(proto.MessageName(pubKey), pubKey.Key) - return crypto.Address(tmhash.SumTruncated(pubKey.Key)) + return address.Hash(proto.MessageName(pubKey), pubKey.Key) } // Bytes returns the PubKey byte format. diff --git a/crypto/keys/ed25519/ed25519_test.go b/crypto/keys/ed25519/ed25519_test.go index 59cce4066ac2..7be25c9ee498 100644 --- a/crypto/keys/ed25519/ed25519_test.go +++ b/crypto/keys/ed25519/ed25519_test.go @@ -84,6 +84,13 @@ func TestPubKeyEquals(t *testing.T) { } } +func TestAddressEd25519(t *testing.T) { + pk := ed25519.PubKey{[]byte{125, 80, 29, 208, 159, 53, 119, 198, 73, 53, 187, 33, 199, 144, 62, 255, 1, 235, 117, 96, 128, 211, 17, 45, 34, 64, 189, 165, 33, 182, 54, 206}} + addr := pk.Address() + assert.Len(t, addr, 32, "Address must be 32 bytes long") + assert.Equal(t, "6F91DCE652D04A6F4B85E0F51874A631D711B476E08096ECCA7E5B721BB6571F", addr.String()) +} + func TestPrivKeyEquals(t *testing.T) { ed25519PrivKey := ed25519.GenPrivKey() diff --git a/types/address/hash.go b/types/address/hash.go index 688c1af3c3ab..c2345b14c7c8 100644 --- a/types/address/hash.go +++ b/types/address/hash.go @@ -10,25 +10,15 @@ import ( "github.com/cosmos/cosmos-sdk/types/errors" ) -/* - TODO - - I still need to think how to organize it. - Ideally, I wanted to Addressable Account abstraction - - so all kinds of accounts which could be addressable (base, multisig, module...) - - Other idea is to leave away this abstraction, and only implement the related functions, - which would take more -*/ - -// BaseLen is the length of generated addresses constructed by BaseAddress. -const BaseLen = sha256.Size +// Len is the length of base addresses +const Len = sha256.Size type Addressable interface { Address() []byte } -func MkBase(typ string, key []byte) []byte { +// Hash creates a new address from address type and key +func Hash(typ string, key []byte) []byte { hasher := sha256.New() hasher.Write(unsafeStrToByteArray(typ)) th := hasher.Sum(nil) @@ -41,7 +31,8 @@ func MkBase(typ string, key []byte) []byte { return hasher.Sum(nil) } -func MkComposed(typ string, subAddresses []Addressable) []byte { +// NewComposed creates a new address based on sub addresses. +func NewComposed(typ string, subAddresses []Addressable) []byte { as := make([][]byte, len(subAddresses)) totalLen := 0 for i := range subAddresses { @@ -56,7 +47,7 @@ func MkComposed(typ string, subAddresses []Addressable) []byte { copy(key[offset:], as[i]) offset += len(as[i]) } - return MkBase(typ, key) + return Hash(typ, key) } // unsafeStrToByteArray uses unsafe to convert string into byte array. Returned array diff --git a/types/address/hash_test.go b/types/address/hash_test.go new file mode 100644 index 000000000000..5e8bcd8c2408 --- /dev/null +++ b/types/address/hash_test.go @@ -0,0 +1,24 @@ +package address + +import ( + "crypto/sha256" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestHash(t *testing.T) { + assert := assert.New(t) + + typ := "1" + key := []byte{1} + part1 := sha256.Sum256([]byte(typ)) + expected := sha256.Sum256(append(part1[:], key...)) + received := Hash(typ, key) + assert.Equal(expected[:], received, "must create a correct address") + + received = Hash("other", key) + assert.NotEqual(expected[:], received, "must create a correct address") + + assert.Len(received, Len, "must have correcte length") +} From d4a1d0232db2c690072c33c7c76241866c69aa62 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 28 Jan 2021 18:08:21 +0100 Subject: [PATCH 08/70] wip --- simapp/sim_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/simapp/sim_test.go b/simapp/sim_test.go index 1c0609c1b82d..afc9fa13cd6d 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -274,9 +274,9 @@ func TestAppSimulationAfterImport(t *testing.T) { // TODO: Make another test for the fuzzer itself, which just has noOp txs // and doesn't depend on the application. func TestAppStateDeterminism(t *testing.T) { - if !FlagEnabledValue { - t.Skip("skipping application simulation") - } + // if !FlagEnabledValue { + // t.Skip("skipping application simulation") + // } config := NewConfigFromFlags() config.InitialBlockHeight = 1 From 0fe7b127769b9ed994d53ddf7f9dc6f71bc00bb0 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Mon, 1 Feb 2021 14:58:42 +0100 Subject: [PATCH 09/70] Use LengthPrefix for composed addresses --- types/address/hash.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/types/address/hash.go b/types/address/hash.go index c2345b14c7c8..22b6c8ae68e1 100644 --- a/types/address/hash.go +++ b/types/address/hash.go @@ -3,6 +3,7 @@ package address import ( "bytes" "crypto/sha256" + "fmt" "reflect" "sort" "unsafe" @@ -32,11 +33,16 @@ func Hash(typ string, key []byte) []byte { } // NewComposed creates a new address based on sub addresses. -func NewComposed(typ string, subAddresses []Addressable) []byte { +func NewComposed(typ string, subAddresses []Addressable) ([]byte, error) { as := make([][]byte, len(subAddresses)) totalLen := 0 + var err error for i := range subAddresses { - as[i] = subAddresses[i].Address() + a := subAddresses[i].Address() + as[i], err = LengthPrefix(a) + if err != nil { + return nil, fmt.Errorf("not compatible sub-adddress=%v at index=%d [%w]", a, i, err) + } totalLen += len(as[i]) } @@ -47,7 +53,7 @@ func NewComposed(typ string, subAddresses []Addressable) []byte { copy(key[offset:], as[i]) offset += len(as[i]) } - return Hash(typ, key) + return Hash(typ, key), nil } // unsafeStrToByteArray uses unsafe to convert string into byte array. Returned array From 32710dba82d664d6296e7e9a409cbdc76f9ed90c Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Mon, 1 Feb 2021 16:23:58 +0100 Subject: [PATCH 10/70] add tests for NewComposed --- types/address/hash_test.go | 48 +++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/types/address/hash_test.go b/types/address/hash_test.go index 5e8bcd8c2408..e7e598d603b7 100644 --- a/types/address/hash_test.go +++ b/types/address/hash_test.go @@ -9,7 +9,6 @@ import ( func TestHash(t *testing.T) { assert := assert.New(t) - typ := "1" key := []byte{1} part1 := sha256.Sum256([]byte(typ)) @@ -22,3 +21,50 @@ func TestHash(t *testing.T) { assert.Len(received, Len, "must have correcte length") } + +func TestComposed(t *testing.T) { + assert := assert.New(t) + a1 := addrMock{[]byte{11, 12}} + a2 := addrMock{[]byte{21, 22}} + + typ := "multisig" + ac, err := NewComposed(typ, []Addressable{a1, a2}) + assert.NoError(err) + assert.Len(ac, Len) + + // check if optimizations work + checkingKey := append([]byte{}, a1.AddressWithLen(t)...) + checkingKey = append(checkingKey, a2.AddressWithLen(t)...) + ac2 := Hash(typ, checkingKey) + assert.Equal(ac, ac2, "NewComposed works correctly") + + // changing order of addresses shouldn't impact a composed address + ac2, err = NewComposed(typ, []Addressable{a2, a1}) + assert.NoError(err) + assert.Len(ac2, Len) + assert.Equal(ac, ac2, "NewComposed is not sensitive for order") + + // changing a type should change composed address + ac2, err = NewComposed(typ+"other", []Addressable{a2, a1}) + assert.NoError(err) + assert.NotEqual(ac, ac2, "NewComposed must be sensitive to type") + + // changing order of addresses shouldn't impact a composed address + ac2, err = NewComposed(typ, []Addressable{a1, addrMock{make([]byte, 300, 300)}}) + assert.Error(err) + assert.Contains(err.Error(), "should be max 255 bytes, got 300") +} + +type addrMock struct { + Addr []byte +} + +func (a addrMock) Address() []byte { + return a.Addr +} + +func (a addrMock) AddressWithLen(t *testing.T) []byte { + addr, err := LengthPrefix(a.Addr) + assert.NoError(t, err) + return addr +} From 98cdf6d2e20e2689bb0c74b64fe875a04877251f Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Tue, 2 Feb 2021 22:59:20 +0100 Subject: [PATCH 11/70] add module hash function --- types/address/hash.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/types/address/hash.go b/types/address/hash.go index 22b6c8ae68e1..31959c212181 100644 --- a/types/address/hash.go +++ b/types/address/hash.go @@ -56,6 +56,11 @@ func NewComposed(typ string, subAddresses []Addressable) ([]byte, error) { return Hash(typ, key), nil } +// Module is a specialized version of a composed address for modules +func Module(moduleName string, key []byte) []byte { + return Hash("module", append([]byte(moduleName), 0, key...)) +} + // unsafeStrToByteArray uses unsafe to convert string into byte array. Returned array // cannot be altered after this functions is called func unsafeStrToByteArray(s string) []byte { From 956edf08f0530cd54ac994d41423a30e724ddea9 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 4 Feb 2021 03:55:23 +0100 Subject: [PATCH 12/70] fix append --- types/address/hash.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/types/address/hash.go b/types/address/hash.go index 31959c212181..f75a985e2ad8 100644 --- a/types/address/hash.go +++ b/types/address/hash.go @@ -58,7 +58,8 @@ func NewComposed(typ string, subAddresses []Addressable) ([]byte, error) { // Module is a specialized version of a composed address for modules func Module(moduleName string, key []byte) []byte { - return Hash("module", append([]byte(moduleName), 0, key...)) + mKey := append([]byte(moduleName), 0) + return Hash("module", append(mKey, key...)) } // unsafeStrToByteArray uses unsafe to convert string into byte array. Returned array From 6f0acf49e6537de3cd60f38e8dffe74b304e8958 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Sun, 7 Feb 2021 15:18:34 +0100 Subject: [PATCH 13/70] rollback ed25519 ADR-28 update --- crypto/keys/ed25519/ed25519.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crypto/keys/ed25519/ed25519.go b/crypto/keys/ed25519/ed25519.go index 2597f8951ac7..1c1ed1839a41 100644 --- a/crypto/keys/ed25519/ed25519.go +++ b/crypto/keys/ed25519/ed25519.go @@ -6,12 +6,11 @@ import ( "fmt" "io" - proto "github.com/gogo/protobuf/proto" "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/tmhash" "github.com/cosmos/cosmos-sdk/codec" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - "github.com/cosmos/cosmos-sdk/types/address" "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -156,7 +155,8 @@ func (pubKey *PubKey) Address() crypto.Address { if len(pubKey.Key) != PubKeySize { panic("pubkey is incorrect size") } - return address.Hash(proto.MessageName(pubKey), pubKey.Key) + return crypto.Address(tmhash.SumTruncated(pubKey.Key)) + // TODO use ADR-28: return address.Hash(proto.MessageName(pubKey), pubKey.Key) } // Bytes returns the PubKey byte format. From abd614a2c34984a23cfdba713ee87442fb84ef2c Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Sun, 7 Feb 2021 19:16:52 +0100 Subject: [PATCH 14/70] rollback ed25519 ADR-28 test --- crypto/keys/ed25519/ed25519_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crypto/keys/ed25519/ed25519_test.go b/crypto/keys/ed25519/ed25519_test.go index 7be25c9ee498..81166c3f1068 100644 --- a/crypto/keys/ed25519/ed25519_test.go +++ b/crypto/keys/ed25519/ed25519_test.go @@ -87,8 +87,9 @@ func TestPubKeyEquals(t *testing.T) { func TestAddressEd25519(t *testing.T) { pk := ed25519.PubKey{[]byte{125, 80, 29, 208, 159, 53, 119, 198, 73, 53, 187, 33, 199, 144, 62, 255, 1, 235, 117, 96, 128, 211, 17, 45, 34, 64, 189, 165, 33, 182, 54, 206}} addr := pk.Address() - assert.Len(t, addr, 32, "Address must be 32 bytes long") - assert.Equal(t, "6F91DCE652D04A6F4B85E0F51874A631D711B476E08096ECCA7E5B721BB6571F", addr.String()) + assert.Len(t, addr, 20, "Address must be 20 bytes long") + // TODO: update for ADR-28 addresses: + // assert.Equal(t, "6F91DCE652D04A6F4B85E0F51874A631D711B476E08096ECCA7E5B721BB6571F", addr.String()) } func TestPrivKeyEquals(t *testing.T) { From 964bf10b9de109377e83238bf2e6661df4ef18c6 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Sun, 7 Feb 2021 19:34:54 +0100 Subject: [PATCH 15/70] Adding Module tests and convert tests to test suite --- types/address/hash.go | 3 ++- types/address/hash_test.go | 34 +++++++++++++++++++++++++++------- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/types/address/hash.go b/types/address/hash.go index f75a985e2ad8..853a63d0e3a6 100644 --- a/types/address/hash.go +++ b/types/address/hash.go @@ -56,7 +56,8 @@ func NewComposed(typ string, subAddresses []Addressable) ([]byte, error) { return Hash(typ, key), nil } -// Module is a specialized version of a composed address for modules +// Module is a specialized version of a composed address for modules. Each module account +// is constructed from a module name and module account key. func Module(moduleName string, key []byte) []byte { mKey := append([]byte(moduleName), 0) return Hash("module", append(mKey, key...)) diff --git a/types/address/hash_test.go b/types/address/hash_test.go index e7e598d603b7..e2aab829ac5b 100644 --- a/types/address/hash_test.go +++ b/types/address/hash_test.go @@ -5,10 +5,17 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" ) -func TestHash(t *testing.T) { - assert := assert.New(t) +func TestAddressSuite(t *testing.T) { + suite.Run(t, new(AddressSuite)) +} + +type AddressSuite struct{ suite.Suite } + +func (suite *AddressSuite) TestHash() { + assert := suite.Assert() typ := "1" key := []byte{1} part1 := sha256.Sum256([]byte(typ)) @@ -18,12 +25,11 @@ func TestHash(t *testing.T) { received = Hash("other", key) assert.NotEqual(expected[:], received, "must create a correct address") - assert.Len(received, Len, "must have correcte length") } -func TestComposed(t *testing.T) { - assert := assert.New(t) +func (suite *AddressSuite) TestComposed() { + assert := suite.Assert() a1 := addrMock{[]byte{11, 12}} a2 := addrMock{[]byte{21, 22}} @@ -33,8 +39,8 @@ func TestComposed(t *testing.T) { assert.Len(ac, Len) // check if optimizations work - checkingKey := append([]byte{}, a1.AddressWithLen(t)...) - checkingKey = append(checkingKey, a2.AddressWithLen(t)...) + checkingKey := append([]byte{}, a1.AddressWithLen(suite.T())...) + checkingKey = append(checkingKey, a2.AddressWithLen(suite.T())...) ac2 := Hash(typ, checkingKey) assert.Equal(ac, ac2, "NewComposed works correctly") @@ -55,6 +61,20 @@ func TestComposed(t *testing.T) { assert.Contains(err.Error(), "should be max 255 bytes, got 300") } +func (suite *AddressSuite) TestModule() { + assert := suite.Assert() + var modName, key = "myModule", []byte{1, 2} + addr := Module(modName, key) + assert.Len(addr, Len, "must have address length") + + addr2 := Module("myModule2", key) + assert.NotEqual(addr, addr2, "changing module name must change address") + + addr3 := Module(modName, []byte{1, 2, 3}) + assert.NotEqual(addr, addr3, "changing key must change address") + assert.NotEqual(addr2, addr3, "changing key must change address") +} + type addrMock struct { Addr []byte } From 679afbed526f6b5e5be68cdfcdbad4db76c266e5 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Sun, 7 Feb 2021 19:48:28 +0100 Subject: [PATCH 16/70] convert store_key_test.go to test suite --- types/address/store_key_test.go | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/types/address/store_key_test.go b/types/address/store_key_test.go index 3bb00bd022b0..ac28f814cc36 100644 --- a/types/address/store_key_test.go +++ b/types/address/store_key_test.go @@ -3,12 +3,19 @@ package address_test import ( "testing" - "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" "github.com/cosmos/cosmos-sdk/types/address" ) -func TestLengthPrefixedAddressStoreKey(t *testing.T) { +func TestStoreKeySuite(t *testing.T) { + suite.Run(t, new(StoreKeySuite)) +} + +type StoreKeySuite struct{ suite.Suite } + +func (suite *StoreKeySuite) TestLengthPrefix() { + require := suite.Require() addr10byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} addr20byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19} addr256byte := make([]byte, 256) @@ -23,15 +30,16 @@ func TestLengthPrefixedAddressStoreKey(t *testing.T) { {"20-byte address", addr20byte, append([]byte{byte(20)}, addr20byte...), false}, {"256-byte address (too long)", addr256byte, nil, true}, } + for _, tt := range tests { tt := tt - t.Run(tt.name, func(t *testing.T) { + suite.Run(tt.name, func() { storeKey, err := address.LengthPrefix(tt.addr) if tt.expErr { - require.Error(t, err) + require.Error(err) } else { - require.NoError(t, err) - require.Equal(t, tt.expStoreKey, storeKey) + require.NoError(err) + require.Equal(tt.expStoreKey, storeKey) } }) } From bba458f0c9c9324872c0b6ba1729bf5610512776 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Sun, 7 Feb 2021 20:03:36 +0100 Subject: [PATCH 17/70] rollback test check comment --- simapp/sim_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/simapp/sim_test.go b/simapp/sim_test.go index afc9fa13cd6d..1c0609c1b82d 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -274,9 +274,9 @@ func TestAppSimulationAfterImport(t *testing.T) { // TODO: Make another test for the fuzzer itself, which just has noOp txs // and doesn't depend on the application. func TestAppStateDeterminism(t *testing.T) { - // if !FlagEnabledValue { - // t.Skip("skipping application simulation") - // } + if !FlagEnabledValue { + t.Skip("skipping application simulation") + } config := NewConfigFromFlags() config.InitialBlockHeight = 1 From 8d22e18aeea7db57c651fca717d1dc95f6b3d024 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Sun, 7 Feb 2021 22:57:18 +0100 Subject: [PATCH 18/70] any.pb.go update --- codec/types/any.pb.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/codec/types/any.pb.go b/codec/types/any.pb.go index 97d9f1c2aa64..94cf80216287 100644 --- a/codec/types/any.pb.go +++ b/codec/types/any.pb.go @@ -476,10 +476,7 @@ func (m *Any) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthAny - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthAny } if (iNdEx + skippy) > l { From baa1192ddc0cf852dc3ea9dfe8bed199712fc132 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Sun, 7 Feb 2021 22:57:36 +0100 Subject: [PATCH 19/70] generated proto files --- crypto/keys/secp256k1/keys.pb.go | 5 +- crypto/keys/secp256r1/keys.pb.go | 497 +++++++++++++++++++++++ proto/cosmos/crypto/secp256r1/keys.proto | 18 + 3 files changed, 517 insertions(+), 3 deletions(-) create mode 100644 crypto/keys/secp256r1/keys.pb.go create mode 100644 proto/cosmos/crypto/secp256r1/keys.proto diff --git a/crypto/keys/secp256k1/keys.pb.go b/crypto/keys/secp256k1/keys.pb.go index 5329805b85fe..afcbab54b05d 100644 --- a/crypto/keys/secp256k1/keys.pb.go +++ b/crypto/keys/secp256k1/keys.pb.go @@ -5,12 +5,11 @@ package secp256k1 import ( fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" io "io" math "math" math_bits "math/bits" - - _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" ) // Reference imports to suppress errors if they are not otherwise used. diff --git a/crypto/keys/secp256r1/keys.pb.go b/crypto/keys/secp256r1/keys.pb.go new file mode 100644 index 000000000000..b994c0e03645 --- /dev/null +++ b/crypto/keys/secp256r1/keys.pb.go @@ -0,0 +1,497 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: cosmos/crypto/secp256r1/keys.proto + +package secp256r1 + +import ( + crypto_secp256r1 "crypto/secp256r1" + 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 + +// PubKey defines a secp256r1 public key +type PubKey struct { + Key crypto_secp256r1.PublicKey `protobuf:"bytes,1,opt,name=key,proto3,casttype=crypto/secp256r1.PublicKey" json:"key,omitempty"` +} + +func (m *PubKey) Reset() { *m = PubKey{} } +func (*PubKey) ProtoMessage() {} +func (*PubKey) Descriptor() ([]byte, []int) { + return fileDescriptor_b90c18415095c0c3, []int{0} +} +func (m *PubKey) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PubKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PubKey.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 *PubKey) XXX_Merge(src proto.Message) { + xxx_messageInfo_PubKey.Merge(m, src) +} +func (m *PubKey) XXX_Size() int { + return m.Size() +} +func (m *PubKey) XXX_DiscardUnknown() { + xxx_messageInfo_PubKey.DiscardUnknown(m) +} + +var xxx_messageInfo_PubKey proto.InternalMessageInfo + +func (m *PubKey) GetKey() crypto_secp256r1.PublicKey { + if m != nil { + return m.Key + } + return nil +} + +// PrivKey defines a secp256r1 private key +type PrivKey struct { + Key crypto_secp256r1.PrivateKey `protobuf:"bytes,1,opt,name=key,proto3,casttype=crypto/secp256r1.PrivateKey" json:"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_b90c18415095c0c3, []int{1} +} +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) GetKey() crypto_secp256r1.PrivateKey { + if m != nil { + return m.Key + } + return nil +} + +func init() { + proto.RegisterType((*PubKey)(nil), "cosmos.crypto.secp256r1.PubKey") + proto.RegisterType((*PrivKey)(nil), "cosmos.crypto.secp256r1.PrivKey") +} + +func init() { + proto.RegisterFile("cosmos/crypto/secp256r1/keys.proto", fileDescriptor_b90c18415095c0c3) +} + +var fileDescriptor_b90c18415095c0c3 = []byte{ + // 223 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4a, 0xce, 0x2f, 0xce, + 0xcd, 0x2f, 0xd6, 0x4f, 0x2e, 0xaa, 0x2c, 0x28, 0xc9, 0xd7, 0x2f, 0x4e, 0x4d, 0x2e, 0x30, 0x32, + 0x35, 0x2b, 0x32, 0xd4, 0xcf, 0x4e, 0xad, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, + 0x87, 0xa8, 0xd1, 0x83, 0xa8, 0xd1, 0x83, 0xab, 0x91, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0xab, + 0xd1, 0x07, 0xb1, 0x20, 0xca, 0x95, 0x1c, 0xb8, 0xd8, 0x02, 0x4a, 0x93, 0xbc, 0x53, 0x2b, 0x85, + 0x0c, 0xb8, 0x98, 0xb3, 0x53, 0x2b, 0x25, 0x18, 0x15, 0x18, 0x35, 0x78, 0x9c, 0xe4, 0x7e, 0xdd, + 0x93, 0x97, 0x42, 0xb7, 0x46, 0x2f, 0xa0, 0x34, 0x29, 0x27, 0x33, 0xd9, 0x3b, 0xb5, 0x32, 0x08, + 0xa4, 0xd4, 0x8a, 0x65, 0xc6, 0x02, 0x79, 0x06, 0x25, 0x1b, 0x2e, 0xf6, 0x80, 0xa2, 0xcc, 0x32, + 0x90, 0x11, 0x86, 0xc8, 0x46, 0xc8, 0xff, 0xba, 0x27, 0x2f, 0x8d, 0x69, 0x44, 0x51, 0x66, 0x59, + 0x62, 0x49, 0x2a, 0xcc, 0x0c, 0x27, 0x9f, 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, 0x32, 0x4a, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x87, 0xf9, 0x1b, + 0x4c, 0xe9, 0x16, 0xa7, 0x64, 0xc3, 0x82, 0x00, 0xe4, 0x71, 0x84, 0xe9, 0x49, 0x6c, 0x60, 0x4f, + 0x19, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x94, 0x6c, 0xc9, 0xc3, 0x29, 0x01, 0x00, 0x00, +} + +func (m *PubKey) 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 *PubKey) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PubKey) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintKeys(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +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.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintKeys(dAtA, i, uint64(len(m.Key))) + 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 *PubKey) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Key) + if l > 0 { + n += 1 + l + sovKeys(uint64(l)) + } + return n +} + +func (m *PrivKey) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Key) + 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 *PubKey) 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: PubKey: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PubKey: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Key", 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.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...) + if m.Key == nil { + m.Key = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipKeys(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthKeys + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +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 Key", 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.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...) + if m.Key == nil { + m.Key = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipKeys(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (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/proto/cosmos/crypto/secp256r1/keys.proto b/proto/cosmos/crypto/secp256r1/keys.proto new file mode 100644 index 000000000000..cf0df759fbd8 --- /dev/null +++ b/proto/cosmos/crypto/secp256r1/keys.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; +package cosmos.crypto.secp256r1; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1"; + +// PubKey defines a secp256r1 public key +message PubKey { + option (gogoproto.goproto_stringer) = false; + + bytes key = 1 [(gogoproto.casttype) = "crypto/secp256r1.PublicKey"]; +} + +// PrivKey defines a secp256r1 private key +message PrivKey { + bytes key = 1 [(gogoproto.casttype) = "crypto/secp256r1.PrivateKey"]; +} From c99dce558be6a6a666f1ed8c498054ffdb7acf29 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Sun, 7 Feb 2021 23:27:34 +0100 Subject: [PATCH 20/70] wip --- crypto/keys/ecdsa/secp256r1_privkey.go | 54 +++ crypto/keys/ecdsa/secp256r1_pubkey.go | 79 ++++ crypto/keys/ecdsa/secp256r1_test.go | 1 + crypto/keys/secp256r1/keys.pb.go | 497 ----------------------- proto/cosmos/base/bytes.proto | 24 ++ proto/cosmos/crypto/secp256r1/keys.proto | 18 - scripts/protocgen.sh | 10 +- types/bytes.pb.go | 318 +++++++++++++++ 8 files changed, 481 insertions(+), 520 deletions(-) create mode 100644 crypto/keys/ecdsa/secp256r1_privkey.go create mode 100644 crypto/keys/ecdsa/secp256r1_pubkey.go create mode 100644 crypto/keys/ecdsa/secp256r1_test.go delete mode 100644 crypto/keys/secp256r1/keys.pb.go create mode 100644 proto/cosmos/base/bytes.proto delete mode 100644 proto/cosmos/crypto/secp256r1/keys.proto create mode 100644 types/bytes.pb.go diff --git a/crypto/keys/ecdsa/secp256r1_privkey.go b/crypto/keys/ecdsa/secp256r1_privkey.go new file mode 100644 index 000000000000..ee75e79643be --- /dev/null +++ b/crypto/keys/ecdsa/secp256r1_privkey.go @@ -0,0 +1,54 @@ +package secp256r1 + +import ( + "crypto/ecdsa" + "crypto/rand" + "crypto/sha256" + "crypto/subtle" + "fmt" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" +) + +// "github.com/cosmos/cosmos-sdk/codec" +// +// "github.com/cosmos/cosmos-sdk/types/errors" + +// GenPrivKey generates a new secp256r1 private key. It uses OS randomness. +func GenPrivKey() *PrivKey { + key, err := ecdsa.GenerateKey(curve, rand.Reader) + return PrivKey{key}, err +} + +// Bytes returns the byte representation of the Private Key. +// func (privKey *PrivKey) Bytes() []byte { +// return privKey.Key +// } + +// Sign signs arbitrary data using ECDSA. +func (privKey *PrivKey) Sign(msg []byte) ([]byte, error) { + digest := sha256.Sum256(msg) + return privKey.Key.Sign(rand.Reader, digest, nil) +} + +func (pubKey *PubKey) String() string { + return fmt.Sprintf("secp256r1{%X}", pubKey.Key) +} + +// PubKey returns the public key corresponding to privKey. +func (privKey *PrivKey) PubKey(msg []byte) cryptotypes.PubKey { + pk := privKey.Key.Public() + return PubKey{pk} +} + +// 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 { + if privKey.Type() != other.Type() { + return false + } + pk2, ok := other.(PrivKey) + privKey.Key.Equal(other) + + return subtle.ConstantTimeCompare(privKey.Bytes(), other.Bytes()) == 1 +} diff --git a/crypto/keys/ecdsa/secp256r1_pubkey.go b/crypto/keys/ecdsa/secp256r1_pubkey.go new file mode 100644 index 000000000000..fbc55d3e9b6d --- /dev/null +++ b/crypto/keys/ecdsa/secp256r1_pubkey.go @@ -0,0 +1,79 @@ +package secp256r1 + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "fmt" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" +) + +// "github.com/cosmos/cosmos-sdk/codec" +// +// "github.com/cosmos/cosmos-sdk/types/errors" + +const ( + keyType = "secp256r1" + PrivKeyName = "cosmos/PrivKeySecp256r1" + PubKeyName = "cosmos/PubKeySecp256r1" + // PubKeySize is is the size, in bytes, of public keys as used in this package. + // PubKeySize = 32 + // PrivKeySize is the size, in bytes, of private keys as used in this package. + // PrivKeySize = 64 + // SeedSize is the size, in bytes, of private key seeds. These are the + // private key representations used by RFC 8032. + SeedSize = 32 +) + +var curve elliptic.Curve + +func init() { + curve = elliptic.P256() + // params := curve.Params() + // if params.BitSize/8 != PubKeySize { + // panic(fmt.Sprintf("Wrong PubKeySize=%d, expecting=%d", PubKeySize, params.BitSize/8)) + // } +} + +// type curve + +type ecdsaPK struct { + ecdsa.PublicKey + // typ +} + +// var _ cryptotypes.PubKey = &PubKey{} + +/* +type PubKey interface { + proto.Message + + Address() Address + Bytes() []byte + VerifySignature(msg []byte, sig []byte) bool + Equals(PubKey) bool + Type() string +} + +// Message is implemented by generated protocol buffer messages. +type Message interface { + Reset() + String() string + ProtoMessage() +} +*/ + +// Bytes returns the byte representation of the Private Key. +// func (privKey *PrivKey) Bytes() []byte { +// return privKey.Key +// } + +func (pk *ecdsaPK) String() string { + return fmt.Sprintf("secp256r1{%X}", pubKey.Key) +} + +// Equals - you probably don't need to use this. +// Runs in constant time based on length of the keys. +func (pk *ecdsaPK) Equals(other cryptotypes.PubKey) bool { + +} diff --git a/crypto/keys/ecdsa/secp256r1_test.go b/crypto/keys/ecdsa/secp256r1_test.go new file mode 100644 index 000000000000..e7c27fd07b82 --- /dev/null +++ b/crypto/keys/ecdsa/secp256r1_test.go @@ -0,0 +1 @@ +package secp256r1 diff --git a/crypto/keys/secp256r1/keys.pb.go b/crypto/keys/secp256r1/keys.pb.go deleted file mode 100644 index b994c0e03645..000000000000 --- a/crypto/keys/secp256r1/keys.pb.go +++ /dev/null @@ -1,497 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: cosmos/crypto/secp256r1/keys.proto - -package secp256r1 - -import ( - crypto_secp256r1 "crypto/secp256r1" - 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 - -// PubKey defines a secp256r1 public key -type PubKey struct { - Key crypto_secp256r1.PublicKey `protobuf:"bytes,1,opt,name=key,proto3,casttype=crypto/secp256r1.PublicKey" json:"key,omitempty"` -} - -func (m *PubKey) Reset() { *m = PubKey{} } -func (*PubKey) ProtoMessage() {} -func (*PubKey) Descriptor() ([]byte, []int) { - return fileDescriptor_b90c18415095c0c3, []int{0} -} -func (m *PubKey) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *PubKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_PubKey.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 *PubKey) XXX_Merge(src proto.Message) { - xxx_messageInfo_PubKey.Merge(m, src) -} -func (m *PubKey) XXX_Size() int { - return m.Size() -} -func (m *PubKey) XXX_DiscardUnknown() { - xxx_messageInfo_PubKey.DiscardUnknown(m) -} - -var xxx_messageInfo_PubKey proto.InternalMessageInfo - -func (m *PubKey) GetKey() crypto_secp256r1.PublicKey { - if m != nil { - return m.Key - } - return nil -} - -// PrivKey defines a secp256r1 private key -type PrivKey struct { - Key crypto_secp256r1.PrivateKey `protobuf:"bytes,1,opt,name=key,proto3,casttype=crypto/secp256r1.PrivateKey" json:"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_b90c18415095c0c3, []int{1} -} -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) GetKey() crypto_secp256r1.PrivateKey { - if m != nil { - return m.Key - } - return nil -} - -func init() { - proto.RegisterType((*PubKey)(nil), "cosmos.crypto.secp256r1.PubKey") - proto.RegisterType((*PrivKey)(nil), "cosmos.crypto.secp256r1.PrivKey") -} - -func init() { - proto.RegisterFile("cosmos/crypto/secp256r1/keys.proto", fileDescriptor_b90c18415095c0c3) -} - -var fileDescriptor_b90c18415095c0c3 = []byte{ - // 223 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4a, 0xce, 0x2f, 0xce, - 0xcd, 0x2f, 0xd6, 0x4f, 0x2e, 0xaa, 0x2c, 0x28, 0xc9, 0xd7, 0x2f, 0x4e, 0x4d, 0x2e, 0x30, 0x32, - 0x35, 0x2b, 0x32, 0xd4, 0xcf, 0x4e, 0xad, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, - 0x87, 0xa8, 0xd1, 0x83, 0xa8, 0xd1, 0x83, 0xab, 0x91, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0xab, - 0xd1, 0x07, 0xb1, 0x20, 0xca, 0x95, 0x1c, 0xb8, 0xd8, 0x02, 0x4a, 0x93, 0xbc, 0x53, 0x2b, 0x85, - 0x0c, 0xb8, 0x98, 0xb3, 0x53, 0x2b, 0x25, 0x18, 0x15, 0x18, 0x35, 0x78, 0x9c, 0xe4, 0x7e, 0xdd, - 0x93, 0x97, 0x42, 0xb7, 0x46, 0x2f, 0xa0, 0x34, 0x29, 0x27, 0x33, 0xd9, 0x3b, 0xb5, 0x32, 0x08, - 0xa4, 0xd4, 0x8a, 0x65, 0xc6, 0x02, 0x79, 0x06, 0x25, 0x1b, 0x2e, 0xf6, 0x80, 0xa2, 0xcc, 0x32, - 0x90, 0x11, 0x86, 0xc8, 0x46, 0xc8, 0xff, 0xba, 0x27, 0x2f, 0x8d, 0x69, 0x44, 0x51, 0x66, 0x59, - 0x62, 0x49, 0x2a, 0xcc, 0x0c, 0x27, 0x9f, 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, 0x32, 0x4a, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x87, 0xf9, 0x1b, - 0x4c, 0xe9, 0x16, 0xa7, 0x64, 0xc3, 0x82, 0x00, 0xe4, 0x71, 0x84, 0xe9, 0x49, 0x6c, 0x60, 0x4f, - 0x19, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x94, 0x6c, 0xc9, 0xc3, 0x29, 0x01, 0x00, 0x00, -} - -func (m *PubKey) 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 *PubKey) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *PubKey) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Key) > 0 { - i -= len(m.Key) - copy(dAtA[i:], m.Key) - i = encodeVarintKeys(dAtA, i, uint64(len(m.Key))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -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.Key) > 0 { - i -= len(m.Key) - copy(dAtA[i:], m.Key) - i = encodeVarintKeys(dAtA, i, uint64(len(m.Key))) - 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 *PubKey) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Key) - if l > 0 { - n += 1 + l + sovKeys(uint64(l)) - } - return n -} - -func (m *PrivKey) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Key) - 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 *PubKey) 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: PubKey: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: PubKey: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Key", 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.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...) - if m.Key == nil { - m.Key = []byte{} - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipKeys(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthKeys - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -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 Key", 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.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...) - if m.Key == nil { - m.Key = []byte{} - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipKeys(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (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/proto/cosmos/base/bytes.proto b/proto/cosmos/base/bytes.proto new file mode 100644 index 000000000000..0e4f8f45e531 --- /dev/null +++ b/proto/cosmos/base/bytes.proto @@ -0,0 +1,24 @@ +syntax = "proto3"; +package cosmos.crypto.secp256r1; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/types"; +option (gogoproto.goproto_stringer_all) = false; +option (gogoproto.stringer_all) = false; + +// PBBytes defines a structure wrapping protocol buffers raw bytes serialization +message PBBytes { + bytes bytes = 1; +} + + +// // PubKey defines a P-256 s(ecp256r1) public key +// message PubKey { +// bytes key = 1; +// } + +// // PrivKey defines a P-256 (secp256r1) private key +// message PrivKey { +// bytes key = 1; +// } diff --git a/proto/cosmos/crypto/secp256r1/keys.proto b/proto/cosmos/crypto/secp256r1/keys.proto deleted file mode 100644 index cf0df759fbd8..000000000000 --- a/proto/cosmos/crypto/secp256r1/keys.proto +++ /dev/null @@ -1,18 +0,0 @@ -syntax = "proto3"; -package cosmos.crypto.secp256r1; - -import "gogoproto/gogo.proto"; - -option go_package = "github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1"; - -// PubKey defines a secp256r1 public key -message PubKey { - option (gogoproto.goproto_stringer) = false; - - bytes key = 1 [(gogoproto.casttype) = "crypto/secp256r1.PublicKey"]; -} - -// PrivKey defines a secp256r1 private key -message PrivKey { - bytes key = 1 [(gogoproto.casttype) = "crypto/secp256r1.PrivateKey"]; -} diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh index bd3e4009712b..ca909668439d 100755 --- a/scripts/protocgen.sh +++ b/scripts/protocgen.sh @@ -27,11 +27,11 @@ done # command to generate docs using protoc-gen-doc buf protoc \ --I "proto" \ --I "third_party/proto" \ ---doc_out=./docs/core \ ---doc_opt=./docs/protodoc-markdown.tmpl,proto-docs.md \ -$(find "$(pwd)/proto" -maxdepth 5 -name '*.proto') + -I "proto" \ + -I "third_party/proto" \ + --doc_out=./docs/core \ + --doc_opt=./docs/protodoc-markdown.tmpl,proto-docs.md \ + $(find "$(pwd)/proto" -maxdepth 5 -name '*.proto') go mod tidy # generate codec/testdata proto code diff --git a/types/bytes.pb.go b/types/bytes.pb.go new file mode 100644 index 000000000000..9d9926d86fff --- /dev/null +++ b/types/bytes.pb.go @@ -0,0 +1,318 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: cosmos/base/bytes.proto + +package types + +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 + +// PBBytes defines a structure wrapping protocol buffers raw bytes serialization +type PBBytes struct { + Bytes []byte `protobuf:"bytes,1,opt,name=bytes,proto3" json:"bytes,omitempty"` +} + +func (m *PBBytes) Reset() { *m = PBBytes{} } +func (*PBBytes) ProtoMessage() {} +func (*PBBytes) Descriptor() ([]byte, []int) { + return fileDescriptor_b510f2b6b79ff3d8, []int{0} +} +func (m *PBBytes) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PBBytes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PBBytes.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 *PBBytes) XXX_Merge(src proto.Message) { + xxx_messageInfo_PBBytes.Merge(m, src) +} +func (m *PBBytes) XXX_Size() int { + return m.Size() +} +func (m *PBBytes) XXX_DiscardUnknown() { + xxx_messageInfo_PBBytes.DiscardUnknown(m) +} + +var xxx_messageInfo_PBBytes proto.InternalMessageInfo + +func (m *PBBytes) GetBytes() []byte { + if m != nil { + return m.Bytes + } + return nil +} + +func init() { + proto.RegisterType((*PBBytes)(nil), "cosmos.crypto.secp256r1.PBBytes") +} + +func init() { proto.RegisterFile("cosmos/base/bytes.proto", fileDescriptor_b510f2b6b79ff3d8) } + +var fileDescriptor_b510f2b6b79ff3d8 = []byte{ + // 173 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4f, 0xce, 0x2f, 0xce, + 0xcd, 0x2f, 0xd6, 0x4f, 0x4a, 0x2c, 0x4e, 0xd5, 0x4f, 0xaa, 0x2c, 0x49, 0x2d, 0xd6, 0x2b, 0x28, + 0xca, 0x2f, 0xc9, 0x17, 0x82, 0x4a, 0xe8, 0x25, 0x17, 0x55, 0x16, 0x94, 0xe4, 0xeb, 0x15, 0xa7, + 0x26, 0x17, 0x18, 0x99, 0x9a, 0x15, 0x19, 0x4a, 0x89, 0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0xd5, 0xe8, + 0x83, 0x58, 0x10, 0xe5, 0x4a, 0xf2, 0x5c, 0xec, 0x01, 0x4e, 0x4e, 0x20, 0xfd, 0x42, 0x22, 0x5c, + 0xac, 0x60, 0x83, 0x24, 0x18, 0x15, 0x18, 0x35, 0x78, 0x82, 0x20, 0x1c, 0x27, 0x97, 0x1b, 0x0f, + 0xe5, 0x18, 0x1a, 0x1e, 0xc9, 0x31, 0x9c, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, + 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, + 0x94, 0x52, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x3e, 0xd4, 0x55, 0x10, + 0x4a, 0xb7, 0x38, 0x25, 0x5b, 0xbf, 0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, 0x0d, 0x6c, 0x9b, 0x31, + 0x20, 0x00, 0x00, 0xff, 0xff, 0xf1, 0x44, 0x60, 0x8d, 0xb7, 0x00, 0x00, 0x00, +} + +func (m *PBBytes) 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 *PBBytes) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PBBytes) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Bytes) > 0 { + i -= len(m.Bytes) + copy(dAtA[i:], m.Bytes) + i = encodeVarintBytes(dAtA, i, uint64(len(m.Bytes))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintBytes(dAtA []byte, offset int, v uint64) int { + offset -= sovBytes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *PBBytes) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Bytes) + if l > 0 { + n += 1 + l + sovBytes(uint64(l)) + } + return n +} + +func sovBytes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozBytes(x uint64) (n int) { + return sovBytes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *PBBytes) 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 ErrIntOverflowBytes + } + 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: PBBytes: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PBBytes: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Bytes", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowBytes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthBytes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthBytes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Bytes = append(m.Bytes[:0], dAtA[iNdEx:postIndex]...) + if m.Bytes == nil { + m.Bytes = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipBytes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthBytes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipBytes(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, ErrIntOverflowBytes + } + 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, ErrIntOverflowBytes + } + 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, ErrIntOverflowBytes + } + 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, ErrInvalidLengthBytes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupBytes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthBytes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthBytes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowBytes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupBytes = fmt.Errorf("proto: unexpected end of group") +) From de2e52193dc7cbdc9849c07b7024bd86880675ed Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Mon, 8 Feb 2021 16:09:44 +0100 Subject: [PATCH 21/70] renames --- crypto/keys/ecdsa/{secp256r1_privkey.go => ecdsa_privkey.go} | 0 crypto/keys/ecdsa/{secp256r1_pubkey.go => ecdsa_pubkey.go} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename crypto/keys/ecdsa/{secp256r1_privkey.go => ecdsa_privkey.go} (100%) rename crypto/keys/ecdsa/{secp256r1_pubkey.go => ecdsa_pubkey.go} (100%) diff --git a/crypto/keys/ecdsa/secp256r1_privkey.go b/crypto/keys/ecdsa/ecdsa_privkey.go similarity index 100% rename from crypto/keys/ecdsa/secp256r1_privkey.go rename to crypto/keys/ecdsa/ecdsa_privkey.go diff --git a/crypto/keys/ecdsa/secp256r1_pubkey.go b/crypto/keys/ecdsa/ecdsa_pubkey.go similarity index 100% rename from crypto/keys/ecdsa/secp256r1_pubkey.go rename to crypto/keys/ecdsa/ecdsa_pubkey.go From 3bb0700ec83a90a4aabab7f2f4f9accd143bd45c Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 10 Feb 2021 15:06:54 +0100 Subject: [PATCH 22/70] wip2 --- crypto/keys/ecdsa/ecdsa_privkey.go | 38 ++++++++---- crypto/keys/ecdsa/ecdsa_pubkey.go | 92 ++++++++++++++++++----------- crypto/keys/ecdsa/secp256r1_test.go | 1 - docs/core/proto-docs.md | 34 +++++++++++ 4 files changed, 118 insertions(+), 47 deletions(-) delete mode 100644 crypto/keys/ecdsa/secp256r1_test.go diff --git a/crypto/keys/ecdsa/ecdsa_privkey.go b/crypto/keys/ecdsa/ecdsa_privkey.go index ee75e79643be..fc147d166996 100644 --- a/crypto/keys/ecdsa/ecdsa_privkey.go +++ b/crypto/keys/ecdsa/ecdsa_privkey.go @@ -1,25 +1,41 @@ -package secp256r1 +package ecdsa import ( "crypto/ecdsa" "crypto/rand" - "crypto/sha256" - "crypto/subtle" - "fmt" - - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + // cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" ) // "github.com/cosmos/cosmos-sdk/codec" -// // "github.com/cosmos/cosmos-sdk/types/errors" +type ecdsaSK struct { + *ecdsa.PrivateKey +} + // GenPrivKey generates a new secp256r1 private key. It uses OS randomness. -func GenPrivKey() *PrivKey { - key, err := ecdsa.GenerateKey(curve, rand.Reader) - return PrivKey{key}, err +// TODO: return cryptotypes.PrivKey +func GenSecp256r1() (ecdsaSK, error) { + key, err := ecdsa.GenerateKey(secp256r1, rand.Reader) + return ecdsaSK{key}, err } +// TODO: change return type +func (sk ecdsaSK) PubKey() ecdsaPK { + return ecdsaPK{&sk.PublicKey, nil} +} + +/* +type LedgerPrivKey interface { + Bytes() []byte + Sign(msg []byte) ([]byte, error) + PubKey() PubKey + Equals(LedgerPrivKey) bool + Type() string + } +*/ + +/* // Bytes returns the byte representation of the Private Key. // func (privKey *PrivKey) Bytes() []byte { // return privKey.Key @@ -52,3 +68,5 @@ func (privKey *PrivKey) Equals(other cryptotypes.LedgerPrivKey) bool { return subtle.ConstantTimeCompare(privKey.Bytes(), other.Bytes()) == 1 } + +*/ diff --git a/crypto/keys/ecdsa/ecdsa_pubkey.go b/crypto/keys/ecdsa/ecdsa_pubkey.go index fbc55d3e9b6d..42ab65c00b92 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey.go @@ -1,11 +1,14 @@ -package secp256r1 +package ecdsa import ( + "crypto" "crypto/ecdsa" "crypto/elliptic" "fmt" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + // cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" ) // "github.com/cosmos/cosmos-sdk/codec" @@ -13,11 +16,8 @@ import ( // "github.com/cosmos/cosmos-sdk/types/errors" const ( - keyType = "secp256r1" - PrivKeyName = "cosmos/PrivKeySecp256r1" - PubKeyName = "cosmos/PubKeySecp256r1" // PubKeySize is is the size, in bytes, of public keys as used in this package. - // PubKeySize = 32 + PubKeySize = 32 + 1 // PrivKeySize is the size, in bytes, of private keys as used in this package. // PrivKeySize = 64 // SeedSize is the size, in bytes, of private key seeds. These are the @@ -25,27 +25,62 @@ const ( SeedSize = 32 ) -var curve elliptic.Curve +var secp256r1 elliptic.Curve +var curveNames map[elliptic.Curve]string func init() { - curve = elliptic.P256() - // params := curve.Params() - // if params.BitSize/8 != PubKeySize { - // panic(fmt.Sprintf("Wrong PubKeySize=%d, expecting=%d", PubKeySize, params.BitSize/8)) - // } + secp256r1 = elliptic.P256() + params := secp256r1.Params() + if params.BitSize/8 != PubKeySize-1 { + panic(fmt.Sprintf("Wrong PubKeySize=%d, expecting=%d", PubKeySize, params.BitSize/8)) + } + + curveNames = map[elliptic.Curve]string{ + secp256r1: "secp256r1", + } } -// type curve - type ecdsaPK struct { - ecdsa.PublicKey - // typ + *ecdsa.PublicKey + + // cache + address []byte // skd.AccAddress } +// TODO: // var _ cryptotypes.PubKey = &PubKey{} +// String implements PubKey interface +func (pk ecdsaPK) Address() sdk.AccAddress { + if pk.address == nil { + pk.address = address.Hash(curveNames[pk.Curve], pk.Bytes()) + } + return pk.address +} + +// String implements PubKey interface +func (pk ecdsaPK) String() string { + return fmt.Sprintf("%s{%X}", curveNames[pk.Curve], pk.Bytes()) +} + +// Bytes returns the byte representation of the public key in a compressed representation. +func (pk ecdsaPK) Bytes() []byte { + return elliptic.MarshalCompressed(pk.Curve, pk.X, pk.Y) +} + +// Equals - you probably don't need to use this. +// Runs in constant time based on length of the keys. +func (pk ecdsaPK) Equal(other crypto.PublicKey) bool { + pk2, ok := other.(ecdsaPK) + if !ok { + return false + } + + return pk.PublicKey.Equal(pk2.PublicKey) +} + /* -type PubKey interface { + type PubKey interface { proto.Message Address() Address @@ -53,27 +88,12 @@ type PubKey interface { VerifySignature(msg []byte, sig []byte) bool Equals(PubKey) bool Type() string -} + } -// Message is implemented by generated protocol buffer messages. -type Message interface { + // Message is implemented by generated protocol buffer messages. + type Message interface { Reset() String() string ProtoMessage() -} + } */ - -// Bytes returns the byte representation of the Private Key. -// func (privKey *PrivKey) Bytes() []byte { -// return privKey.Key -// } - -func (pk *ecdsaPK) String() string { - return fmt.Sprintf("secp256r1{%X}", pubKey.Key) -} - -// Equals - you probably don't need to use this. -// Runs in constant time based on length of the keys. -func (pk *ecdsaPK) Equals(other cryptotypes.PubKey) bool { - -} diff --git a/crypto/keys/ecdsa/secp256r1_test.go b/crypto/keys/ecdsa/secp256r1_test.go deleted file mode 100644 index e7c27fd07b82..000000000000 --- a/crypto/keys/ecdsa/secp256r1_test.go +++ /dev/null @@ -1 +0,0 @@ -package secp256r1 diff --git a/docs/core/proto-docs.md b/docs/core/proto-docs.md index b06aaf246185..a130b07c77d0 100644 --- a/docs/core/proto-docs.md +++ b/docs/core/proto-docs.md @@ -108,6 +108,9 @@ - [Msg](#cosmos.bank.v1beta1.Msg) +- [cosmos/base/bytes.proto](#cosmos/base/bytes.proto) + - [PBBytes](#cosmos.crypto.secp256r1.PBBytes) + - [cosmos/base/kv/v1beta1/kv.proto](#cosmos/base/kv/v1beta1/kv.proto) - [Pair](#cosmos.base.kv.v1beta1.Pair) - [Pairs](#cosmos.base.kv.v1beta1.Pairs) @@ -2102,6 +2105,37 @@ Msg defines the bank Msg service. + +

Top

+ +## cosmos/base/bytes.proto + + + + + +### PBBytes +PBBytes defines a structure wrapping protocol buffers raw bytes serialization + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `bytes` | [bytes](#bytes) | | | + + + + + + + + + + + + + + +

Top

From 4abcd8f2d3276f0995749216fa78d4ee61e5a603 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 10 Feb 2021 15:13:49 +0100 Subject: [PATCH 23/70] add String method to PBBytes --- types/bytes.go | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 types/bytes.go diff --git a/types/bytes.go b/types/bytes.go new file mode 100644 index 000000000000..aefaaf21f7a3 --- /dev/null +++ b/types/bytes.go @@ -0,0 +1,8 @@ +package types + +import "encoding/hex" + +// String encode bytes using hex encoder +func (m *PBBytes) String() string { + return hex.EncodeToString(m.Bytes) +} From 06aba105d23e6d191fd273a5cfaf7942fae2c479 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 10 Feb 2021 15:14:34 +0100 Subject: [PATCH 24/70] wip3 --- crypto/keys/ecdsa/ecdsa_privkey.go | 7 +- crypto/keys/ecdsa/ecdsa_pubkey.go | 131 ++++++++++++++++++++++------- 2 files changed, 105 insertions(+), 33 deletions(-) diff --git a/crypto/keys/ecdsa/ecdsa_privkey.go b/crypto/keys/ecdsa/ecdsa_privkey.go index fc147d166996..c1ea8b14b1e3 100644 --- a/crypto/keys/ecdsa/ecdsa_privkey.go +++ b/crypto/keys/ecdsa/ecdsa_privkey.go @@ -3,7 +3,8 @@ package ecdsa import ( "crypto/ecdsa" "crypto/rand" - // cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" ) // "github.com/cosmos/cosmos-sdk/codec" @@ -20,8 +21,8 @@ func GenSecp256r1() (ecdsaSK, error) { return ecdsaSK{key}, err } -// TODO: change return type -func (sk ecdsaSK) PubKey() ecdsaPK { +// PubKey implements SDK PrivKey interface +func (sk ecdsaSK) PubKey() cryptotypes.PubKey { return ecdsaPK{&sk.PublicKey, nil} } diff --git a/crypto/keys/ecdsa/ecdsa_pubkey.go b/crypto/keys/ecdsa/ecdsa_pubkey.go index 42ab65c00b92..429f1dc82d76 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey.go @@ -1,14 +1,18 @@ package ecdsa import ( - "crypto" "crypto/ecdsa" "crypto/elliptic" + "crypto/sha256" + "encoding/asn1" "fmt" + "math/big" - sdk "github.com/cosmos/cosmos-sdk/types" + tmcrypto "github.com/tendermint/tendermint/crypto" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/types/address" - // cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/types/errors" ) // "github.com/cosmos/cosmos-sdk/codec" @@ -17,7 +21,7 @@ import ( const ( // PubKeySize is is the size, in bytes, of public keys as used in this package. - PubKeySize = 32 + 1 + PubKeySize = 32 + 1 + 1 // PrivKeySize is the size, in bytes, of private keys as used in this package. // PrivKeySize = 64 // SeedSize is the size, in bytes, of private key seeds. These are the @@ -27,31 +31,46 @@ const ( var secp256r1 elliptic.Curve var curveNames map[elliptic.Curve]string +var curveTypes map[elliptic.Curve]byte +var curveTypesRev map[byte]elliptic.Curve func init() { secp256r1 = elliptic.P256() - params := secp256r1.Params() - if params.BitSize/8 != PubKeySize-1 { - panic(fmt.Sprintf("Wrong PubKeySize=%d, expecting=%d", PubKeySize, params.BitSize/8)) + // PubKeySize is ceil of field bit size + 1 for the sign + 1 for the type + expected := (secp256r1.Params().BitSize+7)/8 + 2 + if expected != PubKeySize { + panic(fmt.Sprintf("Wrong PubKeySize=%d, expecting=%d", PubKeySize, expected)) } curveNames = map[elliptic.Curve]string{ secp256r1: "secp256r1", } + curveTypes = map[elliptic.Curve]byte{ + // 0 reserved + secp256r1: 1, + } + curveTypesRev = map[byte]elliptic.Curve{} + for c, b := range curveTypes { + curveTypesRev[b] = c + } +} + +// signature holds the r and s values of an ECDSA signature +type signature struct { + R, S *big.Int } type ecdsaPK struct { *ecdsa.PublicKey // cache - address []byte // skd.AccAddress + address tmcrypto.Address } -// TODO: -// var _ cryptotypes.PubKey = &PubKey{} +var _ cryptotypes.PubKey = &ecdsaPK{} // String implements PubKey interface -func (pk ecdsaPK) Address() sdk.AccAddress { +func (pk ecdsaPK) Address() tmcrypto.Address { if pk.address == nil { pk.address = address.Hash(curveNames[pk.Curve], pk.Bytes()) } @@ -63,14 +82,20 @@ func (pk ecdsaPK) String() string { return fmt.Sprintf("%s{%X}", curveNames[pk.Curve], pk.Bytes()) } -// Bytes returns the byte representation of the public key in a compressed representation. +// Bytes returns the byte representation of the public key using a compressed form +// specified in section 4.3.6 of ANSI X9.62 with first byte being the curve type. func (pk ecdsaPK) Bytes() []byte { - return elliptic.MarshalCompressed(pk.Curve, pk.X, pk.Y) + compressed := make([]byte, PubKeySize) + compressed[0] = curveTypes[pk.Curve] + compressed[1] = byte(pk.Y.Bit(0)) | 2 + pk.X.FillBytes(compressed[2:]) + return compressed } // Equals - you probably don't need to use this. // Runs in constant time based on length of the keys. -func (pk ecdsaPK) Equal(other crypto.PublicKey) bool { +// TODO: change to Equals +func (pk ecdsaPK) Equals(other cryptotypes.PubKey) bool { pk2, ok := other.(ecdsaPK) if !ok { return false @@ -79,21 +104,67 @@ func (pk ecdsaPK) Equal(other crypto.PublicKey) bool { return pk.PublicKey.Equal(pk2.PublicKey) } +// VerifySignature implements skd.PubKey interface +func (pk ecdsaPK) VerifySignature(msg []byte, sig []byte) bool { + s := new(signature) + if _, err := asn1.Unmarshal(sig, s); err != nil || s == nil { + return false + } + + h := sha256.Sum256(msg) + return ecdsa.Verify(pk.PublicKey, h[:], s.R, s.S) +} + +// Type returns key type name. Implements sdk.PubKey interface +func (pk ecdsaPK) Type() string { + return curveNames[pk.Curve] +} + +// **** proto.Message **** + +func (pk ecdsaPK) Reset() {} // TODO: maybe we need to have this? +func (ecdsaPK) ProtoMessage() {} + /* - type PubKey interface { - proto.Message - - Address() Address - Bytes() []byte - VerifySignature(msg []byte, sig []byte) bool - Equals(PubKey) bool - Type() string - } - - // Message is implemented by generated protocol buffer messages. - type Message interface { - Reset() - String() string - ProtoMessage() - } +ProtoMarshaler interface { + Marshal() ([]byte, error) + MarshalTo(data []byte) (n int, err error) + MarshalToSizedBuffer(dAtA []byte) (int, error) + Size() int + Unmarshal(data []byte) error +} */ + +// **** Amino Marshaler **** + +// MarshalAmino overrides Amino binary marshalling. +func (pk ecdsaPK) MarshalAmino() ([]byte, error) { + return pk.Bytes(), nil +} + +// UnmarshalAmino overrides Amino binary marshalling. +func (pk *ecdsaPK) UnmarshalAmino(bz []byte) error { + if len(bz) != PubKeySize { + return errors.Wrap(errors.ErrInvalidPubKey, "invalid pubkey size") + } + curve, ok := curveTypesRev[bz[0]] + if !ok { + return errors.Wrap(errors.ErrInvalidPubKey, "invalid curve type") + } + x, y := elliptic.UnmarshalCompressed(curve, bz[1:]) + if x == nil || y == nil { + return errors.Wrap(errors.ErrInvalidPubKey, "invalid pubkey bytes") + } + pk.PublicKey = &ecdsa.PublicKey{Curve: curve, X: x, Y: y} + return nil +} + +// MarshalAminoJSON overrides Amino JSON marshalling. +func (pk ecdsaPK) MarshalAminoJSON() ([]byte, error) { + return pk.MarshalAmino() +} + +// UnmarshalAminoJSON overrides Amino JSON marshalling. +func (pk *ecdsaPK) UnmarshalAminoJSON(bz []byte) error { + return pk.UnmarshalAmino(bz) +} From 2c80e9c878e4ea855cbf3abb6082343b5120f4e2 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 10 Feb 2021 16:51:12 +0100 Subject: [PATCH 25/70] add pubkey tests --- crypto/keys/ecdsa/ecdsa_pubkey_test.go | 71 ++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 crypto/keys/ecdsa/ecdsa_pubkey_test.go diff --git a/crypto/keys/ecdsa/ecdsa_pubkey_test.go b/crypto/keys/ecdsa/ecdsa_pubkey_test.go new file mode 100644 index 000000000000..e2afccc854fd --- /dev/null +++ b/crypto/keys/ecdsa/ecdsa_pubkey_test.go @@ -0,0 +1,71 @@ +package ecdsa + +import ( + "encoding/hex" + "testing" + + "github.com/stretchr/testify/suite" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" +) + +type EcdsaSuite struct { + suite.Suite + pk cryptotypes.PubKey + sk ecdsaSK +} + +func TestEcdsaSuite(t *testing.T) { + suite.Run(t, new(EcdsaSuite)) +} + +func (suite *EcdsaSuite) SetupSuite() { + sk, err := GenSecp256r1() + suite.Assert().NoError(err) + suite.pk = sk.PubKey() +} + +func (suite *EcdsaSuite) TestString() { + assert := suite.Assert() + require := suite.Require() + + pkStr := suite.pk.String() + prefix := "secp256r1{" + require.Len(pkStr, len(prefix)+PubKeySize*2+1) // prefix + hex_len + "}" + assert.Equal(prefix, pkStr[:len(prefix)]) + assert.EqualValues('}', pkStr[len(pkStr)-1]) + + bz, err := hex.DecodeString(pkStr[len(prefix) : len(pkStr)-1]) + require.NoError(err) + assert.EqualValues(suite.pk.Bytes(), bz) +} + +func (suite *EcdsaSuite) TestEqual() { + assert := suite.Assert() + + skOther, err := GenSecp256r1() + assert.NoError(err) + pkOther := skOther.PubKey() + pkOther2 := ecdsaPK{&skOther.PublicKey, nil} + + assert.False(suite.pk.Equals(pkOther)) + + assert.True(pkOther.Equals(pkOther2)) + assert.True(pkOther2.Equals(pkOther), "Equals must be reflexive") +} + +func (suite *EcdsaSuite) TestMarshalAmino() { + require := suite.Require() + type AminoPubKey interface { + cryptotypes.PubKey + MarshalAmino() ([]byte, error) + } + + pk := suite.pk.(AminoPubKey) + bz, err := pk.MarshalAmino() + require.NoError(err) + + var pk2 = new(ecdsaPK) + require.NoError(pk2.UnmarshalAmino(bz)) + require.True(pk2.Equals(suite.pk)) +} From 73ce143098b1cd94dfcd3f4ae50703c23b10391d Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 11 Feb 2021 02:20:19 +0100 Subject: [PATCH 26/70] adding cryptotypes.PrivKey methods --- crypto/keys/ecdsa/ecdsa_privkey.go | 77 +++++++++++-------------- crypto/keys/ecdsa/ecdsa_privkey_test.go | 17 ++++++ crypto/keys/ecdsa/ecdsa_pubkey.go | 15 ++--- crypto/keys/ecdsa/ecdsa_pubkey_test.go | 17 +++--- 4 files changed, 67 insertions(+), 59 deletions(-) create mode 100644 crypto/keys/ecdsa/ecdsa_privkey_test.go diff --git a/crypto/keys/ecdsa/ecdsa_privkey.go b/crypto/keys/ecdsa/ecdsa_privkey.go index c1ea8b14b1e3..ac24d18e3a2f 100644 --- a/crypto/keys/ecdsa/ecdsa_privkey.go +++ b/crypto/keys/ecdsa/ecdsa_privkey.go @@ -3,6 +3,7 @@ package ecdsa import ( "crypto/ecdsa" "crypto/rand" + "crypto/sha256" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" ) @@ -11,63 +12,55 @@ import ( // "github.com/cosmos/cosmos-sdk/types/errors" type ecdsaSK struct { - *ecdsa.PrivateKey + ecdsa.PrivateKey } -// GenPrivKey generates a new secp256r1 private key. It uses OS randomness. -// TODO: return cryptotypes.PrivKey -func GenSecp256r1() (ecdsaSK, error) { +var _ cryptotypes.PrivKey = ecdsaSK{} + +// GenSecp256r1 generates a new secp256r1 private key. It uses OS randomness. +func GenSecp256r1() (cryptotypes.PrivKey, error) { key, err := ecdsa.GenerateKey(secp256r1, rand.Reader) - return ecdsaSK{key}, err + return ecdsaSK{*key}, err } // PubKey implements SDK PrivKey interface func (sk ecdsaSK) PubKey() cryptotypes.PubKey { - return ecdsaPK{&sk.PublicKey, nil} -} - -/* -type LedgerPrivKey interface { - Bytes() []byte - Sign(msg []byte) ([]byte, error) - PubKey() PubKey - Equals(LedgerPrivKey) bool - Type() string - } -*/ - -/* -// Bytes returns the byte representation of the Private Key. -// func (privKey *PrivKey) Bytes() []byte { -// return privKey.Key -// } - -// Sign signs arbitrary data using ECDSA. -func (privKey *PrivKey) Sign(msg []byte) ([]byte, error) { - digest := sha256.Sum256(msg) - return privKey.Key.Sign(rand.Reader, digest, nil) -} - -func (pubKey *PubKey) String() string { - return fmt.Sprintf("secp256r1{%X}", pubKey.Key) + return ecdsaPK{sk.PublicKey, nil} } -// PubKey returns the public key corresponding to privKey. -func (privKey *PrivKey) PubKey(msg []byte) cryptotypes.PubKey { - pk := privKey.Key.Public() - return PubKey{pk} +// Bytes serialize the private key with first byte being the curve type +func (sk ecdsaSK) Bytes() []byte { + bz := make([]byte, PrivKeySize) + bz[0] = curveTypes[sk.Curve] + sk.D.FillBytes(bz[1:]) + return bz } // 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 { - if privKey.Type() != other.Type() { +func (sk ecdsaSK) Equals(other cryptotypes.LedgerPrivKey) bool { + sk2, ok := other.(ecdsaSK) + if !ok { return false } - pk2, ok := other.(PrivKey) - privKey.Key.Equal(other) + return sk.PrivateKey.Equal(sk2.PrivateKey) +} - return subtle.ConstantTimeCompare(privKey.Bytes(), other.Bytes()) == 1 +// Type returns key type name. Implements sdk.PrivKey interface +func (sk ecdsaSK) Type() string { + return curveNames[sk.Curve] } -*/ +// Sign hashes and signs the message usign ECDSA. Implements sdk.PrivKey interface +func (sk ecdsaSK) Sign(msg []byte) ([]byte, error) { + digest := sha256.Sum256(msg) + return sk.PrivateKey.Sign(rand.Reader, digest[:], nil) +} + +// **** proto.Message **** + +func (ecdsaSK) Reset() {} +func (ecdsaSK) ProtoMessage() {} +func (sk ecdsaSK) String() string { + return curveNames[sk.Curve] + "{-}" +} diff --git a/crypto/keys/ecdsa/ecdsa_privkey_test.go b/crypto/keys/ecdsa/ecdsa_privkey_test.go new file mode 100644 index 000000000000..f420068d8ee1 --- /dev/null +++ b/crypto/keys/ecdsa/ecdsa_privkey_test.go @@ -0,0 +1,17 @@ +package ecdsa + +func (suite *EcdsaSuite) TestSkString() { + suite.Require().Equal("secp256r1{-}", suite.sk.String()) +} + +func (suite *EcdsaSuite) xTestSkEqual() { + require := suite.Require() + + skOther, err := GenSecp256r1() + require.NoError(err) + require.False(suite.sk.Equals(skOther)) + + skOther2 := ecdsaSK{skOther.(ecdsaSK).PrivateKey} + require.True(skOther.Equals(skOther2)) + require.True(skOther2.Equals(skOther), "Equals must be reflexive") +} diff --git a/crypto/keys/ecdsa/ecdsa_pubkey.go b/crypto/keys/ecdsa/ecdsa_pubkey.go index 429f1dc82d76..e7ec36e42523 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey.go @@ -23,10 +23,7 @@ const ( // PubKeySize is is the size, in bytes, of public keys as used in this package. PubKeySize = 32 + 1 + 1 // PrivKeySize is the size, in bytes, of private keys as used in this package. - // PrivKeySize = 64 - // SeedSize is the size, in bytes, of private key seeds. These are the - // private key representations used by RFC 8032. - SeedSize = 32 + PrivKeySize = 32 + 1 ) var secp256r1 elliptic.Curve @@ -61,7 +58,7 @@ type signature struct { } type ecdsaPK struct { - *ecdsa.PublicKey + ecdsa.PublicKey // cache address tmcrypto.Address @@ -94,14 +91,13 @@ func (pk ecdsaPK) Bytes() []byte { // Equals - you probably don't need to use this. // Runs in constant time based on length of the keys. -// TODO: change to Equals func (pk ecdsaPK) Equals(other cryptotypes.PubKey) bool { pk2, ok := other.(ecdsaPK) if !ok { return false } - return pk.PublicKey.Equal(pk2.PublicKey) + return pk.PublicKey.Equal(&pk2.PublicKey) } // VerifySignature implements skd.PubKey interface @@ -112,7 +108,7 @@ func (pk ecdsaPK) VerifySignature(msg []byte, sig []byte) bool { } h := sha256.Sum256(msg) - return ecdsa.Verify(pk.PublicKey, h[:], s.R, s.S) + return ecdsa.Verify(&pk.PublicKey, h[:], s.R, s.S) } // Type returns key type name. Implements sdk.PubKey interface @@ -155,7 +151,8 @@ func (pk *ecdsaPK) UnmarshalAmino(bz []byte) error { if x == nil || y == nil { return errors.Wrap(errors.ErrInvalidPubKey, "invalid pubkey bytes") } - pk.PublicKey = &ecdsa.PublicKey{Curve: curve, X: x, Y: y} + pk.PublicKey.Curve = curve + pk.PublicKey.X, pk.PublicKey.Y = x, y return nil } diff --git a/crypto/keys/ecdsa/ecdsa_pubkey_test.go b/crypto/keys/ecdsa/ecdsa_pubkey_test.go index e2afccc854fd..6a4e7a23bea9 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey_test.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey_test.go @@ -12,7 +12,7 @@ import ( type EcdsaSuite struct { suite.Suite pk cryptotypes.PubKey - sk ecdsaSK + sk cryptotypes.PrivKey } func TestEcdsaSuite(t *testing.T) { @@ -21,7 +21,8 @@ func TestEcdsaSuite(t *testing.T) { func (suite *EcdsaSuite) SetupSuite() { sk, err := GenSecp256r1() - suite.Assert().NoError(err) + suite.Require().NoError(err) + suite.sk = sk suite.pk = sk.PubKey() } @@ -41,17 +42,17 @@ func (suite *EcdsaSuite) TestString() { } func (suite *EcdsaSuite) TestEqual() { - assert := suite.Assert() + require := suite.Require() skOther, err := GenSecp256r1() - assert.NoError(err) + require.NoError(err) pkOther := skOther.PubKey() - pkOther2 := ecdsaPK{&skOther.PublicKey, nil} + pkOther2 := ecdsaPK{skOther.(ecdsaSK).PublicKey, nil} - assert.False(suite.pk.Equals(pkOther)) + require.False(suite.pk.Equals(pkOther)) - assert.True(pkOther.Equals(pkOther2)) - assert.True(pkOther2.Equals(pkOther), "Equals must be reflexive") + require.True(pkOther.Equals(pkOther2)) + require.True(pkOther2.Equals(pkOther), "Equals must be reflexive") } func (suite *EcdsaSuite) TestMarshalAmino() { From 9e66ef6edf3aceee296676d7b1f656f5bbd82b67 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 18 Feb 2021 12:25:44 +0100 Subject: [PATCH 27/70] re-enable test --- crypto/keys/ecdsa/ecdsa_privkey_test.go | 2 +- crypto/keys/ecdsa/ecdsa_pubkey_test.go | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/crypto/keys/ecdsa/ecdsa_privkey_test.go b/crypto/keys/ecdsa/ecdsa_privkey_test.go index f420068d8ee1..c031e2e517dc 100644 --- a/crypto/keys/ecdsa/ecdsa_privkey_test.go +++ b/crypto/keys/ecdsa/ecdsa_privkey_test.go @@ -4,7 +4,7 @@ func (suite *EcdsaSuite) TestSkString() { suite.Require().Equal("secp256r1{-}", suite.sk.String()) } -func (suite *EcdsaSuite) xTestSkEqual() { +func (suite *EcdsaSuite) TestSkEqual() { require := suite.Require() skOther, err := GenSecp256r1() diff --git a/crypto/keys/ecdsa/ecdsa_pubkey_test.go b/crypto/keys/ecdsa/ecdsa_pubkey_test.go index 6a4e7a23bea9..f13bb82c39d3 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey_test.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey_test.go @@ -41,7 +41,7 @@ func (suite *EcdsaSuite) TestString() { assert.EqualValues(suite.pk.Bytes(), bz) } -func (suite *EcdsaSuite) TestEqual() { +func (suite *EcdsaSuite) TestEquals() { require := suite.Require() skOther, err := GenSecp256r1() @@ -50,7 +50,6 @@ func (suite *EcdsaSuite) TestEqual() { pkOther2 := ecdsaPK{skOther.(ecdsaSK).PublicKey, nil} require.False(suite.pk.Equals(pkOther)) - require.True(pkOther.Equals(pkOther2)) require.True(pkOther2.Equals(pkOther), "Equals must be reflexive") } From ab780db15a78c5cd8a7f754c998c5cd18656385d Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 18 Feb 2021 14:36:00 +0100 Subject: [PATCH 28/70] fix equals test --- crypto/keys/ecdsa/ecdsa_privkey.go | 17 ++++++++++++++++- crypto/keys/ecdsa/ecdsa_privkey_test.go | 4 ++-- crypto/keys/ecdsa/ecdsa_pubkey.go | 2 +- crypto/keys/ecdsa/ecdsa_pubkey_test.go | 4 ++++ 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/crypto/keys/ecdsa/ecdsa_privkey.go b/crypto/keys/ecdsa/ecdsa_privkey.go index ac24d18e3a2f..9148143e8539 100644 --- a/crypto/keys/ecdsa/ecdsa_privkey.go +++ b/crypto/keys/ecdsa/ecdsa_privkey.go @@ -1,9 +1,11 @@ package ecdsa import ( + "crypto" "crypto/ecdsa" "crypto/rand" "crypto/sha256" + "fmt" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" ) @@ -43,7 +45,20 @@ func (sk ecdsaSK) Equals(other cryptotypes.LedgerPrivKey) bool { if !ok { return false } - return sk.PrivateKey.Equal(sk2.PrivateKey) + // return EcEqual(&sk.PrivateKey, &sk2.PrivateKey) + + return sk.PrivateKey.Equal(&sk2.PrivateKey) +} + +// TODO: remove +// See PublicKey.Equal for details on how Curve is compared. +func EcEqual(priv *ecdsa.PrivateKey, x crypto.PrivateKey) bool { + xx, ok := x.(*ecdsa.PrivateKey) + if !ok { + fmt.Println("not *ecdsa.PrivateKey") + return false + } + return priv.PublicKey.Equal(&xx.PublicKey) && priv.D.Cmp(xx.D) == 0 } // Type returns key type name. Implements sdk.PrivKey interface diff --git a/crypto/keys/ecdsa/ecdsa_privkey_test.go b/crypto/keys/ecdsa/ecdsa_privkey_test.go index c031e2e517dc..9720e1796e2b 100644 --- a/crypto/keys/ecdsa/ecdsa_privkey_test.go +++ b/crypto/keys/ecdsa/ecdsa_privkey_test.go @@ -9,9 +9,9 @@ func (suite *EcdsaSuite) TestSkEqual() { skOther, err := GenSecp256r1() require.NoError(err) - require.False(suite.sk.Equals(skOther)) + // require.False(suite.sk.Equals(skOther)) skOther2 := ecdsaSK{skOther.(ecdsaSK).PrivateKey} require.True(skOther.Equals(skOther2)) - require.True(skOther2.Equals(skOther), "Equals must be reflexive") + // require.True(skOther2.Equals(skOther), "Equals must be reflexive") } diff --git a/crypto/keys/ecdsa/ecdsa_pubkey.go b/crypto/keys/ecdsa/ecdsa_pubkey.go index e7ec36e42523..20aa91d9321b 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey.go @@ -64,7 +64,7 @@ type ecdsaPK struct { address tmcrypto.Address } -var _ cryptotypes.PubKey = &ecdsaPK{} +var _ cryptotypes.PubKey = ecdsaPK{} // String implements PubKey interface func (pk ecdsaPK) Address() tmcrypto.Address { diff --git a/crypto/keys/ecdsa/ecdsa_pubkey_test.go b/crypto/keys/ecdsa/ecdsa_pubkey_test.go index f13bb82c39d3..7b44681b2642 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey_test.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey_test.go @@ -69,3 +69,7 @@ func (suite *EcdsaSuite) TestMarshalAmino() { require.NoError(pk2.UnmarshalAmino(bz)) require.True(pk2.Equals(suite.pk)) } + +func (suite *EcdsaSuite) TestMarshalProto() { + +} From 0ac339f7e72c53e236af687467ac1eeab4e5d518 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Mon, 22 Feb 2021 15:56:58 +0100 Subject: [PATCH 29/70] fix ecdsa object receiver --- crypto/keys/ecdsa/ecdsa_privkey.go | 2 +- crypto/keys/ecdsa/ecdsa_pubkey.go | 70 ++++++++++++++++++++------ crypto/keys/ecdsa/ecdsa_pubkey_test.go | 37 +++++++++++++- 3 files changed, 92 insertions(+), 17 deletions(-) diff --git a/crypto/keys/ecdsa/ecdsa_privkey.go b/crypto/keys/ecdsa/ecdsa_privkey.go index 9148143e8539..74dabbcaeee7 100644 --- a/crypto/keys/ecdsa/ecdsa_privkey.go +++ b/crypto/keys/ecdsa/ecdsa_privkey.go @@ -27,7 +27,7 @@ func GenSecp256r1() (cryptotypes.PrivKey, error) { // PubKey implements SDK PrivKey interface func (sk ecdsaSK) PubKey() cryptotypes.PubKey { - return ecdsaPK{sk.PublicKey, nil} + return &ecdsaPK{sk.PublicKey, nil} } // Bytes serialize the private key with first byte being the curve type diff --git a/crypto/keys/ecdsa/ecdsa_pubkey.go b/crypto/keys/ecdsa/ecdsa_pubkey.go index 20aa91d9321b..294d385120c5 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey.go @@ -8,6 +8,8 @@ import ( "fmt" "math/big" + "github.com/gogo/protobuf/proto" + gogotypes "github.com/gogo/protobuf/types" tmcrypto "github.com/tendermint/tendermint/crypto" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -64,10 +66,8 @@ type ecdsaPK struct { address tmcrypto.Address } -var _ cryptotypes.PubKey = ecdsaPK{} - // String implements PubKey interface -func (pk ecdsaPK) Address() tmcrypto.Address { +func (pk *ecdsaPK) Address() tmcrypto.Address { if pk.address == nil { pk.address = address.Hash(curveNames[pk.Curve], pk.Bytes()) } @@ -75,13 +75,13 @@ func (pk ecdsaPK) Address() tmcrypto.Address { } // String implements PubKey interface -func (pk ecdsaPK) String() string { +func (pk *ecdsaPK) String() string { return fmt.Sprintf("%s{%X}", curveNames[pk.Curve], pk.Bytes()) } // Bytes returns the byte representation of the public key using a compressed form // specified in section 4.3.6 of ANSI X9.62 with first byte being the curve type. -func (pk ecdsaPK) Bytes() []byte { +func (pk *ecdsaPK) Bytes() []byte { compressed := make([]byte, PubKeySize) compressed[0] = curveTypes[pk.Curve] compressed[1] = byte(pk.Y.Bit(0)) | 2 @@ -91,8 +91,8 @@ func (pk ecdsaPK) Bytes() []byte { // Equals - you probably don't need to use this. // Runs in constant time based on length of the keys. -func (pk ecdsaPK) Equals(other cryptotypes.PubKey) bool { - pk2, ok := other.(ecdsaPK) +func (pk *ecdsaPK) Equals(other cryptotypes.PubKey) bool { + pk2, ok := other.(*ecdsaPK) if !ok { return false } @@ -101,7 +101,7 @@ func (pk ecdsaPK) Equals(other cryptotypes.PubKey) bool { } // VerifySignature implements skd.PubKey interface -func (pk ecdsaPK) VerifySignature(msg []byte, sig []byte) bool { +func (pk *ecdsaPK) VerifySignature(msg []byte, sig []byte) bool { s := new(signature) if _, err := asn1.Unmarshal(sig, s); err != nil || s == nil { return false @@ -112,29 +112,69 @@ func (pk ecdsaPK) VerifySignature(msg []byte, sig []byte) bool { } // Type returns key type name. Implements sdk.PubKey interface -func (pk ecdsaPK) Type() string { +func (pk *ecdsaPK) Type() string { return curveNames[pk.Curve] } // **** proto.Message **** -func (pk ecdsaPK) Reset() {} // TODO: maybe we need to have this? -func (ecdsaPK) ProtoMessage() {} +func (pk *ecdsaPK) Reset() {} // TODO: maybe we need to have this? +func (*ecdsaPK) ProtoMessage() {} + +// **** Proto Marshaler **** + +func (pk *ecdsaPK) Marshal() ([]byte, error) { + bv := gogotypes.BytesValue{Value: pk.Bytes()} + return proto.Marshal(&bv) +} + +func (pk *ecdsaPK) Unmarshal(b []byte) error { + bv := gogotypes.BytesValue{} + err := proto.Unmarshal(b, &bv) + if err != nil { + return err + } + if len(bv.Value) < 2 { + return fmt.Errorf("wrong ECDSA PK bytes, expecting at least 2 bytes") + } + + curve, ok := curveTypesRev[bv.Value[0]] + if !ok { + return fmt.Errorf("wrong ECDSA PK bytes, unknown curve type: %d", bv.Value[0]) + } + cpk := ecdsa.PublicKey{Curve: curve} + cpk.X, cpk.Y = elliptic.UnmarshalCompressed(curve, bv.Value[1:]) + if cpk.X == nil || cpk.Y == nil { + return fmt.Errorf("wrong ECDSA PK bytes") + } + + if pk == nil { + *pk = ecdsaPK{cpk, nil} + } else { + pk.PublicKey = cpk + } + + return nil + // addrValue := gogotypes.BytesValue{} + // bz, err := proto.Marshal(suite.pk) + // k.cdc.MustUnmarshalBinaryBare(bz, &addrValue) + +} /* -ProtoMarshaler interface { + ProtoMarshaler interface { Marshal() ([]byte, error) MarshalTo(data []byte) (n int, err error) MarshalToSizedBuffer(dAtA []byte) (int, error) Size() int Unmarshal(data []byte) error -} + } */ // **** Amino Marshaler **** // MarshalAmino overrides Amino binary marshalling. -func (pk ecdsaPK) MarshalAmino() ([]byte, error) { +func (pk *ecdsaPK) MarshalAmino() ([]byte, error) { return pk.Bytes(), nil } @@ -157,7 +197,7 @@ func (pk *ecdsaPK) UnmarshalAmino(bz []byte) error { } // MarshalAminoJSON overrides Amino JSON marshalling. -func (pk ecdsaPK) MarshalAminoJSON() ([]byte, error) { +func (pk *ecdsaPK) MarshalAminoJSON() ([]byte, error) { return pk.MarshalAmino() } diff --git a/crypto/keys/ecdsa/ecdsa_pubkey_test.go b/crypto/keys/ecdsa/ecdsa_pubkey_test.go index 7b44681b2642..344d91cf7457 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey_test.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey_test.go @@ -2,8 +2,10 @@ package ecdsa import ( "encoding/hex" + "fmt" "testing" + proto "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/suite" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -47,7 +49,7 @@ func (suite *EcdsaSuite) TestEquals() { skOther, err := GenSecp256r1() require.NoError(err) pkOther := skOther.PubKey() - pkOther2 := ecdsaPK{skOther.(ecdsaSK).PublicKey, nil} + pkOther2 := &ecdsaPK{skOther.(ecdsaSK).PublicKey, nil} require.False(suite.pk.Equals(pkOther)) require.True(pkOther.Equals(pkOther2)) @@ -71,5 +73,38 @@ func (suite *EcdsaSuite) TestMarshalAmino() { } func (suite *EcdsaSuite) TestMarshalProto() { + require := suite.Require() + // registry := types.NewInterfaceRegistry() + // cdc := codec.NewProtoCodec(registry) + + bz, err := proto.Marshal(suite.pk) + require.NoError(err) + fmt.Println("bytes:", bz) + + // bz, err := cdc.MarshalInterface(suite) + // require.NoError(t, err) + + // var animal testdata.Animal + + // // empty registry should fail + // err = cdc.UnmarshalInterface(bz, &animal) + // require.Error(t, err) + + // // wrong type registration should fail + // registry.RegisterImplementations((*testdata.Animal)(nil), &testdata.Dog{}) + // err = cdc.UnmarshalInterface(bz, &animal) + // require.Error(t, err) + + // // should pass + // registry = NewTestInterfaceRegistry() + // cdc = codec.NewProtoCodec(registry) + // err = cdc.UnmarshalInterface(bz, &animal) + // require.NoError(t, err) + // require.Equal(t, kitty, animal) + + // // nil should fail + // registry = NewTestInterfaceRegistry() + // err = cdc.UnmarshalInterface(bz, nil) + // require.Error(t, err) } From 8d08d8b2aaaaf5da824c29b15efb8c096b3d0db8 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Tue, 23 Feb 2021 22:08:22 +0100 Subject: [PATCH 30/70] add ProtoMarshaler implementation and tests --- crypto/keys/ecdsa/ecdsa_pubkey.go | 48 ++++++++++++------- crypto/keys/ecdsa/ecdsa_pubkey_test.go | 64 +++++++++++++++----------- 2 files changed, 70 insertions(+), 42 deletions(-) diff --git a/crypto/keys/ecdsa/ecdsa_pubkey.go b/crypto/keys/ecdsa/ecdsa_pubkey.go index 294d385120c5..3793493e1b87 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey.go @@ -7,8 +7,8 @@ import ( "encoding/asn1" "fmt" "math/big" + math_bits "math/bits" - "github.com/gogo/protobuf/proto" gogotypes "github.com/gogo/protobuf/types" tmcrypto "github.com/tendermint/tendermint/crypto" @@ -33,6 +33,10 @@ var curveNames map[elliptic.Curve]string var curveTypes map[elliptic.Curve]byte var curveTypesRev map[byte]elliptic.Curve +// Protobuf Bytes size - this computation is based on gogotypes.BytesValue.Sizee implementation +var sovPubKeySize = 1 + PubKeySize + sovKeys(PubKeySize) +var sovPrivKeySize = 1 + PrivKeySize + sovKeys(PrivKeySize) + func init() { secp256r1 = elliptic.P256() // PubKeySize is ceil of field bit size + 1 for the sign + 1 for the type @@ -123,14 +127,28 @@ func (*ecdsaPK) ProtoMessage() {} // **** Proto Marshaler **** +// Marshal implements ProtoMarshaler interface func (pk *ecdsaPK) Marshal() ([]byte, error) { bv := gogotypes.BytesValue{Value: pk.Bytes()} - return proto.Marshal(&bv) + return bv.Marshal() +} + +// MarshalTo implements ProtoMarshaler interface +func (pk *ecdsaPK) MarshalTo(data []byte) (int, error) { + bv := gogotypes.BytesValue{Value: pk.Bytes()} + return bv.MarshalTo(data) +} + +// MarshalToSizedBuffer implements ProtoMarshaler interface +func (pk *ecdsaPK) MarshalToSizedBuffer(dAtA []byte) (int, error) { + bv := gogotypes.BytesValue{Value: pk.Bytes()} + return bv.MarshalToSizedBuffer(dAtA) } +// Unmarshal implements ProtoMarshaler interface func (pk *ecdsaPK) Unmarshal(b []byte) error { bv := gogotypes.BytesValue{} - err := proto.Unmarshal(b, &bv) + err := bv.Unmarshal(b) if err != nil { return err } @@ -155,21 +173,15 @@ func (pk *ecdsaPK) Unmarshal(b []byte) error { } return nil - // addrValue := gogotypes.BytesValue{} - // bz, err := proto.Marshal(suite.pk) - // k.cdc.MustUnmarshalBinaryBare(bz, &addrValue) - } -/* - ProtoMarshaler interface { - Marshal() ([]byte, error) - MarshalTo(data []byte) (n int, err error) - MarshalToSizedBuffer(dAtA []byte) (int, error) - Size() int - Unmarshal(data []byte) error - } -*/ +// Size implements ProtoMarshaler interface +func (pk *ecdsaPK) Size() int { + if pk == nil { + return 0 + } + return sovPubKeySize +} // **** Amino Marshaler **** @@ -205,3 +217,7 @@ func (pk *ecdsaPK) MarshalAminoJSON() ([]byte, error) { func (pk *ecdsaPK) UnmarshalAminoJSON(bz []byte) error { return pk.UnmarshalAmino(bz) } + +func sovKeys(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} diff --git a/crypto/keys/ecdsa/ecdsa_pubkey_test.go b/crypto/keys/ecdsa/ecdsa_pubkey_test.go index 344d91cf7457..a4788e44ad73 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey_test.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey_test.go @@ -2,12 +2,14 @@ package ecdsa import ( "encoding/hex" - "fmt" "testing" proto "github.com/gogo/protobuf/proto" + gogotypes "github.com/gogo/protobuf/types" "github.com/stretchr/testify/suite" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" ) @@ -53,7 +55,8 @@ func (suite *EcdsaSuite) TestEquals() { require.False(suite.pk.Equals(pkOther)) require.True(pkOther.Equals(pkOther2)) - require.True(pkOther2.Equals(pkOther), "Equals must be reflexive") + require.True(pkOther2.Equals(pkOther)) + require.True(pkOther.Equals(pkOther), "Equals must be reflexive") } func (suite *EcdsaSuite) TestMarshalAmino() { @@ -72,39 +75,48 @@ func (suite *EcdsaSuite) TestMarshalAmino() { require.True(pk2.Equals(suite.pk)) } +func (suite *EcdsaSuite) TestSize() { + require := suite.Require() + bv := gogotypes.BytesValue{Value: suite.pk.Bytes()} + require.Equal(bv.Size(), suite.pk.(*ecdsaPK).Size()) + + var nilPk *ecdsaPK + require.Equal(0, nilPk.Size(), "nil value must have zero size") +} + func (suite *EcdsaSuite) TestMarshalProto() { require := suite.Require() - // registry := types.NewInterfaceRegistry() - // cdc := codec.NewProtoCodec(registry) + /**** test structure marshalling ****/ + + var pk ecdsaPK bz, err := proto.Marshal(suite.pk) require.NoError(err) - fmt.Println("bytes:", bz) - - // bz, err := cdc.MarshalInterface(suite) - // require.NoError(t, err) + require.NoError(proto.Unmarshal(bz, &pk)) + require.True(pk.Equals(suite.pk)) - // var animal testdata.Animal + /**** test structure marshalling with codec ****/ - // // empty registry should fail - // err = cdc.UnmarshalInterface(bz, &animal) - // require.Error(t, err) + pk = ecdsaPK{} + registry := types.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(registry) + bz, err = cdc.MarshalBinaryBare(suite.pk.(*ecdsaPK)) + require.NoError(err) + require.NoError(cdc.UnmarshalBinaryBare(bz, &pk)) + require.True(pk.Equals(suite.pk)) - // // wrong type registration should fail - // registry.RegisterImplementations((*testdata.Animal)(nil), &testdata.Dog{}) - // err = cdc.UnmarshalInterface(bz, &animal) - // require.Error(t, err) + /**** test interface marshalling ****/ - // // should pass - // registry = NewTestInterfaceRegistry() - // cdc = codec.NewProtoCodec(registry) - // err = cdc.UnmarshalInterface(bz, &animal) - // require.NoError(t, err) - // require.Equal(t, kitty, animal) + bz, err = cdc.MarshalInterface(suite.pk) + require.NoError(err) + var pkI cryptotypes.PubKey + err = cdc.UnmarshalInterface(bz, &pkI) + require.EqualError(err, "no registered implementations of type types.PubKey") - // // nil should fail - // registry = NewTestInterfaceRegistry() - // err = cdc.UnmarshalInterface(bz, nil) - // require.Error(t, err) + registry.RegisterImplementations((*cryptotypes.PubKey)(nil), new(ecdsaPK)) + require.NoError(cdc.UnmarshalInterface(bz, &pkI)) + require.True(pkI.Equals(suite.pk)) + cdc.UnmarshalInterface(bz, nil) + require.Error(err, "nil should fail") } From 0434d8da24e6d793ab44b1e3a98082eb3fc829f2 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Tue, 23 Feb 2021 22:22:11 +0100 Subject: [PATCH 31/70] move code to init and add interface registry --- crypto/codec/proto.go | 11 ++++--- crypto/keys/ecdsa/ecdsa_pubkey.go | 41 ------------------------- crypto/keys/ecdsa/init.go | 51 +++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 45 deletions(-) create mode 100644 crypto/keys/ecdsa/init.go diff --git a/crypto/codec/proto.go b/crypto/codec/proto.go index 9c07ca110596..7b4bd3b5042b 100644 --- a/crypto/codec/proto.go +++ b/crypto/codec/proto.go @@ -2,6 +2,7 @@ package codec import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/ecdsa" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "github.com/cosmos/cosmos-sdk/crypto/keys/multisig" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" @@ -10,8 +11,10 @@ import ( // RegisterInterfaces registers the sdk.Tx interface. func RegisterInterfaces(registry codectypes.InterfaceRegistry) { - registry.RegisterInterface("cosmos.crypto.PubKey", (*cryptotypes.PubKey)(nil)) - registry.RegisterImplementations((*cryptotypes.PubKey)(nil), &ed25519.PubKey{}) - registry.RegisterImplementations((*cryptotypes.PubKey)(nil), &secp256k1.PubKey{}) - registry.RegisterImplementations((*cryptotypes.PubKey)(nil), &multisig.LegacyAminoPubKey{}) + var pk *cryptotypes.PubKey + registry.RegisterInterface("cosmos.crypto.PubKey", pk) + registry.RegisterImplementations(pk, &ed25519.PubKey{}) + registry.RegisterImplementations(pk, &secp256k1.PubKey{}) + registry.RegisterImplementations(pk, &multisig.LegacyAminoPubKey{}) + ecdsa.RegisterInterfaces(registry) } diff --git a/crypto/keys/ecdsa/ecdsa_pubkey.go b/crypto/keys/ecdsa/ecdsa_pubkey.go index 3793493e1b87..190d758de041 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey.go @@ -17,47 +17,6 @@ import ( "github.com/cosmos/cosmos-sdk/types/errors" ) -// "github.com/cosmos/cosmos-sdk/codec" -// -// "github.com/cosmos/cosmos-sdk/types/errors" - -const ( - // PubKeySize is is the size, in bytes, of public keys as used in this package. - PubKeySize = 32 + 1 + 1 - // PrivKeySize is the size, in bytes, of private keys as used in this package. - PrivKeySize = 32 + 1 -) - -var secp256r1 elliptic.Curve -var curveNames map[elliptic.Curve]string -var curveTypes map[elliptic.Curve]byte -var curveTypesRev map[byte]elliptic.Curve - -// Protobuf Bytes size - this computation is based on gogotypes.BytesValue.Sizee implementation -var sovPubKeySize = 1 + PubKeySize + sovKeys(PubKeySize) -var sovPrivKeySize = 1 + PrivKeySize + sovKeys(PrivKeySize) - -func init() { - secp256r1 = elliptic.P256() - // PubKeySize is ceil of field bit size + 1 for the sign + 1 for the type - expected := (secp256r1.Params().BitSize+7)/8 + 2 - if expected != PubKeySize { - panic(fmt.Sprintf("Wrong PubKeySize=%d, expecting=%d", PubKeySize, expected)) - } - - curveNames = map[elliptic.Curve]string{ - secp256r1: "secp256r1", - } - curveTypes = map[elliptic.Curve]byte{ - // 0 reserved - secp256r1: 1, - } - curveTypesRev = map[byte]elliptic.Curve{} - for c, b := range curveTypes { - curveTypesRev[b] = c - } -} - // signature holds the r and s values of an ECDSA signature type signature struct { R, S *big.Int diff --git a/crypto/keys/ecdsa/init.go b/crypto/keys/ecdsa/init.go new file mode 100644 index 000000000000..22cdf20bd604 --- /dev/null +++ b/crypto/keys/ecdsa/init.go @@ -0,0 +1,51 @@ +package ecdsa + +import ( + "crypto/elliptic" + "fmt" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" +) + +const ( + // PubKeySize is is the size, in bytes, of public keys as used in this package. + PubKeySize = 32 + 1 + 1 + // PrivKeySize is the size, in bytes, of private keys as used in this package. + PrivKeySize = 32 + 1 +) + +var secp256r1 elliptic.Curve +var curveNames map[elliptic.Curve]string +var curveTypes map[elliptic.Curve]byte +var curveTypesRev map[byte]elliptic.Curve + +// Protobuf Bytes size - this computation is based on gogotypes.BytesValue.Sizee implementation +var sovPubKeySize = 1 + PubKeySize + sovKeys(PubKeySize) +var sovPrivKeySize = 1 + PrivKeySize + sovKeys(PrivKeySize) + +func init() { + secp256r1 = elliptic.P256() + // PubKeySize is ceil of field bit size + 1 for the sign + 1 for the type + expected := (secp256r1.Params().BitSize+7)/8 + 2 + if expected != PubKeySize { + panic(fmt.Sprintf("Wrong PubKeySize=%d, expecting=%d", PubKeySize, expected)) + } + + curveNames = map[elliptic.Curve]string{ + secp256r1: "secp256r1", + } + curveTypes = map[elliptic.Curve]byte{ + // 0 reserved + secp256r1: 1, + } + curveTypesRev = map[byte]elliptic.Curve{} + for c, b := range curveTypes { + curveTypesRev[b] = c + } +} + +// RegisterInterfaces adds ecdsa PubKey to pubkey registry +func RegisterInterfaces(registry codectypes.InterfaceRegistry) { + registry.RegisterImplementations((*cryptotypes.PubKey)(nil), &ecdsaPK{}) +} From 6a8ada7df19f2b40db8df0b0412a31b161307f78 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Tue, 23 Feb 2021 23:05:12 +0100 Subject: [PATCH 32/70] add bytes tests --- crypto/keys/ecdsa/ecdsa_pubkey.go | 3 +++ crypto/keys/ecdsa/ecdsa_pubkey_test.go | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/crypto/keys/ecdsa/ecdsa_pubkey.go b/crypto/keys/ecdsa/ecdsa_pubkey.go index 190d758de041..8b623ca796ca 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey.go @@ -45,6 +45,9 @@ func (pk *ecdsaPK) String() string { // Bytes returns the byte representation of the public key using a compressed form // specified in section 4.3.6 of ANSI X9.62 with first byte being the curve type. func (pk *ecdsaPK) Bytes() []byte { + if pk == nil { + return nil + } compressed := make([]byte, PubKeySize) compressed[0] = curveTypes[pk.Curve] compressed[1] = byte(pk.Y.Bit(0)) | 2 diff --git a/crypto/keys/ecdsa/ecdsa_pubkey_test.go b/crypto/keys/ecdsa/ecdsa_pubkey_test.go index a4788e44ad73..c6806ae4e430 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey_test.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey_test.go @@ -45,6 +45,13 @@ func (suite *EcdsaSuite) TestString() { assert.EqualValues(suite.pk.Bytes(), bz) } +func (suite *EcdsaSuite) TestBytes() { + require := suite.Require() + var pk *ecdsaPK + require.Nil(pk.Bytes()) + require.Len(suite.pk.Bytes(), PubKeySize) +} + func (suite *EcdsaSuite) TestEquals() { require := suite.Require() From c414ca0212196ebb641e708512c8de44bc399f66 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Tue, 23 Feb 2021 23:31:59 +0100 Subject: [PATCH 33/70] merge Unmarshal with UnmarshalAmino --- crypto/keys/ecdsa/ecdsa_pubkey.go | 49 ++++++++------------------ crypto/keys/ecdsa/ecdsa_pubkey_test.go | 35 ++++++++++++++---- crypto/keys/ecdsa/init.go | 5 +++ 3 files changed, 49 insertions(+), 40 deletions(-) diff --git a/crypto/keys/ecdsa/ecdsa_pubkey.go b/crypto/keys/ecdsa/ecdsa_pubkey.go index 8b623ca796ca..e6adffc5c40c 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey.go @@ -7,7 +7,6 @@ import ( "encoding/asn1" "fmt" "math/big" - math_bits "math/bits" gogotypes "github.com/gogo/protobuf/types" tmcrypto "github.com/tendermint/tendermint/crypto" @@ -84,7 +83,9 @@ func (pk *ecdsaPK) Type() string { // **** proto.Message **** -func (pk *ecdsaPK) Reset() {} // TODO: maybe we need to have this? +func (pk *ecdsaPK) Reset() { + *pk = ecdsaPK{} +} func (*ecdsaPK) ProtoMessage() {} // **** Proto Marshaler **** @@ -114,27 +115,7 @@ func (pk *ecdsaPK) Unmarshal(b []byte) error { if err != nil { return err } - if len(bv.Value) < 2 { - return fmt.Errorf("wrong ECDSA PK bytes, expecting at least 2 bytes") - } - - curve, ok := curveTypesRev[bv.Value[0]] - if !ok { - return fmt.Errorf("wrong ECDSA PK bytes, unknown curve type: %d", bv.Value[0]) - } - cpk := ecdsa.PublicKey{Curve: curve} - cpk.X, cpk.Y = elliptic.UnmarshalCompressed(curve, bv.Value[1:]) - if cpk.X == nil || cpk.Y == nil { - return fmt.Errorf("wrong ECDSA PK bytes") - } - - if pk == nil { - *pk = ecdsaPK{cpk, nil} - } else { - pk.PublicKey = cpk - } - - return nil + return pk.UnmarshalAmino(bv.Value) } // Size implements ProtoMarshaler interface @@ -155,18 +136,22 @@ func (pk *ecdsaPK) MarshalAmino() ([]byte, error) { // UnmarshalAmino overrides Amino binary marshalling. func (pk *ecdsaPK) UnmarshalAmino(bz []byte) error { if len(bz) != PubKeySize { - return errors.Wrap(errors.ErrInvalidPubKey, "invalid pubkey size") + return errors.Wrapf(errors.ErrInvalidPubKey, "wrong ECDSA PK bytes, expecting %d bytes", PubKeySize) } curve, ok := curveTypesRev[bz[0]] if !ok { - return errors.Wrap(errors.ErrInvalidPubKey, "invalid curve type") + return errors.Wrapf(errors.ErrInvalidPubKey, "wrong ECDSA PK bytes, unknown curve type: %d", bz[0]) + } + cpk := ecdsa.PublicKey{Curve: curve} + cpk.X, cpk.Y = elliptic.UnmarshalCompressed(curve, bz[1:]) + if cpk.X == nil || cpk.Y == nil { + return errors.Wrapf(errors.ErrInvalidPubKey, "wrong ECDSA PK bytes, unknown curve type: %d", bz[0]) } - x, y := elliptic.UnmarshalCompressed(curve, bz[1:]) - if x == nil || y == nil { - return errors.Wrap(errors.ErrInvalidPubKey, "invalid pubkey bytes") + if pk == nil { + *pk = ecdsaPK{cpk, nil} + } else { + pk.PublicKey = cpk } - pk.PublicKey.Curve = curve - pk.PublicKey.X, pk.PublicKey.Y = x, y return nil } @@ -179,7 +164,3 @@ func (pk *ecdsaPK) MarshalAminoJSON() ([]byte, error) { func (pk *ecdsaPK) UnmarshalAminoJSON(bz []byte) error { return pk.UnmarshalAmino(bz) } - -func sovKeys(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} diff --git a/crypto/keys/ecdsa/ecdsa_pubkey_test.go b/crypto/keys/ecdsa/ecdsa_pubkey_test.go index c6806ae4e430..d7203b64f3f9 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey_test.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey_test.go @@ -1,7 +1,9 @@ package ecdsa import ( + "crypto/ecdsa" "encoding/hex" + "math/big" "testing" proto "github.com/gogo/protobuf/proto" @@ -30,7 +32,7 @@ func (suite *EcdsaSuite) SetupSuite() { suite.pk = sk.PubKey() } -func (suite *EcdsaSuite) TestString() { +func (suite *EcdsaSuite) TestPKString() { assert := suite.Assert() require := suite.Require() @@ -45,14 +47,14 @@ func (suite *EcdsaSuite) TestString() { assert.EqualValues(suite.pk.Bytes(), bz) } -func (suite *EcdsaSuite) TestBytes() { +func (suite *EcdsaSuite) TestPKBytes() { require := suite.Require() var pk *ecdsaPK require.Nil(pk.Bytes()) require.Len(suite.pk.Bytes(), PubKeySize) } -func (suite *EcdsaSuite) TestEquals() { +func (suite *EcdsaSuite) TestPKEquals() { require := suite.Require() skOther, err := GenSecp256r1() @@ -66,7 +68,7 @@ func (suite *EcdsaSuite) TestEquals() { require.True(pkOther.Equals(pkOther), "Equals must be reflexive") } -func (suite *EcdsaSuite) TestMarshalAmino() { +func (suite *EcdsaSuite) TestPKMarshalAmino() { require := suite.Require() type AminoPubKey interface { cryptotypes.PubKey @@ -82,7 +84,7 @@ func (suite *EcdsaSuite) TestMarshalAmino() { require.True(pk2.Equals(suite.pk)) } -func (suite *EcdsaSuite) TestSize() { +func (suite *EcdsaSuite) TestPKSize() { require := suite.Require() bv := gogotypes.BytesValue{Value: suite.pk.Bytes()} require.Equal(bv.Size(), suite.pk.(*ecdsaPK).Size()) @@ -91,7 +93,7 @@ func (suite *EcdsaSuite) TestSize() { require.Equal(0, nilPk.Size(), "nil value must have zero size") } -func (suite *EcdsaSuite) TestMarshalProto() { +func (suite *EcdsaSuite) TestPKMarshalProto() { require := suite.Require() /**** test structure marshalling ****/ @@ -112,6 +114,20 @@ func (suite *EcdsaSuite) TestMarshalProto() { require.NoError(cdc.UnmarshalBinaryBare(bz, &pk)) require.True(pk.Equals(suite.pk)) + const bufSize = 100 + bz2 := make([]byte, bufSize) + pkCpy := suite.pk.(*ecdsaPK) + _, err = pkCpy.MarshalTo(bz2) + require.NoError(err) + require.Len(bz2, bufSize) + require.Equal(bz, bz2[:sovPubKeySize]) + + bz2 = make([]byte, bufSize) + _, err = pkCpy.MarshalToSizedBuffer(bz2) + require.NoError(err) + require.Len(bz2, bufSize) + require.Equal(bz, bz2[(bufSize-sovPubKeySize):]) + /**** test interface marshalling ****/ bz, err = cdc.MarshalInterface(suite.pk) @@ -127,3 +143,10 @@ func (suite *EcdsaSuite) TestMarshalProto() { cdc.UnmarshalInterface(bz, nil) require.Error(err, "nil should fail") } + +func (suite *EcdsaSuite) TestPKReset() { + pk := &ecdsaPK{ecdsa.PublicKey{X: big.NewInt(1)}, []byte{1}} + pk.Reset() + suite.Nil(pk.address) + suite.Equal(pk.PublicKey, ecdsa.PublicKey{}) +} diff --git a/crypto/keys/ecdsa/init.go b/crypto/keys/ecdsa/init.go index 22cdf20bd604..425a71577e36 100644 --- a/crypto/keys/ecdsa/init.go +++ b/crypto/keys/ecdsa/init.go @@ -3,6 +3,7 @@ package ecdsa import ( "crypto/elliptic" "fmt" + math_bits "math/bits" codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -49,3 +50,7 @@ func init() { func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterImplementations((*cryptotypes.PubKey)(nil), &ecdsaPK{}) } + +func sovKeys(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} From 7d1f6949f97cdbc206a1299d6cf9ac2106a89ad3 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 24 Feb 2021 00:22:50 +0100 Subject: [PATCH 34/70] implement ProtoMarshaler to ecdsaSK --- crypto/keys/ecdsa/ecdsa_privkey.go | 96 ++++++++++++++++++------- crypto/keys/ecdsa/ecdsa_privkey_test.go | 38 +++++++++- crypto/keys/ecdsa/ecdsa_pubkey_test.go | 2 +- 3 files changed, 109 insertions(+), 27 deletions(-) diff --git a/crypto/keys/ecdsa/ecdsa_privkey.go b/crypto/keys/ecdsa/ecdsa_privkey.go index 74dabbcaeee7..ec881bc16142 100644 --- a/crypto/keys/ecdsa/ecdsa_privkey.go +++ b/crypto/keys/ecdsa/ecdsa_privkey.go @@ -1,13 +1,14 @@ package ecdsa import ( - "crypto" "crypto/ecdsa" "crypto/rand" "crypto/sha256" "fmt" + "math/big" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + gogotypes "github.com/gogo/protobuf/types" ) // "github.com/cosmos/cosmos-sdk/codec" @@ -17,21 +18,22 @@ type ecdsaSK struct { ecdsa.PrivateKey } -var _ cryptotypes.PrivKey = ecdsaSK{} - // GenSecp256r1 generates a new secp256r1 private key. It uses OS randomness. func GenSecp256r1() (cryptotypes.PrivKey, error) { key, err := ecdsa.GenerateKey(secp256r1, rand.Reader) - return ecdsaSK{*key}, err + return &ecdsaSK{*key}, err } // PubKey implements SDK PrivKey interface -func (sk ecdsaSK) PubKey() cryptotypes.PubKey { +func (sk *ecdsaSK) PubKey() cryptotypes.PubKey { return &ecdsaPK{sk.PublicKey, nil} } // Bytes serialize the private key with first byte being the curve type -func (sk ecdsaSK) Bytes() []byte { +func (sk *ecdsaSK) Bytes() []byte { + if sk == nil { + return nil + } bz := make([]byte, PrivKeySize) bz[0] = curveTypes[sk.Curve] sk.D.FillBytes(bz[1:]) @@ -40,8 +42,8 @@ func (sk ecdsaSK) Bytes() []byte { // Equals - you probably don't need to use this. // Runs in constant time based on length of the keys. -func (sk ecdsaSK) Equals(other cryptotypes.LedgerPrivKey) bool { - sk2, ok := other.(ecdsaSK) +func (sk *ecdsaSK) Equals(other cryptotypes.LedgerPrivKey) bool { + sk2, ok := other.(*ecdsaSK) if !ok { return false } @@ -50,32 +52,78 @@ func (sk ecdsaSK) Equals(other cryptotypes.LedgerPrivKey) bool { return sk.PrivateKey.Equal(&sk2.PrivateKey) } -// TODO: remove -// See PublicKey.Equal for details on how Curve is compared. -func EcEqual(priv *ecdsa.PrivateKey, x crypto.PrivateKey) bool { - xx, ok := x.(*ecdsa.PrivateKey) - if !ok { - fmt.Println("not *ecdsa.PrivateKey") - return false - } - return priv.PublicKey.Equal(&xx.PublicKey) && priv.D.Cmp(xx.D) == 0 -} - // Type returns key type name. Implements sdk.PrivKey interface -func (sk ecdsaSK) Type() string { +func (sk *ecdsaSK) Type() string { return curveNames[sk.Curve] } // Sign hashes and signs the message usign ECDSA. Implements sdk.PrivKey interface -func (sk ecdsaSK) Sign(msg []byte) ([]byte, error) { +func (sk *ecdsaSK) Sign(msg []byte) ([]byte, error) { digest := sha256.Sum256(msg) return sk.PrivateKey.Sign(rand.Reader, digest[:], nil) } // **** proto.Message **** -func (ecdsaSK) Reset() {} -func (ecdsaSK) ProtoMessage() {} -func (sk ecdsaSK) String() string { +func (sk *ecdsaSK) Reset() { + sk.D = new(big.Int) + sk.PublicKey = ecdsa.PublicKey{} +} + +func (*ecdsaSK) ProtoMessage() {} +func (sk *ecdsaSK) String() string { return curveNames[sk.Curve] + "{-}" } + +// **** Proto Marshaler **** + +// Marshal implements ProtoMarshaler interface +func (sk *ecdsaSK) Marshal() ([]byte, error) { + bv := gogotypes.BytesValue{Value: sk.Bytes()} + return bv.Marshal() +} + +// MarshalTo implements ProtoMarshaler interface +func (sk *ecdsaSK) MarshalTo(data []byte) (int, error) { + bv := gogotypes.BytesValue{Value: sk.Bytes()} + return bv.MarshalTo(data) +} + +// MarshalToSizedBuffer implements ProtoMarshaler interface +func (sk *ecdsaSK) MarshalToSizedBuffer(dAtA []byte) (int, error) { + bv := gogotypes.BytesValue{Value: sk.Bytes()} + return bv.MarshalToSizedBuffer(dAtA) +} + +// Unmarshal implements ProtoMarshaler interface +func (sk *ecdsaSK) Unmarshal(b []byte) error { + bv := gogotypes.BytesValue{} + err := bv.Unmarshal(b) + if err != nil { + return err + } + bz := bv.Value + if len(bz) != PrivKeySize { + return fmt.Errorf("wrong ECDSA SK bytes, expecting %d bytes", PrivKeySize) + } + curve, ok := curveTypesRev[bz[0]] + if !ok { + return fmt.Errorf("wrong ECDSA PK bytes, unknown curve type: %d", bz[0]) + } + + if sk == nil { + sk = new(ecdsaSK) + } + sk.Curve = curve + sk.D = new(big.Int).SetBytes(bz[1:]) + sk.X, sk.Y = curve.ScalarBaseMult(bz[1:]) + return nil +} + +// Size implements ProtoMarshaler interface +func (sk *ecdsaSK) Size() int { + if sk == nil { + return 0 + } + return sovPrivKeySize +} diff --git a/crypto/keys/ecdsa/ecdsa_privkey_test.go b/crypto/keys/ecdsa/ecdsa_privkey_test.go index 9720e1796e2b..107621b54930 100644 --- a/crypto/keys/ecdsa/ecdsa_privkey_test.go +++ b/crypto/keys/ecdsa/ecdsa_privkey_test.go @@ -1,17 +1,51 @@ package ecdsa +import ( + "crypto/ecdsa" + "math/big" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" +) + +var _ cryptotypes.PrivKey = &ecdsaSK{} + func (suite *EcdsaSuite) TestSkString() { suite.Require().Equal("secp256r1{-}", suite.sk.String()) } -func (suite *EcdsaSuite) TestSkEqual() { +func (suite *EcdsaSuite) TestSkEquals() { require := suite.Require() skOther, err := GenSecp256r1() require.NoError(err) // require.False(suite.sk.Equals(skOther)) - skOther2 := ecdsaSK{skOther.(ecdsaSK).PrivateKey} + skOther2 := &ecdsaSK{skOther.(*ecdsaSK).PrivateKey} require.True(skOther.Equals(skOther2)) // require.True(skOther2.Equals(skOther), "Equals must be reflexive") } + +func (suite *EcdsaSuite) TestSkPubKey() { + pk := suite.sk.PubKey() + suite.True(suite.sk.(*ecdsaSK).PublicKey.Equal(&pk.(*ecdsaPK).PublicKey)) +} + +func (suite *EcdsaSuite) Bytes() { + bz := suite.sk.Bytes() + suite.Len(bz, PrivKeySize) + var sk *ecdsaSK + suite.Nil(sk.Bytes()) +} + +func (suite *EcdsaSuite) TestSkReset() { + var sk = &ecdsaSK{PrivateKey: ecdsa.PrivateKey{D: big.NewInt(1)}} + sk.Reset() + suite.Equal(0, sk.D.Cmp(big.NewInt(0))) + suite.Equal(ecdsa.PublicKey{}, sk.PublicKey) +} + +func (suite *EcdsaSuite) TestSkProtoMarshal() { +} + +func (suite *EcdsaSuite) TestSkEquals2() { +} diff --git a/crypto/keys/ecdsa/ecdsa_pubkey_test.go b/crypto/keys/ecdsa/ecdsa_pubkey_test.go index d7203b64f3f9..db458987b19c 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey_test.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey_test.go @@ -60,7 +60,7 @@ func (suite *EcdsaSuite) TestPKEquals() { skOther, err := GenSecp256r1() require.NoError(err) pkOther := skOther.PubKey() - pkOther2 := &ecdsaPK{skOther.(ecdsaSK).PublicKey, nil} + pkOther2 := &ecdsaPK{skOther.(*ecdsaSK).PublicKey, nil} require.False(suite.pk.Equals(pkOther)) require.True(pkOther.Equals(pkOther2)) From e122dce462a58029bfae9b5945f2bd3e5ecfaca1 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 24 Feb 2021 00:23:45 +0100 Subject: [PATCH 35/70] remove bytes.go --- types/bytes.go | 8 -- types/bytes.pb.go | 318 ---------------------------------------------- 2 files changed, 326 deletions(-) delete mode 100644 types/bytes.go delete mode 100644 types/bytes.pb.go diff --git a/types/bytes.go b/types/bytes.go deleted file mode 100644 index aefaaf21f7a3..000000000000 --- a/types/bytes.go +++ /dev/null @@ -1,8 +0,0 @@ -package types - -import "encoding/hex" - -// String encode bytes using hex encoder -func (m *PBBytes) String() string { - return hex.EncodeToString(m.Bytes) -} diff --git a/types/bytes.pb.go b/types/bytes.pb.go deleted file mode 100644 index 9d9926d86fff..000000000000 --- a/types/bytes.pb.go +++ /dev/null @@ -1,318 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: cosmos/base/bytes.proto - -package types - -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 - -// PBBytes defines a structure wrapping protocol buffers raw bytes serialization -type PBBytes struct { - Bytes []byte `protobuf:"bytes,1,opt,name=bytes,proto3" json:"bytes,omitempty"` -} - -func (m *PBBytes) Reset() { *m = PBBytes{} } -func (*PBBytes) ProtoMessage() {} -func (*PBBytes) Descriptor() ([]byte, []int) { - return fileDescriptor_b510f2b6b79ff3d8, []int{0} -} -func (m *PBBytes) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *PBBytes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_PBBytes.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 *PBBytes) XXX_Merge(src proto.Message) { - xxx_messageInfo_PBBytes.Merge(m, src) -} -func (m *PBBytes) XXX_Size() int { - return m.Size() -} -func (m *PBBytes) XXX_DiscardUnknown() { - xxx_messageInfo_PBBytes.DiscardUnknown(m) -} - -var xxx_messageInfo_PBBytes proto.InternalMessageInfo - -func (m *PBBytes) GetBytes() []byte { - if m != nil { - return m.Bytes - } - return nil -} - -func init() { - proto.RegisterType((*PBBytes)(nil), "cosmos.crypto.secp256r1.PBBytes") -} - -func init() { proto.RegisterFile("cosmos/base/bytes.proto", fileDescriptor_b510f2b6b79ff3d8) } - -var fileDescriptor_b510f2b6b79ff3d8 = []byte{ - // 173 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4f, 0xce, 0x2f, 0xce, - 0xcd, 0x2f, 0xd6, 0x4f, 0x4a, 0x2c, 0x4e, 0xd5, 0x4f, 0xaa, 0x2c, 0x49, 0x2d, 0xd6, 0x2b, 0x28, - 0xca, 0x2f, 0xc9, 0x17, 0x82, 0x4a, 0xe8, 0x25, 0x17, 0x55, 0x16, 0x94, 0xe4, 0xeb, 0x15, 0xa7, - 0x26, 0x17, 0x18, 0x99, 0x9a, 0x15, 0x19, 0x4a, 0x89, 0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0xd5, 0xe8, - 0x83, 0x58, 0x10, 0xe5, 0x4a, 0xf2, 0x5c, 0xec, 0x01, 0x4e, 0x4e, 0x20, 0xfd, 0x42, 0x22, 0x5c, - 0xac, 0x60, 0x83, 0x24, 0x18, 0x15, 0x18, 0x35, 0x78, 0x82, 0x20, 0x1c, 0x27, 0x97, 0x1b, 0x0f, - 0xe5, 0x18, 0x1a, 0x1e, 0xc9, 0x31, 0x9c, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, - 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, - 0x94, 0x52, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x3e, 0xd4, 0x55, 0x10, - 0x4a, 0xb7, 0x38, 0x25, 0x5b, 0xbf, 0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, 0x0d, 0x6c, 0x9b, 0x31, - 0x20, 0x00, 0x00, 0xff, 0xff, 0xf1, 0x44, 0x60, 0x8d, 0xb7, 0x00, 0x00, 0x00, -} - -func (m *PBBytes) 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 *PBBytes) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *PBBytes) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Bytes) > 0 { - i -= len(m.Bytes) - copy(dAtA[i:], m.Bytes) - i = encodeVarintBytes(dAtA, i, uint64(len(m.Bytes))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func encodeVarintBytes(dAtA []byte, offset int, v uint64) int { - offset -= sovBytes(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *PBBytes) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Bytes) - if l > 0 { - n += 1 + l + sovBytes(uint64(l)) - } - return n -} - -func sovBytes(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozBytes(x uint64) (n int) { - return sovBytes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *PBBytes) 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 ErrIntOverflowBytes - } - 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: PBBytes: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: PBBytes: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Bytes", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowBytes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthBytes - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthBytes - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Bytes = append(m.Bytes[:0], dAtA[iNdEx:postIndex]...) - if m.Bytes == nil { - m.Bytes = []byte{} - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipBytes(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthBytes - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipBytes(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, ErrIntOverflowBytes - } - 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, ErrIntOverflowBytes - } - 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, ErrIntOverflowBytes - } - 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, ErrInvalidLengthBytes - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupBytes - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthBytes - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthBytes = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowBytes = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupBytes = fmt.Errorf("proto: unexpected end of group") -) From c91e4297b23a2f50723d918f55a375453128a9de Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 24 Feb 2021 12:33:55 +0100 Subject: [PATCH 36/70] add private key marshaling tests --- crypto/keys/ecdsa/ecdsa_privkey_test.go | 40 +++++++++++++++++++++++-- crypto/keys/ecdsa/ecdsa_pubkey_test.go | 14 ++++----- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/crypto/keys/ecdsa/ecdsa_privkey_test.go b/crypto/keys/ecdsa/ecdsa_privkey_test.go index 107621b54930..c414a6702161 100644 --- a/crypto/keys/ecdsa/ecdsa_privkey_test.go +++ b/crypto/keys/ecdsa/ecdsa_privkey_test.go @@ -4,7 +4,10 @@ import ( "crypto/ecdsa" "math/big" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + proto "github.com/gogo/protobuf/proto" ) var _ cryptotypes.PrivKey = &ecdsaSK{} @@ -44,8 +47,41 @@ func (suite *EcdsaSuite) TestSkReset() { suite.Equal(ecdsa.PublicKey{}, sk.PublicKey) } -func (suite *EcdsaSuite) TestSkProtoMarshal() { +func (suite *EcdsaSuite) TestSkMarshalProto() { + require := suite.Require() + + /**** test structure marshalling ****/ + + var sk ecdsaSK + bz, err := proto.Marshal(suite.sk) + require.NoError(err) + require.NoError(proto.Unmarshal(bz, &sk)) + require.True(sk.Equals(suite.sk)) + + /**** test structure marshalling with codec ****/ + + sk = ecdsaSK{} + registry := types.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(registry) + bz, err = cdc.MarshalBinaryBare(suite.sk.(*ecdsaSK)) + require.NoError(err) + require.NoError(cdc.UnmarshalBinaryBare(bz, &sk)) + require.True(sk.Equals(suite.sk)) + + const bufSize = 100 + bz2 := make([]byte, bufSize) + skCpy := suite.sk.(*ecdsaSK) + _, err = skCpy.MarshalTo(bz2) + require.NoError(err) + require.Len(bz2, bufSize) + require.Equal(bz, bz2[:sovPrivKeySize]) + + bz2 = make([]byte, bufSize) + _, err = skCpy.MarshalToSizedBuffer(bz2) + require.NoError(err) + require.Len(bz2, bufSize) + require.Equal(bz, bz2[(bufSize-sovPrivKeySize):]) } -func (suite *EcdsaSuite) TestSkEquals2() { +func (suite *EcdsaSuite) TestSign() { } diff --git a/crypto/keys/ecdsa/ecdsa_pubkey_test.go b/crypto/keys/ecdsa/ecdsa_pubkey_test.go index db458987b19c..612bdad3b0d3 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey_test.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey_test.go @@ -54,6 +54,13 @@ func (suite *EcdsaSuite) TestPKBytes() { require.Len(suite.pk.Bytes(), PubKeySize) } +func (suite *EcdsaSuite) TestPKReset() { + pk := &ecdsaPK{ecdsa.PublicKey{X: big.NewInt(1)}, []byte{1}} + pk.Reset() + suite.Nil(pk.address) + suite.Equal(pk.PublicKey, ecdsa.PublicKey{}) +} + func (suite *EcdsaSuite) TestPKEquals() { require := suite.Require() @@ -143,10 +150,3 @@ func (suite *EcdsaSuite) TestPKMarshalProto() { cdc.UnmarshalInterface(bz, nil) require.Error(err, "nil should fail") } - -func (suite *EcdsaSuite) TestPKReset() { - pk := &ecdsaPK{ecdsa.PublicKey{X: big.NewInt(1)}, []byte{1}} - pk.Reset() - suite.Nil(pk.address) - suite.Equal(pk.PublicKey, ecdsa.PublicKey{}) -} From fcdbb1a5612946b0c1d0803d05cdd04fb2708067 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 25 Feb 2021 00:09:22 +0100 Subject: [PATCH 37/70] break tests into 2 suites --- crypto/keys/ecdsa/ecdsa_privkey_test.go | 22 ++++++++++++------- crypto/keys/ecdsa/ecdsa_pubkey_test.go | 28 +++++++++++++------------ 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/crypto/keys/ecdsa/ecdsa_privkey_test.go b/crypto/keys/ecdsa/ecdsa_privkey_test.go index c414a6702161..ae006bd19a19 100644 --- a/crypto/keys/ecdsa/ecdsa_privkey_test.go +++ b/crypto/keys/ecdsa/ecdsa_privkey_test.go @@ -3,20 +3,28 @@ package ecdsa import ( "crypto/ecdsa" "math/big" + "testing" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/types" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" proto "github.com/gogo/protobuf/proto" + "github.com/stretchr/testify/suite" ) var _ cryptotypes.PrivKey = &ecdsaSK{} -func (suite *EcdsaSuite) TestSkString() { +func TestSKSuite(t *testing.T) { + suite.Run(t, new(SKSuite)) +} + +type SKSuite struct{ CommonSuite } + +func (suite *SKSuite) TestString() { suite.Require().Equal("secp256r1{-}", suite.sk.String()) } -func (suite *EcdsaSuite) TestSkEquals() { +func (suite *SKSuite) TestEquals() { require := suite.Require() skOther, err := GenSecp256r1() @@ -28,26 +36,26 @@ func (suite *EcdsaSuite) TestSkEquals() { // require.True(skOther2.Equals(skOther), "Equals must be reflexive") } -func (suite *EcdsaSuite) TestSkPubKey() { +func (suite *SKSuite) TestPubKey() { pk := suite.sk.PubKey() suite.True(suite.sk.(*ecdsaSK).PublicKey.Equal(&pk.(*ecdsaPK).PublicKey)) } -func (suite *EcdsaSuite) Bytes() { +func (suite *SKSuite) Bytes() { bz := suite.sk.Bytes() suite.Len(bz, PrivKeySize) var sk *ecdsaSK suite.Nil(sk.Bytes()) } -func (suite *EcdsaSuite) TestSkReset() { +func (suite *SKSuite) TestReset() { var sk = &ecdsaSK{PrivateKey: ecdsa.PrivateKey{D: big.NewInt(1)}} sk.Reset() suite.Equal(0, sk.D.Cmp(big.NewInt(0))) suite.Equal(ecdsa.PublicKey{}, sk.PublicKey) } -func (suite *EcdsaSuite) TestSkMarshalProto() { +func (suite *SKSuite) TestMarshalProto() { require := suite.Require() /**** test structure marshalling ****/ @@ -83,5 +91,5 @@ func (suite *EcdsaSuite) TestSkMarshalProto() { require.Equal(bz, bz2[(bufSize-sovPrivKeySize):]) } -func (suite *EcdsaSuite) TestSign() { +func (suite *SKSuite) TestSign() { } diff --git a/crypto/keys/ecdsa/ecdsa_pubkey_test.go b/crypto/keys/ecdsa/ecdsa_pubkey_test.go index 612bdad3b0d3..0e3474d1a45d 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey_test.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey_test.go @@ -15,24 +15,26 @@ import ( cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" ) -type EcdsaSuite struct { +func TestPKSuite(t *testing.T) { + suite.Run(t, new(PKSuite)) +} + +type CommonSuite struct { suite.Suite pk cryptotypes.PubKey sk cryptotypes.PrivKey } -func TestEcdsaSuite(t *testing.T) { - suite.Run(t, new(EcdsaSuite)) -} - -func (suite *EcdsaSuite) SetupSuite() { +func (suite *CommonSuite) SetupSuite() { sk, err := GenSecp256r1() suite.Require().NoError(err) suite.sk = sk suite.pk = sk.PubKey() } -func (suite *EcdsaSuite) TestPKString() { +type PKSuite struct{ CommonSuite } + +func (suite *PKSuite) TestString() { assert := suite.Assert() require := suite.Require() @@ -47,21 +49,21 @@ func (suite *EcdsaSuite) TestPKString() { assert.EqualValues(suite.pk.Bytes(), bz) } -func (suite *EcdsaSuite) TestPKBytes() { +func (suite *PKSuite) TestBytes() { require := suite.Require() var pk *ecdsaPK require.Nil(pk.Bytes()) require.Len(suite.pk.Bytes(), PubKeySize) } -func (suite *EcdsaSuite) TestPKReset() { +func (suite *PKSuite) TestReset() { pk := &ecdsaPK{ecdsa.PublicKey{X: big.NewInt(1)}, []byte{1}} pk.Reset() suite.Nil(pk.address) suite.Equal(pk.PublicKey, ecdsa.PublicKey{}) } -func (suite *EcdsaSuite) TestPKEquals() { +func (suite *PKSuite) TestEquals() { require := suite.Require() skOther, err := GenSecp256r1() @@ -75,7 +77,7 @@ func (suite *EcdsaSuite) TestPKEquals() { require.True(pkOther.Equals(pkOther), "Equals must be reflexive") } -func (suite *EcdsaSuite) TestPKMarshalAmino() { +func (suite *PKSuite) TestMarshalAmino() { require := suite.Require() type AminoPubKey interface { cryptotypes.PubKey @@ -91,7 +93,7 @@ func (suite *EcdsaSuite) TestPKMarshalAmino() { require.True(pk2.Equals(suite.pk)) } -func (suite *EcdsaSuite) TestPKSize() { +func (suite *PKSuite) TestSize() { require := suite.Require() bv := gogotypes.BytesValue{Value: suite.pk.Bytes()} require.Equal(bv.Size(), suite.pk.(*ecdsaPK).Size()) @@ -100,7 +102,7 @@ func (suite *EcdsaSuite) TestPKSize() { require.Equal(0, nilPk.Size(), "nil value must have zero size") } -func (suite *EcdsaSuite) TestPKMarshalProto() { +func (suite *PKSuite) TestMarshalProto() { require := suite.Require() /**** test structure marshalling ****/ From 0593e419730705b60cb64e3028499450b2c3c3c7 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 25 Feb 2021 00:20:06 +0100 Subject: [PATCH 38/70] add signature tests --- crypto/keys/ecdsa/ecdsa_privkey_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/crypto/keys/ecdsa/ecdsa_privkey_test.go b/crypto/keys/ecdsa/ecdsa_privkey_test.go index ae006bd19a19..1bd29900265f 100644 --- a/crypto/keys/ecdsa/ecdsa_privkey_test.go +++ b/crypto/keys/ecdsa/ecdsa_privkey_test.go @@ -5,6 +5,8 @@ import ( "math/big" "testing" + "github.com/tendermint/tendermint/crypto" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/types" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -92,4 +94,22 @@ func (suite *SKSuite) TestMarshalProto() { } func (suite *SKSuite) TestSign() { + require := suite.Require() + + msg := crypto.CRandBytes(1000) + sig, err := suite.sk.Sign(msg) + require.NoError(err) + sigCpy := make([]byte, len(sig)) + copy(sigCpy, sig) + require.True(suite.pk.VerifySignature(msg, sigCpy)) + + // Mutate the signature + for i := range sig { + sigCpy[i] ^= byte(i + 1) + require.False(suite.pk.VerifySignature(msg, sigCpy)) + } + + // Mutate the message + msg[1] ^= byte(2) + require.False(suite.pk.VerifySignature(msg, sig)) } From 567f41a2c9bf48046a53090bd075b170cd944159 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 25 Feb 2021 00:24:44 +0100 Subject: [PATCH 39/70] remove TODO --- crypto/keys/ed25519/ed25519.go | 1 - 1 file changed, 1 deletion(-) diff --git a/crypto/keys/ed25519/ed25519.go b/crypto/keys/ed25519/ed25519.go index cfeb523b043e..7c70d573ec30 100644 --- a/crypto/keys/ed25519/ed25519.go +++ b/crypto/keys/ed25519/ed25519.go @@ -162,7 +162,6 @@ func (pubKey *PubKey) Address() crypto.Address { // For ADR-28 compatible address we would need to // return address.Hash(proto.MessageName(pubKey), pubKey.Key) return crypto.Address(tmhash.SumTruncated(pubKey.Key)) - // TODO use ADR-28: return address.Hash(proto.MessageName(pubKey), pubKey.Key) } // Bytes returns the PubKey byte format. From 8f2108b3fe8eab614d9803ea6fcba3acc74a9179 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 25 Feb 2021 01:36:21 +0100 Subject: [PATCH 40/70] remove bytes.proto --- proto/cosmos/base/bytes.proto | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 proto/cosmos/base/bytes.proto diff --git a/proto/cosmos/base/bytes.proto b/proto/cosmos/base/bytes.proto deleted file mode 100644 index 0e4f8f45e531..000000000000 --- a/proto/cosmos/base/bytes.proto +++ /dev/null @@ -1,24 +0,0 @@ -syntax = "proto3"; -package cosmos.crypto.secp256r1; - -import "gogoproto/gogo.proto"; - -option go_package = "github.com/cosmos/cosmos-sdk/types"; -option (gogoproto.goproto_stringer_all) = false; -option (gogoproto.stringer_all) = false; - -// PBBytes defines a structure wrapping protocol buffers raw bytes serialization -message PBBytes { - bytes bytes = 1; -} - - -// // PubKey defines a P-256 s(ecp256r1) public key -// message PubKey { -// bytes key = 1; -// } - -// // PrivKey defines a P-256 (secp256r1) private key -// message PrivKey { -// bytes key = 1; -// } From 6dc666f056bf1e5b221e5117a81265e244ff6635 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 25 Feb 2021 01:44:35 +0100 Subject: [PATCH 41/70] adding changelog --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 444e0bf9450f..cfb4a58543dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +## New Features + +* [\#8559](https://github.com/cosmos/cosmos-sdk/pull/8559) Adding Protobuf compatible secp256r1 ECDSA signatures. + ### Client Breaking Changes * [\#8363](https://github.com/cosmos/cosmos-sdk/pull/8363) Addresses no longer have a fixed 20-byte length. From the SDK modules' point of view, any 1-255 bytes-long byte array is a valid address. @@ -105,7 +109,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### State Machine Breaking * (x/ibc) [\#8266](https://github.com/cosmos/cosmos-sdk/issues/8266) Add amino JSON support for IBC MsgTransfer in order to support Ledger text signing transfer transactions. -* (x/ibc) [\#8404](https://github.com/cosmos/cosmos-sdk/pull/8404) Reorder IBC `ChanOpenAck` and `ChanOpenConfirm` handler execution to perform core handler first, followed by application callbacks. +* (x/ibc) [\#8404](https://github.com/cosmos/cosmos-sdk/pull/8404) Reorder IBC `ChanOpenAck` and `ChanOpenConfirm` handler execution to perform core handler first, followed by application callbacks. ### Bug Fixes From 97677a43e34352dadf127559362d832f84ce1b28 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Thu, 25 Feb 2021 10:50:04 +0000 Subject: [PATCH 42/70] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfb4a58543dd..a6c934238d7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] -## New Features +## Features * [\#8559](https://github.com/cosmos/cosmos-sdk/pull/8559) Adding Protobuf compatible secp256r1 ECDSA signatures. From c49e66f1d826c7849d5b87a3ad6672d4a843b9a8 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Thu, 25 Feb 2021 10:54:22 +0000 Subject: [PATCH 43/70] Update crypto/keys/ecdsa/ecdsa_privkey.go --- crypto/keys/ecdsa/ecdsa_privkey.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/keys/ecdsa/ecdsa_privkey.go b/crypto/keys/ecdsa/ecdsa_privkey.go index ec881bc16142..09c1f946eee1 100644 --- a/crypto/keys/ecdsa/ecdsa_privkey.go +++ b/crypto/keys/ecdsa/ecdsa_privkey.go @@ -18,7 +18,7 @@ type ecdsaSK struct { ecdsa.PrivateKey } -// GenSecp256r1 generates a new secp256r1 private key. It uses OS randomness. +// GenSecp256r1 generates a new secp256r1 private key. It uses operating system randomness. func GenSecp256r1() (cryptotypes.PrivKey, error) { key, err := ecdsa.GenerateKey(secp256r1, rand.Reader) return &ecdsaSK{*key}, err From 45784bf902986dd8a85836b328f1c70d5044402c Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Thu, 25 Feb 2021 10:57:52 +0000 Subject: [PATCH 44/70] Update crypto/keys/ecdsa/ecdsa_pubkey.go --- crypto/keys/ecdsa/ecdsa_pubkey.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/keys/ecdsa/ecdsa_pubkey.go b/crypto/keys/ecdsa/ecdsa_pubkey.go index e6adffc5c40c..265216614987 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey.go @@ -118,7 +118,7 @@ func (pk *ecdsaPK) Unmarshal(b []byte) error { return pk.UnmarshalAmino(bv.Value) } -// Size implements ProtoMarshaler interface +// Size implements ProtoMarshaler interface. func (pk *ecdsaPK) Size() int { if pk == nil { return 0 From bd99f516591e976339583a6dd43508f6ecc8f4dd Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 25 Feb 2021 12:20:16 +0100 Subject: [PATCH 45/70] comments: add dot (.) at the end --- crypto/keys/ecdsa/ecdsa_privkey.go | 22 +++++++++++++--------- crypto/keys/ecdsa/ecdsa_pubkey.go | 29 ++++++++++++++++------------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/crypto/keys/ecdsa/ecdsa_privkey.go b/crypto/keys/ecdsa/ecdsa_privkey.go index 09c1f946eee1..49ca4c65500d 100644 --- a/crypto/keys/ecdsa/ecdsa_privkey.go +++ b/crypto/keys/ecdsa/ecdsa_privkey.go @@ -24,12 +24,12 @@ func GenSecp256r1() (cryptotypes.PrivKey, error) { return &ecdsaSK{*key}, err } -// PubKey implements SDK PrivKey interface +// PubKey implements SDK PrivKey interface. func (sk *ecdsaSK) PubKey() cryptotypes.PubKey { return &ecdsaPK{sk.PublicKey, nil} } -// Bytes serialize the private key with first byte being the curve type +// Bytes serialize the private key with first byte being the curve type. func (sk *ecdsaSK) Bytes() []byte { if sk == nil { return nil @@ -52,12 +52,12 @@ func (sk *ecdsaSK) Equals(other cryptotypes.LedgerPrivKey) bool { return sk.PrivateKey.Equal(&sk2.PrivateKey) } -// Type returns key type name. Implements sdk.PrivKey interface +// Type returns key type name. Implements sdk.PrivKey interface. func (sk *ecdsaSK) Type() string { return curveNames[sk.Curve] } -// Sign hashes and signs the message usign ECDSA. Implements sdk.PrivKey interface +// Sign hashes and signs the message usign ECDSA. Implements sdk.PrivKey interface. func (sk *ecdsaSK) Sign(msg []byte) ([]byte, error) { digest := sha256.Sum256(msg) return sk.PrivateKey.Sign(rand.Reader, digest[:], nil) @@ -65,37 +65,41 @@ func (sk *ecdsaSK) Sign(msg []byte) ([]byte, error) { // **** proto.Message **** +// Reset implements proto.Message interface. func (sk *ecdsaSK) Reset() { sk.D = new(big.Int) sk.PublicKey = ecdsa.PublicKey{} } +// ProtoMessage implements proto.Message interface. func (*ecdsaSK) ProtoMessage() {} + +// String implements proto.Message interface. func (sk *ecdsaSK) String() string { return curveNames[sk.Curve] + "{-}" } // **** Proto Marshaler **** -// Marshal implements ProtoMarshaler interface +// Marshal implements ProtoMarshaler interface. func (sk *ecdsaSK) Marshal() ([]byte, error) { bv := gogotypes.BytesValue{Value: sk.Bytes()} return bv.Marshal() } -// MarshalTo implements ProtoMarshaler interface +// MarshalTo implements ProtoMarshaler interface. func (sk *ecdsaSK) MarshalTo(data []byte) (int, error) { bv := gogotypes.BytesValue{Value: sk.Bytes()} return bv.MarshalTo(data) } -// MarshalToSizedBuffer implements ProtoMarshaler interface +// MarshalToSizedBuffer implements ProtoMarshaler interface. func (sk *ecdsaSK) MarshalToSizedBuffer(dAtA []byte) (int, error) { bv := gogotypes.BytesValue{Value: sk.Bytes()} return bv.MarshalToSizedBuffer(dAtA) } -// Unmarshal implements ProtoMarshaler interface +// Unmarshal implements ProtoMarshaler interface. func (sk *ecdsaSK) Unmarshal(b []byte) error { bv := gogotypes.BytesValue{} err := bv.Unmarshal(b) @@ -120,7 +124,7 @@ func (sk *ecdsaSK) Unmarshal(b []byte) error { return nil } -// Size implements ProtoMarshaler interface +// Size implements ProtoMarshaler interface. func (sk *ecdsaSK) Size() int { if sk == nil { return 0 diff --git a/crypto/keys/ecdsa/ecdsa_pubkey.go b/crypto/keys/ecdsa/ecdsa_pubkey.go index 265216614987..0b113ec24929 100644 --- a/crypto/keys/ecdsa/ecdsa_pubkey.go +++ b/crypto/keys/ecdsa/ecdsa_pubkey.go @@ -16,7 +16,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/errors" ) -// signature holds the r and s values of an ECDSA signature +// signature holds the r and s values of an ECDSA signature. type signature struct { R, S *big.Int } @@ -28,7 +28,7 @@ type ecdsaPK struct { address tmcrypto.Address } -// String implements PubKey interface +// String implements PubKey interface. func (pk *ecdsaPK) Address() tmcrypto.Address { if pk.address == nil { pk.address = address.Hash(curveNames[pk.Curve], pk.Bytes()) @@ -36,11 +36,6 @@ func (pk *ecdsaPK) Address() tmcrypto.Address { return pk.address } -// String implements PubKey interface -func (pk *ecdsaPK) String() string { - return fmt.Sprintf("%s{%X}", curveNames[pk.Curve], pk.Bytes()) -} - // Bytes returns the byte representation of the public key using a compressed form // specified in section 4.3.6 of ANSI X9.62 with first byte being the curve type. func (pk *ecdsaPK) Bytes() []byte { @@ -65,7 +60,7 @@ func (pk *ecdsaPK) Equals(other cryptotypes.PubKey) bool { return pk.PublicKey.Equal(&pk2.PublicKey) } -// VerifySignature implements skd.PubKey interface +// VerifySignature implements skd.PubKey interface. func (pk *ecdsaPK) VerifySignature(msg []byte, sig []byte) bool { s := new(signature) if _, err := asn1.Unmarshal(sig, s); err != nil || s == nil { @@ -76,39 +71,47 @@ func (pk *ecdsaPK) VerifySignature(msg []byte, sig []byte) bool { return ecdsa.Verify(&pk.PublicKey, h[:], s.R, s.S) } -// Type returns key type name. Implements sdk.PubKey interface +// Type returns key type name. Implements sdk.PubKey interface. func (pk *ecdsaPK) Type() string { return curveNames[pk.Curve] } // **** proto.Message **** +// Reset implements proto.Message interface. func (pk *ecdsaPK) Reset() { *pk = ecdsaPK{} } + +// ProtoMessage implements proto.Message interface. func (*ecdsaPK) ProtoMessage() {} +// String implements proto.Message interface +func (pk *ecdsaPK) String() string { + return fmt.Sprintf("%s{%X}", curveNames[pk.Curve], pk.Bytes()) +} + // **** Proto Marshaler **** -// Marshal implements ProtoMarshaler interface +// Marshal implements ProtoMarshaler interface. func (pk *ecdsaPK) Marshal() ([]byte, error) { bv := gogotypes.BytesValue{Value: pk.Bytes()} return bv.Marshal() } -// MarshalTo implements ProtoMarshaler interface +// MarshalTo implements ProtoMarshaler interface. func (pk *ecdsaPK) MarshalTo(data []byte) (int, error) { bv := gogotypes.BytesValue{Value: pk.Bytes()} return bv.MarshalTo(data) } -// MarshalToSizedBuffer implements ProtoMarshaler interface +// MarshalToSizedBuffer implements ProtoMarshaler interface. func (pk *ecdsaPK) MarshalToSizedBuffer(dAtA []byte) (int, error) { bv := gogotypes.BytesValue{Value: pk.Bytes()} return bv.MarshalToSizedBuffer(dAtA) } -// Unmarshal implements ProtoMarshaler interface +// Unmarshal implements ProtoMarshaler interface. func (pk *ecdsaPK) Unmarshal(b []byte) error { bv := gogotypes.BytesValue{} err := bv.Unmarshal(b) From 641b17029061f34b76931ae3d21fd5b408736e09 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 25 Feb 2021 13:08:47 +0100 Subject: [PATCH 46/70] update comments --- crypto/keys/ecdsa/ecdsa_privkey.go | 2 +- crypto/keys/ecdsa/init.go | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/crypto/keys/ecdsa/ecdsa_privkey.go b/crypto/keys/ecdsa/ecdsa_privkey.go index 49ca4c65500d..50f86827a7e5 100644 --- a/crypto/keys/ecdsa/ecdsa_privkey.go +++ b/crypto/keys/ecdsa/ecdsa_privkey.go @@ -24,7 +24,7 @@ func GenSecp256r1() (cryptotypes.PrivKey, error) { return &ecdsaSK{*key}, err } -// PubKey implements SDK PrivKey interface. +// PubKey implements Cosmos-SDK PrivKey interface. func (sk *ecdsaSK) PubKey() cryptotypes.PubKey { return &ecdsaPK{sk.PublicKey, nil} } diff --git a/crypto/keys/ecdsa/init.go b/crypto/keys/ecdsa/init.go index 425a71577e36..b691eb460039 100644 --- a/crypto/keys/ecdsa/init.go +++ b/crypto/keys/ecdsa/init.go @@ -1,3 +1,7 @@ +// ECDSA package implements Cosmos-SDK compatible ECDSA public and private key. The keys +// can be protobuf serialized and packed in Any. +// Currently supported keys are: +// + secp256r1 package ecdsa import ( From ba95b2f520042d7c95bc775952caacce62456501 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 25 Feb 2021 14:33:16 +0100 Subject: [PATCH 47/70] update commented code --- crypto/keys/ecdsa/ecdsa_privkey.go | 5 ----- crypto/keys/ecdsa/ecdsa_privkey_test.go | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/crypto/keys/ecdsa/ecdsa_privkey.go b/crypto/keys/ecdsa/ecdsa_privkey.go index 50f86827a7e5..f0c27a95ad58 100644 --- a/crypto/keys/ecdsa/ecdsa_privkey.go +++ b/crypto/keys/ecdsa/ecdsa_privkey.go @@ -11,9 +11,6 @@ import ( gogotypes "github.com/gogo/protobuf/types" ) -// "github.com/cosmos/cosmos-sdk/codec" -// "github.com/cosmos/cosmos-sdk/types/errors" - type ecdsaSK struct { ecdsa.PrivateKey } @@ -47,8 +44,6 @@ func (sk *ecdsaSK) Equals(other cryptotypes.LedgerPrivKey) bool { if !ok { return false } - // return EcEqual(&sk.PrivateKey, &sk2.PrivateKey) - return sk.PrivateKey.Equal(&sk2.PrivateKey) } diff --git a/crypto/keys/ecdsa/ecdsa_privkey_test.go b/crypto/keys/ecdsa/ecdsa_privkey_test.go index 1bd29900265f..11e312650d02 100644 --- a/crypto/keys/ecdsa/ecdsa_privkey_test.go +++ b/crypto/keys/ecdsa/ecdsa_privkey_test.go @@ -31,11 +31,11 @@ func (suite *SKSuite) TestEquals() { skOther, err := GenSecp256r1() require.NoError(err) - // require.False(suite.sk.Equals(skOther)) + require.False(suite.sk.Equals(skOther)) skOther2 := &ecdsaSK{skOther.(*ecdsaSK).PrivateKey} require.True(skOther.Equals(skOther2)) - // require.True(skOther2.Equals(skOther), "Equals must be reflexive") + require.True(skOther2.Equals(skOther), "Equals must be reflexive") } func (suite *SKSuite) TestPubKey() { From 2fee3151b8c616da499c7f36d9fc3221524ff818 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 25 Feb 2021 14:37:10 +0100 Subject: [PATCH 48/70] rename files --- crypto/keys/ecdsa/{ecdsa_privkey.go => privkey.go} | 0 .../ecdsa/{ecdsa_privkey_test.go => privkey_internal_test.go} | 0 crypto/keys/ecdsa/{ecdsa_pubkey.go => pubkey.go} | 0 .../keys/ecdsa/{ecdsa_pubkey_test.go => pubkey_internal_test.go} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename crypto/keys/ecdsa/{ecdsa_privkey.go => privkey.go} (100%) rename crypto/keys/ecdsa/{ecdsa_privkey_test.go => privkey_internal_test.go} (100%) rename crypto/keys/ecdsa/{ecdsa_pubkey.go => pubkey.go} (100%) rename crypto/keys/ecdsa/{ecdsa_pubkey_test.go => pubkey_internal_test.go} (100%) diff --git a/crypto/keys/ecdsa/ecdsa_privkey.go b/crypto/keys/ecdsa/privkey.go similarity index 100% rename from crypto/keys/ecdsa/ecdsa_privkey.go rename to crypto/keys/ecdsa/privkey.go diff --git a/crypto/keys/ecdsa/ecdsa_privkey_test.go b/crypto/keys/ecdsa/privkey_internal_test.go similarity index 100% rename from crypto/keys/ecdsa/ecdsa_privkey_test.go rename to crypto/keys/ecdsa/privkey_internal_test.go diff --git a/crypto/keys/ecdsa/ecdsa_pubkey.go b/crypto/keys/ecdsa/pubkey.go similarity index 100% rename from crypto/keys/ecdsa/ecdsa_pubkey.go rename to crypto/keys/ecdsa/pubkey.go diff --git a/crypto/keys/ecdsa/ecdsa_pubkey_test.go b/crypto/keys/ecdsa/pubkey_internal_test.go similarity index 100% rename from crypto/keys/ecdsa/ecdsa_pubkey_test.go rename to crypto/keys/ecdsa/pubkey_internal_test.go From 4f2a5cc92c7b3c93c56a438b9780a9150546841c Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 25 Feb 2021 15:06:23 +0100 Subject: [PATCH 49/70] remove Amino methods --- crypto/keys/ecdsa/pubkey.go | 34 +++++------------------ crypto/keys/ecdsa/pubkey_internal_test.go | 16 ----------- 2 files changed, 7 insertions(+), 43 deletions(-) diff --git a/crypto/keys/ecdsa/pubkey.go b/crypto/keys/ecdsa/pubkey.go index 0b113ec24929..66b52b42490d 100644 --- a/crypto/keys/ecdsa/pubkey.go +++ b/crypto/keys/ecdsa/pubkey.go @@ -118,26 +118,8 @@ func (pk *ecdsaPK) Unmarshal(b []byte) error { if err != nil { return err } - return pk.UnmarshalAmino(bv.Value) -} - -// Size implements ProtoMarshaler interface. -func (pk *ecdsaPK) Size() int { - if pk == nil { - return 0 - } - return sovPubKeySize -} - -// **** Amino Marshaler **** -// MarshalAmino overrides Amino binary marshalling. -func (pk *ecdsaPK) MarshalAmino() ([]byte, error) { - return pk.Bytes(), nil -} - -// UnmarshalAmino overrides Amino binary marshalling. -func (pk *ecdsaPK) UnmarshalAmino(bz []byte) error { + bz := bv.Value if len(bz) != PubKeySize { return errors.Wrapf(errors.ErrInvalidPubKey, "wrong ECDSA PK bytes, expecting %d bytes", PubKeySize) } @@ -158,12 +140,10 @@ func (pk *ecdsaPK) UnmarshalAmino(bz []byte) error { return nil } -// MarshalAminoJSON overrides Amino JSON marshalling. -func (pk *ecdsaPK) MarshalAminoJSON() ([]byte, error) { - return pk.MarshalAmino() -} - -// UnmarshalAminoJSON overrides Amino JSON marshalling. -func (pk *ecdsaPK) UnmarshalAminoJSON(bz []byte) error { - return pk.UnmarshalAmino(bz) +// Size implements ProtoMarshaler interface. +func (pk *ecdsaPK) Size() int { + if pk == nil { + return 0 + } + return sovPubKeySize } diff --git a/crypto/keys/ecdsa/pubkey_internal_test.go b/crypto/keys/ecdsa/pubkey_internal_test.go index 0e3474d1a45d..b12c229b89b6 100644 --- a/crypto/keys/ecdsa/pubkey_internal_test.go +++ b/crypto/keys/ecdsa/pubkey_internal_test.go @@ -77,22 +77,6 @@ func (suite *PKSuite) TestEquals() { require.True(pkOther.Equals(pkOther), "Equals must be reflexive") } -func (suite *PKSuite) TestMarshalAmino() { - require := suite.Require() - type AminoPubKey interface { - cryptotypes.PubKey - MarshalAmino() ([]byte, error) - } - - pk := suite.pk.(AminoPubKey) - bz, err := pk.MarshalAmino() - require.NoError(err) - - var pk2 = new(ecdsaPK) - require.NoError(pk2.UnmarshalAmino(bz)) - require.True(pk2.Equals(suite.pk)) -} - func (suite *PKSuite) TestSize() { require := suite.Require() bv := gogotypes.BytesValue{Value: suite.pk.Bytes()} From 314dbf259a5676a532f95f2858d490b8c0bf24ed Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 25 Feb 2021 16:04:23 +0100 Subject: [PATCH 50/70] use 2 spaces in protocgen.sh --- scripts/protocgen.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh index cd5d314699cc..fc34f9bf66f9 100755 --- a/scripts/protocgen.sh +++ b/scripts/protocgen.sh @@ -27,11 +27,11 @@ done # command to generate docs using protoc-gen-doc buf protoc \ - -I "proto" \ - -I "third_party/proto" \ - --doc_out=./docs/core \ - --doc_opt=./docs/protodoc-markdown.tmpl,proto-docs.md \ - $(find "$(pwd)/proto" -maxdepth 5 -name '*.proto') + -I "proto" \ + -I "third_party/proto" \ + --doc_out=./docs/core \ + --doc_opt=./docs/protodoc-markdown.tmpl,proto-docs.md \ + $(find "$(pwd)/proto" -maxdepth 5 -name '*.proto') go mod tidy # generate codec/testdata proto code From 53a44a64e199f866cb4f9123cdd9744d735fed87 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 25 Feb 2021 21:39:18 +0100 Subject: [PATCH 51/70] rollback changes in protocgen.sh --- scripts/protocgen.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh index fc34f9bf66f9..84eb751c3a10 100755 --- a/scripts/protocgen.sh +++ b/scripts/protocgen.sh @@ -27,11 +27,11 @@ done # command to generate docs using protoc-gen-doc buf protoc \ - -I "proto" \ - -I "third_party/proto" \ - --doc_out=./docs/core \ - --doc_opt=./docs/protodoc-markdown.tmpl,proto-docs.md \ - $(find "$(pwd)/proto" -maxdepth 5 -name '*.proto') +-I "proto" \ +-I "third_party/proto" \ +--doc_out=./docs/core \ +--doc_opt=./docs/protodoc-markdown.tmpl,proto-docs.md \ +$(find "$(pwd)/proto" -maxdepth 5 -name '*.proto') go mod tidy # generate codec/testdata proto code From 9d280349172ef6343367a5ab37041983489eb196 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 25 Feb 2021 21:39:49 +0100 Subject: [PATCH 52/70] add MessageName --- crypto/keys/ecdsa/privkey.go | 5 +++++ crypto/keys/ecdsa/pubkey.go | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/crypto/keys/ecdsa/privkey.go b/crypto/keys/ecdsa/privkey.go index f0c27a95ad58..e27d378538fe 100644 --- a/crypto/keys/ecdsa/privkey.go +++ b/crypto/keys/ecdsa/privkey.go @@ -74,6 +74,11 @@ func (sk *ecdsaSK) String() string { return curveNames[sk.Curve] + "{-}" } +// XXX_MessageName provides a proto name for proto.MessageName. +func (sk *ecdsaSK) XXX_MessageName() string { //nolint:golint + return fmt.Sprintf("cosmos.crypto.%s.PrivKey", curveNames[sk.Curve]) +} + // **** Proto Marshaler **** // Marshal implements ProtoMarshaler interface. diff --git a/crypto/keys/ecdsa/pubkey.go b/crypto/keys/ecdsa/pubkey.go index 66b52b42490d..cd512835afbc 100644 --- a/crypto/keys/ecdsa/pubkey.go +++ b/crypto/keys/ecdsa/pubkey.go @@ -91,6 +91,11 @@ func (pk *ecdsaPK) String() string { return fmt.Sprintf("%s{%X}", curveNames[pk.Curve], pk.Bytes()) } +// XXX_MessageName provides a proto name for proto.MessageName. +func (pk *ecdsaPK) XXX_MessageName() string { //nolint:golint + return "cosmos.crypto.ecdsa.PubKey" +} + // **** Proto Marshaler **** // Marshal implements ProtoMarshaler interface. From be6a226ae8d9095b4704c66a1c41ea016b091883 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Tue, 2 Mar 2021 16:18:41 +0100 Subject: [PATCH 53/70] rework ecdsa proto structure --- docs/core/proto-docs.md | 84 ++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 34 deletions(-) diff --git a/docs/core/proto-docs.md b/docs/core/proto-docs.md index ad82d96f36aa..00889e2d233f 100644 --- a/docs/core/proto-docs.md +++ b/docs/core/proto-docs.md @@ -112,9 +112,6 @@ - [Msg](#cosmos.bank.v1beta1.Msg) -- [cosmos/base/bytes.proto](#cosmos/base/bytes.proto) - - [PBBytes](#cosmos.crypto.secp256r1.PBBytes) - - [cosmos/base/kv/v1beta1/kv.proto](#cosmos/base/kv/v1beta1/kv.proto) - [Pair](#cosmos.base.kv.v1beta1.Pair) - [Pairs](#cosmos.base.kv.v1beta1.Pairs) @@ -193,6 +190,10 @@ - [PrivKey](#cosmos.crypto.secp256k1.PrivKey) - [PubKey](#cosmos.crypto.secp256k1.PubKey) +- [cosmos/crypto/secp256r1/keys.proto](#cosmos/crypto/secp256r1/keys.proto) + - [PrivKey](#cosmos.crypto.secp256r1.PrivKey) + - [PubKey](#cosmos.crypto.secp256r1.PubKey) + - [cosmos/distribution/v1beta1/distribution.proto](#cosmos/distribution/v1beta1/distribution.proto) - [CommunityPoolSpendProposal](#cosmos.distribution.v1beta1.CommunityPoolSpendProposal) - [CommunityPoolSpendProposalWithDeposit](#cosmos.distribution.v1beta1.CommunityPoolSpendProposalWithDeposit) @@ -2166,37 +2167,6 @@ Msg defines the bank Msg service. - -

Top

- -## cosmos/base/bytes.proto - - - - - -### PBBytes -PBBytes defines a structure wrapping protocol buffers raw bytes serialization - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `bytes` | [bytes](#bytes) | | | - - - - - - - - - - - - - - -

Top

@@ -3144,6 +3114,52 @@ This prefix is followed with the x-coordinate. + + + + + + + + + + + +

Top

+ +## cosmos/crypto/secp256r1/keys.proto + + + + + +### PrivKey +PrivKey defines a secp256r1 private key. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `key` | [bytes](#bytes) | | | + + + + + + + + +### PubKey +PubKey defines a secp256r1 public key + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `key` | [bytes](#bytes) | | | + + + + + From c1fd43925a47b88dc5a8857016440f8a2f726592 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Tue, 2 Mar 2021 21:53:08 +0100 Subject: [PATCH 54/70] move ecdsa to internal package --- crypto/keys/{ => internal}/ecdsa/init.go | 0 crypto/keys/{ => internal}/ecdsa/privkey.go | 0 crypto/keys/{ => internal}/ecdsa/privkey_internal_test.go | 0 crypto/keys/{ => internal}/ecdsa/pubkey.go | 0 crypto/keys/{ => internal}/ecdsa/pubkey_internal_test.go | 0 docs/core/proto-docs.md | 8 ++++---- 6 files changed, 4 insertions(+), 4 deletions(-) rename crypto/keys/{ => internal}/ecdsa/init.go (100%) rename crypto/keys/{ => internal}/ecdsa/privkey.go (100%) rename crypto/keys/{ => internal}/ecdsa/privkey_internal_test.go (100%) rename crypto/keys/{ => internal}/ecdsa/pubkey.go (100%) rename crypto/keys/{ => internal}/ecdsa/pubkey_internal_test.go (100%) diff --git a/crypto/keys/ecdsa/init.go b/crypto/keys/internal/ecdsa/init.go similarity index 100% rename from crypto/keys/ecdsa/init.go rename to crypto/keys/internal/ecdsa/init.go diff --git a/crypto/keys/ecdsa/privkey.go b/crypto/keys/internal/ecdsa/privkey.go similarity index 100% rename from crypto/keys/ecdsa/privkey.go rename to crypto/keys/internal/ecdsa/privkey.go diff --git a/crypto/keys/ecdsa/privkey_internal_test.go b/crypto/keys/internal/ecdsa/privkey_internal_test.go similarity index 100% rename from crypto/keys/ecdsa/privkey_internal_test.go rename to crypto/keys/internal/ecdsa/privkey_internal_test.go diff --git a/crypto/keys/ecdsa/pubkey.go b/crypto/keys/internal/ecdsa/pubkey.go similarity index 100% rename from crypto/keys/ecdsa/pubkey.go rename to crypto/keys/internal/ecdsa/pubkey.go diff --git a/crypto/keys/ecdsa/pubkey_internal_test.go b/crypto/keys/internal/ecdsa/pubkey_internal_test.go similarity index 100% rename from crypto/keys/ecdsa/pubkey_internal_test.go rename to crypto/keys/internal/ecdsa/pubkey_internal_test.go diff --git a/docs/core/proto-docs.md b/docs/core/proto-docs.md index 00889e2d233f..e755dc9f311a 100644 --- a/docs/core/proto-docs.md +++ b/docs/core/proto-docs.md @@ -3134,12 +3134,12 @@ This prefix is followed with the x-coordinate. ### PrivKey -PrivKey defines a secp256r1 private key. +PrivKey defines a secp256r1 ECDSA private key. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `key` | [bytes](#bytes) | | | +| `secret` | [bytes](#bytes) | | secret number serialized using big-endian encoding | @@ -3149,12 +3149,12 @@ PrivKey defines a secp256r1 private key. ### PubKey -PubKey defines a secp256r1 public key +PubKey defines a secp256r1 ECDSA public key. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `key` | [bytes](#bytes) | | | +| `point` | [bytes](#bytes) | | Point on secp256r1 curve in a compressed representation as specified in section 4.3.6 of ANSI X9.62. | From a119d7cf19e062e31fc1be4fd68ca57ac07cd297 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Tue, 2 Mar 2021 21:58:23 +0100 Subject: [PATCH 55/70] add secp256r1 proto --- proto/cosmos/crypto/secp256r1/keys.proto | 27 ++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 proto/cosmos/crypto/secp256r1/keys.proto diff --git a/proto/cosmos/crypto/secp256r1/keys.proto b/proto/cosmos/crypto/secp256r1/keys.proto new file mode 100644 index 000000000000..edaa76fe5320 --- /dev/null +++ b/proto/cosmos/crypto/secp256r1/keys.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; +package cosmos.crypto.secp256r1; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1"; + +// PubKey defines a secp256r1 ECDSA public key. +message PubKey { + option (gogoproto.goproto_stringer) = false; + option (gogoproto.marshaler) = false; + option (gogoproto.goproto_getters) = false; + + // Point on secp256r1 curve in a compressed representation as specified in section + // 4.3.6 of ANSI X9.62. + bytes point = 1 [(gogoproto.customtype) = "ecdsaPK"]; +} + +// PrivKey defines a secp256r1 ECDSA private key. +message PrivKey { + option (gogoproto.goproto_stringer) = false; + option (gogoproto.marshaler) = false; + option (gogoproto.goproto_getters) = false; + + // secret number serialized using big-endian encoding + bytes secret = 1; +} From 68ebb56ba317780119d5ba0f476a2c5008c68769 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 3 Mar 2021 04:27:26 +0100 Subject: [PATCH 56/70] refactore proto definition for secp256r1 --- crypto/codec/proto.go | 4 +- crypto/keys/internal/ecdsa/init.go | 61 +-- crypto/keys/internal/ecdsa/privkey.go | 117 +--- .../internal/ecdsa/privkey_internal_test.go | 73 +-- crypto/keys/internal/ecdsa/pubkey.go | 105 +--- .../internal/ecdsa/pubkey_internal_test.go | 113 +--- crypto/keys/secp256r1/init.go | 34 ++ crypto/keys/secp256r1/keys.pb.go | 503 ++++++++++++++++++ crypto/keys/secp256r1/privkey.go | 63 +++ .../keys/secp256r1/privkey_internal_test.go | 115 ++++ crypto/keys/secp256r1/pubkey.go | 59 ++ crypto/keys/secp256r1/pubkey_internal_test.go | 122 +++++ docs/core/proto-docs.md | 2 +- proto/cosmos/crypto/secp256r1/keys.proto | 15 +- 14 files changed, 982 insertions(+), 404 deletions(-) create mode 100644 crypto/keys/secp256r1/init.go create mode 100644 crypto/keys/secp256r1/keys.pb.go create mode 100644 crypto/keys/secp256r1/privkey.go create mode 100644 crypto/keys/secp256r1/privkey_internal_test.go create mode 100644 crypto/keys/secp256r1/pubkey.go create mode 100644 crypto/keys/secp256r1/pubkey_internal_test.go diff --git a/crypto/codec/proto.go b/crypto/codec/proto.go index 7b4bd3b5042b..7f38dee61433 100644 --- a/crypto/codec/proto.go +++ b/crypto/codec/proto.go @@ -2,10 +2,10 @@ package codec import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/crypto/keys/ecdsa" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "github.com/cosmos/cosmos-sdk/crypto/keys/multisig" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" ) @@ -16,5 +16,5 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterImplementations(pk, &ed25519.PubKey{}) registry.RegisterImplementations(pk, &secp256k1.PubKey{}) registry.RegisterImplementations(pk, &multisig.LegacyAminoPubKey{}) - ecdsa.RegisterInterfaces(registry) + secp256r1.RegisterInterfaces(registry) } diff --git a/crypto/keys/internal/ecdsa/init.go b/crypto/keys/internal/ecdsa/init.go index b691eb460039..a27b9caf9a8e 100644 --- a/crypto/keys/internal/ecdsa/init.go +++ b/crypto/keys/internal/ecdsa/init.go @@ -1,60 +1,3 @@ -// ECDSA package implements Cosmos-SDK compatible ECDSA public and private key. The keys -// can be protobuf serialized and packed in Any. -// Currently supported keys are: -// + secp256r1 +// Package ECDSA implements Cosmos-SDK compatible ECDSA public and private key. The keys +// can be serialized. package ecdsa - -import ( - "crypto/elliptic" - "fmt" - math_bits "math/bits" - - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" -) - -const ( - // PubKeySize is is the size, in bytes, of public keys as used in this package. - PubKeySize = 32 + 1 + 1 - // PrivKeySize is the size, in bytes, of private keys as used in this package. - PrivKeySize = 32 + 1 -) - -var secp256r1 elliptic.Curve -var curveNames map[elliptic.Curve]string -var curveTypes map[elliptic.Curve]byte -var curveTypesRev map[byte]elliptic.Curve - -// Protobuf Bytes size - this computation is based on gogotypes.BytesValue.Sizee implementation -var sovPubKeySize = 1 + PubKeySize + sovKeys(PubKeySize) -var sovPrivKeySize = 1 + PrivKeySize + sovKeys(PrivKeySize) - -func init() { - secp256r1 = elliptic.P256() - // PubKeySize is ceil of field bit size + 1 for the sign + 1 for the type - expected := (secp256r1.Params().BitSize+7)/8 + 2 - if expected != PubKeySize { - panic(fmt.Sprintf("Wrong PubKeySize=%d, expecting=%d", PubKeySize, expected)) - } - - curveNames = map[elliptic.Curve]string{ - secp256r1: "secp256r1", - } - curveTypes = map[elliptic.Curve]byte{ - // 0 reserved - secp256r1: 1, - } - curveTypesRev = map[byte]elliptic.Curve{} - for c, b := range curveTypes { - curveTypesRev[b] = c - } -} - -// RegisterInterfaces adds ecdsa PubKey to pubkey registry -func RegisterInterfaces(registry codectypes.InterfaceRegistry) { - registry.RegisterImplementations((*cryptotypes.PubKey)(nil), &ecdsaPK{}) -} - -func sovKeys(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} diff --git a/crypto/keys/internal/ecdsa/privkey.go b/crypto/keys/internal/ecdsa/privkey.go index e27d378538fe..05299c838cbf 100644 --- a/crypto/keys/internal/ecdsa/privkey.go +++ b/crypto/keys/internal/ecdsa/privkey.go @@ -2,132 +2,65 @@ package ecdsa import ( "crypto/ecdsa" + "crypto/elliptic" "crypto/rand" "crypto/sha256" "fmt" "math/big" - - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - gogotypes "github.com/gogo/protobuf/types" ) -type ecdsaSK struct { - ecdsa.PrivateKey +// GenPrivKey generates a new secp256r1 private key. It uses operating system randomness. +func GenPrivKey(curve elliptic.Curve) (PrivKey, error) { + key, err := ecdsa.GenerateKey(curve, rand.Reader) + return PrivKey{*key}, err } -// GenSecp256r1 generates a new secp256r1 private key. It uses operating system randomness. -func GenSecp256r1() (cryptotypes.PrivKey, error) { - key, err := ecdsa.GenerateKey(secp256r1, rand.Reader) - return &ecdsaSK{*key}, err +type PrivKey struct { + ecdsa.PrivateKey } // PubKey implements Cosmos-SDK PrivKey interface. -func (sk *ecdsaSK) PubKey() cryptotypes.PubKey { - return &ecdsaPK{sk.PublicKey, nil} +func (sk *PrivKey) PubKey() PubKey { + return PubKey{sk.PublicKey, nil} } // Bytes serialize the private key with first byte being the curve type. -func (sk *ecdsaSK) Bytes() []byte { +func (sk *PrivKey) Bytes() []byte { if sk == nil { return nil } - bz := make([]byte, PrivKeySize) - bz[0] = curveTypes[sk.Curve] - sk.D.FillBytes(bz[1:]) + fieldSize := (sk.Curve.Params().BitSize + 7) / 8 + bz := make([]byte, fieldSize) + sk.D.FillBytes(bz) return bz } -// Equals - you probably don't need to use this. -// Runs in constant time based on length of the keys. -func (sk *ecdsaSK) Equals(other cryptotypes.LedgerPrivKey) bool { - sk2, ok := other.(*ecdsaSK) - if !ok { - return false - } - return sk.PrivateKey.Equal(&sk2.PrivateKey) -} - -// Type returns key type name. Implements sdk.PrivKey interface. -func (sk *ecdsaSK) Type() string { - return curveNames[sk.Curve] -} - // Sign hashes and signs the message usign ECDSA. Implements sdk.PrivKey interface. -func (sk *ecdsaSK) Sign(msg []byte) ([]byte, error) { +func (sk *PrivKey) Sign(msg []byte) ([]byte, error) { digest := sha256.Sum256(msg) return sk.PrivateKey.Sign(rand.Reader, digest[:], nil) } -// **** proto.Message **** - -// Reset implements proto.Message interface. -func (sk *ecdsaSK) Reset() { - sk.D = new(big.Int) - sk.PublicKey = ecdsa.PublicKey{} -} - -// ProtoMessage implements proto.Message interface. -func (*ecdsaSK) ProtoMessage() {} - // String implements proto.Message interface. -func (sk *ecdsaSK) String() string { - return curveNames[sk.Curve] + "{-}" -} - -// XXX_MessageName provides a proto name for proto.MessageName. -func (sk *ecdsaSK) XXX_MessageName() string { //nolint:golint - return fmt.Sprintf("cosmos.crypto.%s.PrivKey", curveNames[sk.Curve]) -} - -// **** Proto Marshaler **** - -// Marshal implements ProtoMarshaler interface. -func (sk *ecdsaSK) Marshal() ([]byte, error) { - bv := gogotypes.BytesValue{Value: sk.Bytes()} - return bv.Marshal() +func (sk *PrivKey) String(name string) string { + return name + "{-}" } // MarshalTo implements ProtoMarshaler interface. -func (sk *ecdsaSK) MarshalTo(data []byte) (int, error) { - bv := gogotypes.BytesValue{Value: sk.Bytes()} - return bv.MarshalTo(data) -} - -// MarshalToSizedBuffer implements ProtoMarshaler interface. -func (sk *ecdsaSK) MarshalToSizedBuffer(dAtA []byte) (int, error) { - bv := gogotypes.BytesValue{Value: sk.Bytes()} - return bv.MarshalToSizedBuffer(dAtA) +func (sk *PrivKey) MarshalTo(dAtA []byte) (int, error) { + bz := sk.Bytes() + copy(dAtA, bz) + return len(bz), nil } // Unmarshal implements ProtoMarshaler interface. -func (sk *ecdsaSK) Unmarshal(b []byte) error { - bv := gogotypes.BytesValue{} - err := bv.Unmarshal(b) - if err != nil { - return err - } - bz := bv.Value - if len(bz) != PrivKeySize { - return fmt.Errorf("wrong ECDSA SK bytes, expecting %d bytes", PrivKeySize) - } - curve, ok := curveTypesRev[bz[0]] - if !ok { - return fmt.Errorf("wrong ECDSA PK bytes, unknown curve type: %d", bz[0]) +func (sk *PrivKey) Unmarshal(bz []byte, curve elliptic.Curve, expectedSize int) error { + if len(bz) != expectedSize { + return fmt.Errorf("wrong ECDSA SK bytes, expecting %d bytes", expectedSize) } - if sk == nil { - sk = new(ecdsaSK) - } sk.Curve = curve - sk.D = new(big.Int).SetBytes(bz[1:]) - sk.X, sk.Y = curve.ScalarBaseMult(bz[1:]) + sk.D = new(big.Int).SetBytes(bz) + sk.X, sk.Y = curve.ScalarBaseMult(bz) return nil } - -// Size implements ProtoMarshaler interface. -func (sk *ecdsaSK) Size() int { - if sk == nil { - return 0 - } - return sovPrivKeySize -} diff --git a/crypto/keys/internal/ecdsa/privkey_internal_test.go b/crypto/keys/internal/ecdsa/privkey_internal_test.go index 11e312650d02..095e593656d7 100644 --- a/crypto/keys/internal/ecdsa/privkey_internal_test.go +++ b/crypto/keys/internal/ecdsa/privkey_internal_test.go @@ -1,21 +1,13 @@ package ecdsa import ( - "crypto/ecdsa" - "math/big" "testing" "github.com/tendermint/tendermint/crypto" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/codec/types" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - proto "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/suite" ) -var _ cryptotypes.PrivKey = &ecdsaSK{} - func TestSKSuite(t *testing.T) { suite.Run(t, new(SKSuite)) } @@ -23,74 +15,33 @@ func TestSKSuite(t *testing.T) { type SKSuite struct{ CommonSuite } func (suite *SKSuite) TestString() { - suite.Require().Equal("secp256r1{-}", suite.sk.String()) -} - -func (suite *SKSuite) TestEquals() { - require := suite.Require() - - skOther, err := GenSecp256r1() - require.NoError(err) - require.False(suite.sk.Equals(skOther)) - - skOther2 := &ecdsaSK{skOther.(*ecdsaSK).PrivateKey} - require.True(skOther.Equals(skOther2)) - require.True(skOther2.Equals(skOther), "Equals must be reflexive") + const prefix = "abc" + suite.Require().Equal(prefix+"{-}", suite.sk.String(prefix)) } func (suite *SKSuite) TestPubKey() { pk := suite.sk.PubKey() - suite.True(suite.sk.(*ecdsaSK).PublicKey.Equal(&pk.(*ecdsaPK).PublicKey)) + suite.True(suite.sk.PublicKey.Equal(&pk.PublicKey)) } func (suite *SKSuite) Bytes() { bz := suite.sk.Bytes() - suite.Len(bz, PrivKeySize) - var sk *ecdsaSK + suite.Len(bz, 32) + var sk *PrivKey suite.Nil(sk.Bytes()) } -func (suite *SKSuite) TestReset() { - var sk = &ecdsaSK{PrivateKey: ecdsa.PrivateKey{D: big.NewInt(1)}} - sk.Reset() - suite.Equal(0, sk.D.Cmp(big.NewInt(0))) - suite.Equal(ecdsa.PublicKey{}, sk.PublicKey) -} - -func (suite *SKSuite) TestMarshalProto() { +func (suite *SKSuite) TestMarshal() { require := suite.Require() + const size = 32 - /**** test structure marshalling ****/ - - var sk ecdsaSK - bz, err := proto.Marshal(suite.sk) - require.NoError(err) - require.NoError(proto.Unmarshal(bz, &sk)) - require.True(sk.Equals(suite.sk)) - - /**** test structure marshalling with codec ****/ - - sk = ecdsaSK{} - registry := types.NewInterfaceRegistry() - cdc := codec.NewProtoCodec(registry) - bz, err = cdc.MarshalBinaryBare(suite.sk.(*ecdsaSK)) - require.NoError(err) - require.NoError(cdc.UnmarshalBinaryBare(bz, &sk)) - require.True(sk.Equals(suite.sk)) - - const bufSize = 100 - bz2 := make([]byte, bufSize) - skCpy := suite.sk.(*ecdsaSK) - _, err = skCpy.MarshalTo(bz2) - require.NoError(err) - require.Len(bz2, bufSize) - require.Equal(bz, bz2[:sovPrivKeySize]) + var buffer = make([]byte, size) + suite.sk.MarshalTo(buffer) - bz2 = make([]byte, bufSize) - _, err = skCpy.MarshalToSizedBuffer(bz2) + var sk = new(PrivKey) + err := sk.Unmarshal(buffer, secp256r1, size) require.NoError(err) - require.Len(bz2, bufSize) - require.Equal(bz, bz2[(bufSize-sovPrivKeySize):]) + require.True(sk.Equal(&suite.sk.PrivateKey)) } func (suite *SKSuite) TestSign() { diff --git a/crypto/keys/internal/ecdsa/pubkey.go b/crypto/keys/internal/ecdsa/pubkey.go index cd512835afbc..64adfee63638 100644 --- a/crypto/keys/internal/ecdsa/pubkey.go +++ b/crypto/keys/internal/ecdsa/pubkey.go @@ -8,10 +8,8 @@ import ( "fmt" "math/big" - gogotypes "github.com/gogo/protobuf/types" tmcrypto "github.com/tendermint/tendermint/crypto" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/types/address" "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -21,7 +19,7 @@ type signature struct { R, S *big.Int } -type ecdsaPK struct { +type PubKey struct { ecdsa.PublicKey // cache @@ -29,39 +27,24 @@ type ecdsaPK struct { } // String implements PubKey interface. -func (pk *ecdsaPK) Address() tmcrypto.Address { +func (pk *PubKey) Address(protoName string) tmcrypto.Address { if pk.address == nil { - pk.address = address.Hash(curveNames[pk.Curve], pk.Bytes()) + pk.address = address.Hash(protoName, pk.Bytes()) } return pk.address } // Bytes returns the byte representation of the public key using a compressed form // specified in section 4.3.6 of ANSI X9.62 with first byte being the curve type. -func (pk *ecdsaPK) Bytes() []byte { +func (pk *PubKey) Bytes() []byte { if pk == nil { return nil } - compressed := make([]byte, PubKeySize) - compressed[0] = curveTypes[pk.Curve] - compressed[1] = byte(pk.Y.Bit(0)) | 2 - pk.X.FillBytes(compressed[2:]) - return compressed -} - -// Equals - you probably don't need to use this. -// Runs in constant time based on length of the keys. -func (pk *ecdsaPK) Equals(other cryptotypes.PubKey) bool { - pk2, ok := other.(*ecdsaPK) - if !ok { - return false - } - - return pk.PublicKey.Equal(&pk2.PublicKey) + return elliptic.MarshalCompressed(pk.Curve, pk.X, pk.Y) } // VerifySignature implements skd.PubKey interface. -func (pk *ecdsaPK) VerifySignature(msg []byte, sig []byte) bool { +func (pk *PubKey) VerifySignature(msg []byte, sig []byte) bool { s := new(signature) if _, err := asn1.Unmarshal(sig, s); err != nil || s == nil { return false @@ -71,84 +54,30 @@ func (pk *ecdsaPK) VerifySignature(msg []byte, sig []byte) bool { return ecdsa.Verify(&pk.PublicKey, h[:], s.R, s.S) } -// Type returns key type name. Implements sdk.PubKey interface. -func (pk *ecdsaPK) Type() string { - return curveNames[pk.Curve] -} - -// **** proto.Message **** - -// Reset implements proto.Message interface. -func (pk *ecdsaPK) Reset() { - *pk = ecdsaPK{} -} - -// ProtoMessage implements proto.Message interface. -func (*ecdsaPK) ProtoMessage() {} - // String implements proto.Message interface -func (pk *ecdsaPK) String() string { - return fmt.Sprintf("%s{%X}", curveNames[pk.Curve], pk.Bytes()) -} - -// XXX_MessageName provides a proto name for proto.MessageName. -func (pk *ecdsaPK) XXX_MessageName() string { //nolint:golint - return "cosmos.crypto.ecdsa.PubKey" +func (pk *PubKey) String(curveName string) string { + return fmt.Sprintf("%s{%X}", curveName, pk.Bytes()) } // **** Proto Marshaler **** -// Marshal implements ProtoMarshaler interface. -func (pk *ecdsaPK) Marshal() ([]byte, error) { - bv := gogotypes.BytesValue{Value: pk.Bytes()} - return bv.Marshal() -} - // MarshalTo implements ProtoMarshaler interface. -func (pk *ecdsaPK) MarshalTo(data []byte) (int, error) { - bv := gogotypes.BytesValue{Value: pk.Bytes()} - return bv.MarshalTo(data) -} - -// MarshalToSizedBuffer implements ProtoMarshaler interface. -func (pk *ecdsaPK) MarshalToSizedBuffer(dAtA []byte) (int, error) { - bv := gogotypes.BytesValue{Value: pk.Bytes()} - return bv.MarshalToSizedBuffer(dAtA) +func (pk *PubKey) MarshalTo(dAtA []byte) (int, error) { + bz := pk.Bytes() + copy(dAtA, bz) + return len(bz), nil } // Unmarshal implements ProtoMarshaler interface. -func (pk *ecdsaPK) Unmarshal(b []byte) error { - bv := gogotypes.BytesValue{} - err := bv.Unmarshal(b) - if err != nil { - return err - } - - bz := bv.Value - if len(bz) != PubKeySize { - return errors.Wrapf(errors.ErrInvalidPubKey, "wrong ECDSA PK bytes, expecting %d bytes", PubKeySize) - } - curve, ok := curveTypesRev[bz[0]] - if !ok { - return errors.Wrapf(errors.ErrInvalidPubKey, "wrong ECDSA PK bytes, unknown curve type: %d", bz[0]) +func (pk *PubKey) Unmarshal(bz []byte, curve elliptic.Curve, expectedSize int) error { + if len(bz) != expectedSize { + return errors.Wrapf(errors.ErrInvalidPubKey, "wrong ECDSA PK bytes, expecting %d bytes, got %d", expectedSize, len(bz)) } cpk := ecdsa.PublicKey{Curve: curve} - cpk.X, cpk.Y = elliptic.UnmarshalCompressed(curve, bz[1:]) + cpk.X, cpk.Y = elliptic.UnmarshalCompressed(curve, bz) if cpk.X == nil || cpk.Y == nil { return errors.Wrapf(errors.ErrInvalidPubKey, "wrong ECDSA PK bytes, unknown curve type: %d", bz[0]) } - if pk == nil { - *pk = ecdsaPK{cpk, nil} - } else { - pk.PublicKey = cpk - } + pk.PublicKey = cpk return nil } - -// Size implements ProtoMarshaler interface. -func (pk *ecdsaPK) Size() int { - if pk == nil { - return 0 - } - return sovPubKeySize -} diff --git a/crypto/keys/internal/ecdsa/pubkey_internal_test.go b/crypto/keys/internal/ecdsa/pubkey_internal_test.go index b12c229b89b6..2a46bdff39d7 100644 --- a/crypto/keys/internal/ecdsa/pubkey_internal_test.go +++ b/crypto/keys/internal/ecdsa/pubkey_internal_test.go @@ -1,28 +1,27 @@ package ecdsa import ( - "crypto/ecdsa" + "crypto/elliptic" "encoding/hex" - "math/big" "testing" - proto "github.com/gogo/protobuf/proto" - gogotypes "github.com/gogo/protobuf/types" "github.com/stretchr/testify/suite" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/codec/types" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" ) +var secp256r1 = elliptic.P256() + +func GenSecp256r1() (PrivKey, error) { + return GenPrivKey(secp256r1) +} + func TestPKSuite(t *testing.T) { suite.Run(t, new(PKSuite)) } type CommonSuite struct { suite.Suite - pk cryptotypes.PubKey - sk cryptotypes.PrivKey + pk PubKey + sk PrivKey } func (suite *CommonSuite) SetupSuite() { @@ -38,101 +37,33 @@ func (suite *PKSuite) TestString() { assert := suite.Assert() require := suite.Require() - pkStr := suite.pk.String() - prefix := "secp256r1{" - require.Len(pkStr, len(prefix)+PubKeySize*2+1) // prefix + hex_len + "}" - assert.Equal(prefix, pkStr[:len(prefix)]) + prefix := "abc" + pkStr := suite.pk.String(prefix) + assert.Equal(prefix+"{", pkStr[:len(prefix)+1]) assert.EqualValues('}', pkStr[len(pkStr)-1]) - bz, err := hex.DecodeString(pkStr[len(prefix) : len(pkStr)-1]) + bz, err := hex.DecodeString(pkStr[len(prefix)+1 : len(pkStr)-1]) require.NoError(err) assert.EqualValues(suite.pk.Bytes(), bz) } func (suite *PKSuite) TestBytes() { require := suite.Require() - var pk *ecdsaPK + var pk *PubKey require.Nil(pk.Bytes()) - require.Len(suite.pk.Bytes(), PubKeySize) } -func (suite *PKSuite) TestReset() { - pk := &ecdsaPK{ecdsa.PublicKey{X: big.NewInt(1)}, []byte{1}} - pk.Reset() - suite.Nil(pk.address) - suite.Equal(pk.PublicKey, ecdsa.PublicKey{}) -} - -func (suite *PKSuite) TestEquals() { +func (suite *PKSuite) TestMarshal() { require := suite.Require() + const size = 33 // secp256r1 size - skOther, err := GenSecp256r1() + var buffer = make([]byte, size) + n, err := suite.pk.MarshalTo(buffer) require.NoError(err) - pkOther := skOther.PubKey() - pkOther2 := &ecdsaPK{skOther.(*ecdsaSK).PublicKey, nil} - - require.False(suite.pk.Equals(pkOther)) - require.True(pkOther.Equals(pkOther2)) - require.True(pkOther2.Equals(pkOther)) - require.True(pkOther.Equals(pkOther), "Equals must be reflexive") -} - -func (suite *PKSuite) TestSize() { - require := suite.Require() - bv := gogotypes.BytesValue{Value: suite.pk.Bytes()} - require.Equal(bv.Size(), suite.pk.(*ecdsaPK).Size()) - - var nilPk *ecdsaPK - require.Equal(0, nilPk.Size(), "nil value must have zero size") -} - -func (suite *PKSuite) TestMarshalProto() { - require := suite.Require() + require.Equal(size, n) - /**** test structure marshalling ****/ - - var pk ecdsaPK - bz, err := proto.Marshal(suite.pk) - require.NoError(err) - require.NoError(proto.Unmarshal(bz, &pk)) - require.True(pk.Equals(suite.pk)) - - /**** test structure marshalling with codec ****/ - - pk = ecdsaPK{} - registry := types.NewInterfaceRegistry() - cdc := codec.NewProtoCodec(registry) - bz, err = cdc.MarshalBinaryBare(suite.pk.(*ecdsaPK)) + var pk = new(PubKey) + err = pk.Unmarshal(buffer, secp256r1, size) require.NoError(err) - require.NoError(cdc.UnmarshalBinaryBare(bz, &pk)) - require.True(pk.Equals(suite.pk)) - - const bufSize = 100 - bz2 := make([]byte, bufSize) - pkCpy := suite.pk.(*ecdsaPK) - _, err = pkCpy.MarshalTo(bz2) - require.NoError(err) - require.Len(bz2, bufSize) - require.Equal(bz, bz2[:sovPubKeySize]) - - bz2 = make([]byte, bufSize) - _, err = pkCpy.MarshalToSizedBuffer(bz2) - require.NoError(err) - require.Len(bz2, bufSize) - require.Equal(bz, bz2[(bufSize-sovPubKeySize):]) - - /**** test interface marshalling ****/ - - bz, err = cdc.MarshalInterface(suite.pk) - require.NoError(err) - var pkI cryptotypes.PubKey - err = cdc.UnmarshalInterface(bz, &pkI) - require.EqualError(err, "no registered implementations of type types.PubKey") - - registry.RegisterImplementations((*cryptotypes.PubKey)(nil), new(ecdsaPK)) - require.NoError(cdc.UnmarshalInterface(bz, &pkI)) - require.True(pkI.Equals(suite.pk)) - - cdc.UnmarshalInterface(bz, nil) - require.Error(err, "nil should fail") + require.True(pk.PublicKey.Equal(&suite.pk.PublicKey)) } diff --git a/crypto/keys/secp256r1/init.go b/crypto/keys/secp256r1/init.go new file mode 100644 index 000000000000..116ac43e8d5d --- /dev/null +++ b/crypto/keys/secp256r1/init.go @@ -0,0 +1,34 @@ +// secp256r1 package implements Cosmos-SDK compatible ECDSA public and private key. The keys +// can be protobuf serialized and packed in Any. +package secp256r1 + +import ( + "crypto/elliptic" + "fmt" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" +) + +const ( + // fieldSize is the curve domain size. + fieldSize = 32 + + name = "secp256r1" +) + +var secp256r1 elliptic.Curve + +func init() { + secp256r1 = elliptic.P256() + // pubKeySize is ceil of field bit size + 1 for the sign + expected := (secp256r1.Params().BitSize + 7) / 8 + if expected != fieldSize { + panic(fmt.Sprintf("Wrong fieldSize=%d, expecting=%d", fieldSize, expected)) + } +} + +// RegisterInterfaces adds secp256r1 PubKey to pubkey registry +func RegisterInterfaces(registry codectypes.InterfaceRegistry) { + registry.RegisterImplementations((*cryptotypes.PubKey)(nil), &PubKey{}) +} diff --git a/crypto/keys/secp256r1/keys.pb.go b/crypto/keys/secp256r1/keys.pb.go new file mode 100644 index 000000000000..898daa499b11 --- /dev/null +++ b/crypto/keys/secp256r1/keys.pb.go @@ -0,0 +1,503 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: cosmos/crypto/secp256r1/keys.proto + +package secp256r1 + +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 + +// PubKey defines a secp256r1 ECDSA public key. +type PubKey struct { + // Point on secp256r1 curve in a compressed representation as specified in section + // 4.3.6 of ANSI X9.62. + Key *ecdsaPK `protobuf:"bytes,1,opt,name=key,proto3,customtype=ecdsaPK" json:"key,omitempty"` +} + +func (m *PubKey) Reset() { *m = PubKey{} } +func (*PubKey) ProtoMessage() {} +func (*PubKey) Descriptor() ([]byte, []int) { + return fileDescriptor_b90c18415095c0c3, []int{0} +} +func (m *PubKey) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PubKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PubKey.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 *PubKey) XXX_Merge(src proto.Message) { + xxx_messageInfo_PubKey.Merge(m, src) +} +func (m *PubKey) XXX_Size() int { + return m.Size() +} +func (m *PubKey) XXX_DiscardUnknown() { + xxx_messageInfo_PubKey.DiscardUnknown(m) +} + +var xxx_messageInfo_PubKey proto.InternalMessageInfo + +func (*PubKey) XXX_MessageName() string { + return "cosmos.crypto.secp256r1.PubKey" +} + +// PrivKey defines a secp256r1 ECDSA private key. +type PrivKey struct { + // secret number serialized using big-endian encoding + Secret *ecdsaSK `protobuf:"bytes,1,opt,name=secret,proto3,customtype=ecdsaSK" json:"secret,omitempty"` +} + +func (m *PrivKey) Reset() { *m = PrivKey{} } +func (*PrivKey) ProtoMessage() {} +func (*PrivKey) Descriptor() ([]byte, []int) { + return fileDescriptor_b90c18415095c0c3, []int{1} +} +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 (*PrivKey) XXX_MessageName() string { + return "cosmos.crypto.secp256r1.PrivKey" +} +func init() { + proto.RegisterType((*PubKey)(nil), "cosmos.crypto.secp256r1.PubKey") + proto.RegisterType((*PrivKey)(nil), "cosmos.crypto.secp256r1.PrivKey") +} + +func init() { + proto.RegisterFile("cosmos/crypto/secp256r1/keys.proto", fileDescriptor_b90c18415095c0c3) +} + +var fileDescriptor_b90c18415095c0c3 = []byte{ + // 221 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4a, 0xce, 0x2f, 0xce, + 0xcd, 0x2f, 0xd6, 0x4f, 0x2e, 0xaa, 0x2c, 0x28, 0xc9, 0xd7, 0x2f, 0x4e, 0x4d, 0x2e, 0x30, 0x32, + 0x35, 0x2b, 0x32, 0xd4, 0xcf, 0x4e, 0xad, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, + 0x87, 0xa8, 0xd1, 0x83, 0xa8, 0xd1, 0x83, 0xab, 0x91, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0xab, + 0xd1, 0x07, 0xb1, 0x20, 0xca, 0x95, 0xd4, 0xb9, 0xd8, 0x02, 0x4a, 0x93, 0xbc, 0x53, 0x2b, 0x85, + 0x64, 0xb9, 0x98, 0xb3, 0x53, 0x2b, 0x25, 0x18, 0x15, 0x18, 0x35, 0x78, 0x9c, 0xb8, 0x6f, 0xdd, + 0x93, 0x67, 0x4f, 0x4d, 0x4e, 0x29, 0x4e, 0x0c, 0xf0, 0x0e, 0x02, 0x89, 0x2b, 0xe9, 0x71, 0xb1, + 0x07, 0x14, 0x65, 0x96, 0x81, 0x54, 0x2a, 0x73, 0xb1, 0x15, 0xa7, 0x26, 0x17, 0xa5, 0x96, 0x60, + 0x28, 0x0e, 0xf6, 0x0e, 0x82, 0x4a, 0x39, 0x45, 0x9c, 0x78, 0x28, 0xc7, 0x70, 0xe3, 0xa1, 0x1c, + 0xc3, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, + 0x1c, 0xc3, 0x89, 0xc7, 0x72, 0x8c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0x10, 0x65, + 0x94, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0x0f, 0xf3, 0x1c, 0x98, 0xd2, + 0x2d, 0x4e, 0xc9, 0x86, 0xf9, 0x13, 0xe4, 0x3b, 0x84, 0x67, 0x93, 0xd8, 0xc0, 0x2e, 0x37, 0x06, + 0x04, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x65, 0x08, 0x5c, 0x0e, 0x01, 0x00, 0x00, +} + +func (m *PubKey) 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 *PubKey) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PubKey) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Key != nil { + { + size := m.Key.Size() + i -= size + if _, err := m.Key.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintKeys(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +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 m.Secret != nil { + { + size := m.Secret.Size() + i -= size + if _, err := m.Secret.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + 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 *PubKey) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Key != nil { + l = m.Key.Size() + n += 1 + l + sovKeys(uint64(l)) + } + return n +} + +func (m *PrivKey) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Secret != nil { + l = m.Secret.Size() + 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 *PubKey) 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: PubKey: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PubKey: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Key", 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 + } + var v ecdsaPK + m.Key = &v + if err := m.Key.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipKeys(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthKeys + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +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 Secret", 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 + } + var v ecdsaSK + m.Secret = &v + if err := m.Secret.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipKeys(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (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/keys/secp256r1/privkey.go b/crypto/keys/secp256r1/privkey.go new file mode 100644 index 000000000000..c538978cfc07 --- /dev/null +++ b/crypto/keys/secp256r1/privkey.go @@ -0,0 +1,63 @@ +package secp256r1 + +import ( + "github.com/cosmos/cosmos-sdk/crypto/keys/internal/ecdsa" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" +) + +// GenPrivKey generates a new secp256r1 private key. It uses operating system randomness. +func GenPrivKey() (*PrivKey, error) { + key, err := ecdsa.GenPrivKey(secp256r1) + return &PrivKey{&ecdsaSK{key}}, err +} + +// PubKey implements Cosmos-SDK PrivKey interface. +func (m *PrivKey) PubKey() cryptotypes.PubKey { + return &PubKey{&ecdsaPK{m.Secret.PubKey()}} +} + +// String implements Cosmos-SDK proto.Message interface. +func (m *PrivKey) String() string { + return m.Secret.String(name) +} + +// Type returns key type name. Implements sdk.PrivKey interface. +func (m *PrivKey) Type() string { + return name +} + +// Sign hashes and signs the message usign ECDSA. Implements sdk.PrivKey interface. +func (m *PrivKey) Sign(msg []byte) ([]byte, error) { + return m.Secret.Sign(msg) +} + +// Bytes serialize the private key. +func (m *PrivKey) Bytes() []byte { + return m.Secret.Bytes() +} + +// Equals implements SDK PrivKey interface. +func (m *PrivKey) Equals(other cryptotypes.LedgerPrivKey) bool { + sk2, ok := other.(*PrivKey) + if !ok { + return false + } + return m.Secret.Equal(&sk2.Secret.PrivateKey) +} + +type ecdsaSK struct { + ecdsa.PrivKey +} + +// Size implements proto.Marshaler interface +func (sk *ecdsaSK) Size() int { + if sk == nil { + return 0 + } + return fieldSize +} + +// Unmarshal implements proto.Marshaler interface +func (sk *ecdsaSK) Unmarshal(bz []byte) error { + return sk.PrivKey.Unmarshal(bz, secp256r1, fieldSize) +} diff --git a/crypto/keys/secp256r1/privkey_internal_test.go b/crypto/keys/secp256r1/privkey_internal_test.go new file mode 100644 index 000000000000..ae48b47e3d68 --- /dev/null +++ b/crypto/keys/secp256r1/privkey_internal_test.go @@ -0,0 +1,115 @@ +package secp256r1 + +import ( + "testing" + + "github.com/tendermint/tendermint/crypto" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + proto "github.com/gogo/protobuf/proto" + "github.com/stretchr/testify/suite" +) + +var _ cryptotypes.PrivKey = &PrivKey{} + +func TestSKSuite(t *testing.T) { + suite.Run(t, new(SKSuite)) +} + +type SKSuite struct{ CommonSuite } + +func (suite *SKSuite) TestString() { + suite.Require().Equal("secp256r1{-}", suite.sk.String()) +} + +func (suite *SKSuite) TestEquals() { + require := suite.Require() + + skOther, err := GenPrivKey() + require.NoError(err) + require.False(suite.sk.Equals(skOther)) + + skOther2 := &PrivKey{skOther.Secret} + require.True(skOther.Equals(skOther2)) + require.True(skOther2.Equals(skOther), "Equals must be reflexive") +} + +func (suite *SKSuite) TestPubKey() { + pk := suite.sk.PubKey() + suite.True(suite.sk.(*PrivKey).Secret.PublicKey.Equal(&pk.(*PubKey).Key.PublicKey)) +} + +func (suite *SKSuite) Bytes() { + bz := suite.sk.Bytes() + suite.Len(bz, fieldSize) + var sk *PrivKey + suite.Nil(sk.Bytes()) +} + +func (suite *SKSuite) TestMarshalProto() { + require := suite.Require() + + /**** test structure marshalling ****/ + + var sk PrivKey + bz, err := proto.Marshal(suite.sk) + require.NoError(err) + require.NoError(proto.Unmarshal(bz, &sk)) + require.True(sk.Equals(suite.sk)) + + /**** test structure marshalling with codec ****/ + + sk = PrivKey{} + registry := types.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(registry) + bz, err = cdc.MarshalBinaryBare(suite.sk.(*PrivKey)) + require.NoError(err) + require.NoError(cdc.UnmarshalBinaryBare(bz, &sk)) + require.True(sk.Equals(suite.sk)) + + const bufSize = 100 + bz2 := make([]byte, bufSize) + skCpy := suite.sk.(*PrivKey) + _, err = skCpy.MarshalTo(bz2) + require.NoError(err) + require.Len(bz2, bufSize) + require.Equal(bz, bz2[:sk.Size()]) + + bz2 = make([]byte, bufSize) + _, err = skCpy.MarshalToSizedBuffer(bz2) + require.NoError(err) + require.Len(bz2, bufSize) + require.Equal(bz, bz2[(bufSize-sk.Size()):]) +} + +func (suite *SKSuite) TestSign() { + require := suite.Require() + + msg := crypto.CRandBytes(1000) + sig, err := suite.sk.Sign(msg) + require.NoError(err) + sigCpy := make([]byte, len(sig)) + copy(sigCpy, sig) + require.True(suite.pk.VerifySignature(msg, sigCpy)) + + // Mutate the signature + for i := range sig { + sigCpy[i] ^= byte(i + 1) + require.False(suite.pk.VerifySignature(msg, sigCpy)) + } + + // Mutate the message + msg[1] ^= byte(2) + require.False(suite.pk.VerifySignature(msg, sig)) +} + +func (suite *SKSuite) TestSize() { + require := suite.Require() + var pk ecdsaSK + require.Equal(pk.Size(), len(suite.sk.Bytes())) + + var nilPk *ecdsaSK + require.Equal(0, nilPk.Size(), "nil value must have zero size") +} diff --git a/crypto/keys/secp256r1/pubkey.go b/crypto/keys/secp256r1/pubkey.go new file mode 100644 index 000000000000..dc1ba06f7e93 --- /dev/null +++ b/crypto/keys/secp256r1/pubkey.go @@ -0,0 +1,59 @@ +package secp256r1 + +import ( + tmcrypto "github.com/tendermint/tendermint/crypto" + + ecdsa "github.com/cosmos/cosmos-sdk/crypto/keys/internal/ecdsa" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" +) + +// String implements proto.Message interface. +func (m *PubKey) String() string { + return m.Key.String(name) +} + +// Bytes implements SDK PubKey interface. +func (m *PubKey) Bytes() []byte { + return m.Key.Bytes() +} + +// Equals implements SDK PubKey interface. +func (m *PubKey) Equals(other cryptotypes.PubKey) bool { + pk2, ok := other.(*PubKey) + if !ok { + return false + } + return m.Key.Equal(&pk2.Key.PublicKey) +} + +// Address implements SDK PubKey interface. +func (m *PubKey) Address() tmcrypto.Address { + return m.Key.Address(m.XXX_MessageName()) +} + +// Type returns key type name. Implements sdk.PubKey interface. +func (m *PubKey) Type() string { + return name +} + +// VerifySignature implements skd.PubKey interface. +func (m *PubKey) VerifySignature(msg []byte, sig []byte) bool { + return m.Key.VerifySignature(msg, sig) +} + +type ecdsaPK struct { + ecdsa.PubKey +} + +// Size implements proto.Marshaler interface +func (pk *ecdsaPK) Size() int { + if pk == nil { + return 0 + } + return fieldSize + 1 +} + +// Unmarshal implements proto.Marshaler interface +func (pk *ecdsaPK) Unmarshal(bz []byte) error { + return pk.PubKey.Unmarshal(bz, secp256r1, fieldSize+1) +} diff --git a/crypto/keys/secp256r1/pubkey_internal_test.go b/crypto/keys/secp256r1/pubkey_internal_test.go new file mode 100644 index 000000000000..01a1cfb5abd6 --- /dev/null +++ b/crypto/keys/secp256r1/pubkey_internal_test.go @@ -0,0 +1,122 @@ +package secp256r1 + +import ( + "encoding/hex" + "testing" + + proto "github.com/gogo/protobuf/proto" + "github.com/stretchr/testify/suite" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" +) + +var _ cryptotypes.PubKey = (*PubKey)(nil) + +func TestPKSuite(t *testing.T) { + suite.Run(t, new(PKSuite)) +} + +type CommonSuite struct { + suite.Suite + pk *PubKey // cryptotypes.PubKey + sk cryptotypes.PrivKey +} + +func (suite *CommonSuite) SetupSuite() { + sk, err := GenPrivKey() + suite.Require().NoError(err) + suite.sk = sk + suite.pk = sk.PubKey().(*PubKey) +} + +type PKSuite struct{ CommonSuite } + +func (suite *PKSuite) TestString() { + assert := suite.Assert() + require := suite.Require() + + pkStr := suite.pk.String() + prefix := "secp256r1{" + require.Len(pkStr, len(prefix)+suite.pk.Key.Size()*2+1) // prefix + hex_len + "}" + assert.Equal(prefix, pkStr[:len(prefix)]) + assert.EqualValues('}', pkStr[len(pkStr)-1]) + + bz, err := hex.DecodeString(pkStr[len(prefix) : len(pkStr)-1]) + require.NoError(err) + assert.EqualValues(suite.pk.Bytes(), bz) +} + +func (suite *PKSuite) TestEquals() { + require := suite.Require() + + skOther, err := GenPrivKey() + require.NoError(err) + pkOther := skOther.PubKey() + pkOther2 := &PubKey{&ecdsaPK{skOther.Secret.PubKey()}} + + require.False(suite.pk.Equals(pkOther)) + require.True(pkOther.Equals(pkOther2)) + require.True(pkOther2.Equals(pkOther)) + require.True(pkOther.Equals(pkOther), "Equals must be reflexive") +} + +func (suite *PKSuite) TestMarshalProto() { + require := suite.Require() + + /**** test structure marshalling ****/ + + var pk PubKey + bz, err := proto.Marshal(suite.pk) + require.NoError(err) + require.NoError(proto.Unmarshal(bz, &pk)) + require.True(pk.Equals(suite.pk)) + + /**** test structure marshalling with codec ****/ + + pk = PubKey{} + registry := types.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(registry) + bz, err = cdc.MarshalBinaryBare(suite.pk) + require.NoError(err) + require.NoError(cdc.UnmarshalBinaryBare(bz, &pk)) + require.True(pk.Equals(suite.pk)) + + const bufSize = 100 + bz2 := make([]byte, bufSize) + pkCpy := suite.pk + _, err = pkCpy.MarshalTo(bz2) + require.NoError(err) + require.Len(bz2, bufSize) + require.Equal(bz, bz2[:pk.Size()]) + + bz2 = make([]byte, bufSize) + _, err = pkCpy.MarshalToSizedBuffer(bz2) + require.NoError(err) + require.Len(bz2, bufSize) + require.Equal(bz, bz2[(bufSize-pk.Size()):]) + + /**** test interface marshalling ****/ + bz, err = cdc.MarshalInterface(suite.pk) + require.NoError(err) + var pkI cryptotypes.PubKey + err = cdc.UnmarshalInterface(bz, &pkI) + require.EqualError(err, "no registered implementations of type types.PubKey") + + RegisterInterfaces(registry) + require.NoError(cdc.UnmarshalInterface(bz, &pkI)) + require.True(pkI.Equals(suite.pk)) + + cdc.UnmarshalInterface(bz, nil) + require.Error(err, "nil should fail") +} + +func (suite *PKSuite) TestSize() { + require := suite.Require() + var pk ecdsaPK + require.Equal(pk.Size(), len(suite.pk.Bytes())) + + var nilPk *ecdsaPK + require.Equal(0, nilPk.Size(), "nil value must have zero size") +} diff --git a/docs/core/proto-docs.md b/docs/core/proto-docs.md index e755dc9f311a..4253153a5226 100644 --- a/docs/core/proto-docs.md +++ b/docs/core/proto-docs.md @@ -3154,7 +3154,7 @@ PubKey defines a secp256r1 ECDSA public key. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `point` | [bytes](#bytes) | | Point on secp256r1 curve in a compressed representation as specified in section 4.3.6 of ANSI X9.62. | +| `key` | [bytes](#bytes) | | Point on secp256r1 curve in a compressed representation as specified in section 4.3.6 of ANSI X9.62. | diff --git a/proto/cosmos/crypto/secp256r1/keys.proto b/proto/cosmos/crypto/secp256r1/keys.proto index edaa76fe5320..d491791f0bf0 100644 --- a/proto/cosmos/crypto/secp256r1/keys.proto +++ b/proto/cosmos/crypto/secp256r1/keys.proto @@ -4,24 +4,19 @@ package cosmos.crypto.secp256r1; import "gogoproto/gogo.proto"; option go_package = "github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1"; +option (gogoproto.messagename_all) = true; +option (gogoproto.goproto_stringer_all) = false; +option (gogoproto.goproto_getters_all) = false; // PubKey defines a secp256r1 ECDSA public key. message PubKey { - option (gogoproto.goproto_stringer) = false; - option (gogoproto.marshaler) = false; - option (gogoproto.goproto_getters) = false; - // Point on secp256r1 curve in a compressed representation as specified in section // 4.3.6 of ANSI X9.62. - bytes point = 1 [(gogoproto.customtype) = "ecdsaPK"]; + bytes key = 1 [(gogoproto.customtype) = "ecdsaPK"]; } // PrivKey defines a secp256r1 ECDSA private key. message PrivKey { - option (gogoproto.goproto_stringer) = false; - option (gogoproto.marshaler) = false; - option (gogoproto.goproto_getters) = false; - // secret number serialized using big-endian encoding - bytes secret = 1; + bytes secret = 1 [(gogoproto.customtype) = "ecdsaSK"]; } From 057c131bf77387d12b9ab524a20997908a559ddd Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 3 Mar 2021 12:11:33 +0100 Subject: [PATCH 57/70] fix err check --- crypto/keys/internal/ecdsa/privkey.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crypto/keys/internal/ecdsa/privkey.go b/crypto/keys/internal/ecdsa/privkey.go index 05299c838cbf..dbae8c8b3e02 100644 --- a/crypto/keys/internal/ecdsa/privkey.go +++ b/crypto/keys/internal/ecdsa/privkey.go @@ -12,7 +12,10 @@ import ( // GenPrivKey generates a new secp256r1 private key. It uses operating system randomness. func GenPrivKey(curve elliptic.Curve) (PrivKey, error) { key, err := ecdsa.GenerateKey(curve, rand.Reader) - return PrivKey{*key}, err + if err != nil { + return PrivKey{}, err + } + return PrivKey{*key}, nil } type PrivKey struct { From 1f3c36c749f647aade00d77e5af889c6d54127c6 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 3 Mar 2021 15:21:08 +0100 Subject: [PATCH 58/70] update comments --- crypto/keys/internal/ecdsa/privkey.go | 12 ++++++------ crypto/keys/internal/ecdsa/pubkey.go | 10 +++++----- crypto/keys/secp256r1/privkey.go | 6 +++--- crypto/keys/secp256r1/pubkey.go | 4 ++-- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/crypto/keys/internal/ecdsa/privkey.go b/crypto/keys/internal/ecdsa/privkey.go index dbae8c8b3e02..0930285b04a1 100644 --- a/crypto/keys/internal/ecdsa/privkey.go +++ b/crypto/keys/internal/ecdsa/privkey.go @@ -22,12 +22,12 @@ type PrivKey struct { ecdsa.PrivateKey } -// PubKey implements Cosmos-SDK PrivKey interface. +// PubKey returns ECDSA public key associated with this private key. func (sk *PrivKey) PubKey() PubKey { return PubKey{sk.PublicKey, nil} } -// Bytes serialize the private key with first byte being the curve type. +// Bytes serialize the private key using big-endian. func (sk *PrivKey) Bytes() []byte { if sk == nil { return nil @@ -38,25 +38,25 @@ func (sk *PrivKey) Bytes() []byte { return bz } -// Sign hashes and signs the message usign ECDSA. Implements sdk.PrivKey interface. +// Sign hashes and signs the message usign ECDSA. Implements SDK PrivKey interface. func (sk *PrivKey) Sign(msg []byte) ([]byte, error) { digest := sha256.Sum256(msg) return sk.PrivateKey.Sign(rand.Reader, digest[:], nil) } -// String implements proto.Message interface. +// String returns a string representation of the public key based on the curveName. func (sk *PrivKey) String(name string) string { return name + "{-}" } -// MarshalTo implements ProtoMarshaler interface. +// MarshalTo implements proto.Marshaler interface. func (sk *PrivKey) MarshalTo(dAtA []byte) (int, error) { bz := sk.Bytes() copy(dAtA, bz) return len(bz), nil } -// Unmarshal implements ProtoMarshaler interface. +// Unmarshal implements proto.Marshaler interface. func (sk *PrivKey) Unmarshal(bz []byte, curve elliptic.Curve, expectedSize int) error { if len(bz) != expectedSize { return fmt.Errorf("wrong ECDSA SK bytes, expecting %d bytes", expectedSize) diff --git a/crypto/keys/internal/ecdsa/pubkey.go b/crypto/keys/internal/ecdsa/pubkey.go index 64adfee63638..4c9b493a6b5f 100644 --- a/crypto/keys/internal/ecdsa/pubkey.go +++ b/crypto/keys/internal/ecdsa/pubkey.go @@ -26,7 +26,7 @@ type PubKey struct { address tmcrypto.Address } -// String implements PubKey interface. +// Address creates an ADR-28 address for ECDSA keys. protoName is a concrete proto structure id. func (pk *PubKey) Address(protoName string) tmcrypto.Address { if pk.address == nil { pk.address = address.Hash(protoName, pk.Bytes()) @@ -43,7 +43,7 @@ func (pk *PubKey) Bytes() []byte { return elliptic.MarshalCompressed(pk.Curve, pk.X, pk.Y) } -// VerifySignature implements skd.PubKey interface. +// VerifySignature checks if sig is a valid ECDSA signature for msg. func (pk *PubKey) VerifySignature(msg []byte, sig []byte) bool { s := new(signature) if _, err := asn1.Unmarshal(sig, s); err != nil || s == nil { @@ -54,21 +54,21 @@ func (pk *PubKey) VerifySignature(msg []byte, sig []byte) bool { return ecdsa.Verify(&pk.PublicKey, h[:], s.R, s.S) } -// String implements proto.Message interface +// String returns a string representation of the public key based on the curveName. func (pk *PubKey) String(curveName string) string { return fmt.Sprintf("%s{%X}", curveName, pk.Bytes()) } // **** Proto Marshaler **** -// MarshalTo implements ProtoMarshaler interface. +// MarshalTo implements proto.Marshaler interface. func (pk *PubKey) MarshalTo(dAtA []byte) (int, error) { bz := pk.Bytes() copy(dAtA, bz) return len(bz), nil } -// Unmarshal implements ProtoMarshaler interface. +// Unmarshal implements proto.Marshaler interface. func (pk *PubKey) Unmarshal(bz []byte, curve elliptic.Curve, expectedSize int) error { if len(bz) != expectedSize { return errors.Wrapf(errors.ErrInvalidPubKey, "wrong ECDSA PK bytes, expecting %d bytes, got %d", expectedSize, len(bz)) diff --git a/crypto/keys/secp256r1/privkey.go b/crypto/keys/secp256r1/privkey.go index c538978cfc07..8ca725420ff8 100644 --- a/crypto/keys/secp256r1/privkey.go +++ b/crypto/keys/secp256r1/privkey.go @@ -11,17 +11,17 @@ func GenPrivKey() (*PrivKey, error) { return &PrivKey{&ecdsaSK{key}}, err } -// PubKey implements Cosmos-SDK PrivKey interface. +// PubKey implements SDK PrivKey interface. func (m *PrivKey) PubKey() cryptotypes.PubKey { return &PubKey{&ecdsaPK{m.Secret.PubKey()}} } -// String implements Cosmos-SDK proto.Message interface. +// String implements SDK proto.Message interface. func (m *PrivKey) String() string { return m.Secret.String(name) } -// Type returns key type name. Implements sdk.PrivKey interface. +// Type returns key type name. Implements SDK PrivKey interface. func (m *PrivKey) Type() string { return name } diff --git a/crypto/keys/secp256r1/pubkey.go b/crypto/keys/secp256r1/pubkey.go index dc1ba06f7e93..a176a445e104 100644 --- a/crypto/keys/secp256r1/pubkey.go +++ b/crypto/keys/secp256r1/pubkey.go @@ -31,12 +31,12 @@ func (m *PubKey) Address() tmcrypto.Address { return m.Key.Address(m.XXX_MessageName()) } -// Type returns key type name. Implements sdk.PubKey interface. +// Type returns key type name. Implements SDK PubKey interface. func (m *PubKey) Type() string { return name } -// VerifySignature implements skd.PubKey interface. +// VerifySignature implements SDK PubKey interface. func (m *PubKey) VerifySignature(msg []byte, sig []byte) bool { return m.Key.VerifySignature(msg, sig) } From 6d0aaf43a8ae63458fe2341b78baa7b3bf713dcb Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 3 Mar 2021 15:23:29 +0100 Subject: [PATCH 59/70] create const for fieldSize+1 --- crypto/keys/secp256r1/init.go | 3 ++- crypto/keys/secp256r1/pubkey.go | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/crypto/keys/secp256r1/init.go b/crypto/keys/secp256r1/init.go index 116ac43e8d5d..eb3b28cdd1f2 100644 --- a/crypto/keys/secp256r1/init.go +++ b/crypto/keys/secp256r1/init.go @@ -12,7 +12,8 @@ import ( const ( // fieldSize is the curve domain size. - fieldSize = 32 + fieldSize = 32 + pubKeySize = fieldSize + 1 name = "secp256r1" ) diff --git a/crypto/keys/secp256r1/pubkey.go b/crypto/keys/secp256r1/pubkey.go index a176a445e104..c844369b057e 100644 --- a/crypto/keys/secp256r1/pubkey.go +++ b/crypto/keys/secp256r1/pubkey.go @@ -50,10 +50,10 @@ func (pk *ecdsaPK) Size() int { if pk == nil { return 0 } - return fieldSize + 1 + return pubKeySize } // Unmarshal implements proto.Marshaler interface func (pk *ecdsaPK) Unmarshal(bz []byte) error { - return pk.PubKey.Unmarshal(bz, secp256r1, fieldSize+1) + return pk.PubKey.Unmarshal(bz, secp256r1, pubKeySize) } From 8522668d5752c9e40e4160d81f4b61bb6e81fdc8 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 3 Mar 2021 15:31:12 +0100 Subject: [PATCH 60/70] simplify the PubKey.String test --- crypto/keys/secp256r1/pubkey_internal_test.go | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/crypto/keys/secp256r1/pubkey_internal_test.go b/crypto/keys/secp256r1/pubkey_internal_test.go index 01a1cfb5abd6..f5d432b8bde8 100644 --- a/crypto/keys/secp256r1/pubkey_internal_test.go +++ b/crypto/keys/secp256r1/pubkey_internal_test.go @@ -1,7 +1,6 @@ package secp256r1 import ( - "encoding/hex" "testing" proto "github.com/gogo/protobuf/proto" @@ -34,18 +33,11 @@ func (suite *CommonSuite) SetupSuite() { type PKSuite struct{ CommonSuite } func (suite *PKSuite) TestString() { - assert := suite.Assert() require := suite.Require() pkStr := suite.pk.String() prefix := "secp256r1{" - require.Len(pkStr, len(prefix)+suite.pk.Key.Size()*2+1) // prefix + hex_len + "}" - assert.Equal(prefix, pkStr[:len(prefix)]) - assert.EqualValues('}', pkStr[len(pkStr)-1]) - - bz, err := hex.DecodeString(pkStr[len(prefix) : len(pkStr)-1]) - require.NoError(err) - assert.EqualValues(suite.pk.Bytes(), bz) + require.Equal(prefix, pkStr[:len(prefix)]) } func (suite *PKSuite) TestEquals() { From e970f527f3dc98cf5d028c25e33c05de444b9cfc Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 3 Mar 2021 20:31:35 +0100 Subject: [PATCH 61/70] Apply suggestions from code review Co-authored-by: Jonathan Gimeno --- crypto/keys/secp256r1/init.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto/keys/secp256r1/init.go b/crypto/keys/secp256r1/init.go index eb3b28cdd1f2..be938dc77f97 100644 --- a/crypto/keys/secp256r1/init.go +++ b/crypto/keys/secp256r1/init.go @@ -1,4 +1,4 @@ -// secp256r1 package implements Cosmos-SDK compatible ECDSA public and private key. The keys +// Package secp256r1 implements Cosmos-SDK compatible ECDSA public and private key. The keys // can be protobuf serialized and packed in Any. package secp256r1 @@ -25,7 +25,7 @@ func init() { // pubKeySize is ceil of field bit size + 1 for the sign expected := (secp256r1.Params().BitSize + 7) / 8 if expected != fieldSize { - panic(fmt.Sprintf("Wrong fieldSize=%d, expecting=%d", fieldSize, expected)) + panic(fmt.Sprintf("Wrong secp256r1 curve fieldSize=%d, expecting=%d", fieldSize, expected)) } } From 01f2b4f5efcd79a452483bcda152db54a8fbfee2 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 3 Mar 2021 20:35:25 +0100 Subject: [PATCH 62/70] Update doc comments: SDK Interface -> sdk.Interface --- crypto/keys/internal/ecdsa/privkey.go | 2 +- crypto/keys/secp256r1/privkey.go | 6 +++--- crypto/keys/secp256r1/pubkey.go | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crypto/keys/internal/ecdsa/privkey.go b/crypto/keys/internal/ecdsa/privkey.go index 0930285b04a1..5d6e84d3b1d9 100644 --- a/crypto/keys/internal/ecdsa/privkey.go +++ b/crypto/keys/internal/ecdsa/privkey.go @@ -38,7 +38,7 @@ func (sk *PrivKey) Bytes() []byte { return bz } -// Sign hashes and signs the message usign ECDSA. Implements SDK PrivKey interface. +// Sign hashes and signs the message usign ECDSA. Implements sdk.PrivKey interface. func (sk *PrivKey) Sign(msg []byte) ([]byte, error) { digest := sha256.Sum256(msg) return sk.PrivateKey.Sign(rand.Reader, digest[:], nil) diff --git a/crypto/keys/secp256r1/privkey.go b/crypto/keys/secp256r1/privkey.go index 8ca725420ff8..bdfcb46a525c 100644 --- a/crypto/keys/secp256r1/privkey.go +++ b/crypto/keys/secp256r1/privkey.go @@ -11,7 +11,7 @@ func GenPrivKey() (*PrivKey, error) { return &PrivKey{&ecdsaSK{key}}, err } -// PubKey implements SDK PrivKey interface. +// PubKey implements sdk.PrivKey interface. func (m *PrivKey) PubKey() cryptotypes.PubKey { return &PubKey{&ecdsaPK{m.Secret.PubKey()}} } @@ -21,7 +21,7 @@ func (m *PrivKey) String() string { return m.Secret.String(name) } -// Type returns key type name. Implements SDK PrivKey interface. +// Type returns key type name. Implements sdk.PrivKey interface. func (m *PrivKey) Type() string { return name } @@ -36,7 +36,7 @@ func (m *PrivKey) Bytes() []byte { return m.Secret.Bytes() } -// Equals implements SDK PrivKey interface. +// Equals implements sdk.PrivKey interface. func (m *PrivKey) Equals(other cryptotypes.LedgerPrivKey) bool { sk2, ok := other.(*PrivKey) if !ok { diff --git a/crypto/keys/secp256r1/pubkey.go b/crypto/keys/secp256r1/pubkey.go index c844369b057e..2668d03c85c2 100644 --- a/crypto/keys/secp256r1/pubkey.go +++ b/crypto/keys/secp256r1/pubkey.go @@ -12,12 +12,12 @@ func (m *PubKey) String() string { return m.Key.String(name) } -// Bytes implements SDK PubKey interface. +// Bytes implements sdk.PubKey interface. func (m *PubKey) Bytes() []byte { return m.Key.Bytes() } -// Equals implements SDK PubKey interface. +// Equals implements sdk.PubKey interface. func (m *PubKey) Equals(other cryptotypes.PubKey) bool { pk2, ok := other.(*PubKey) if !ok { @@ -26,17 +26,17 @@ func (m *PubKey) Equals(other cryptotypes.PubKey) bool { return m.Key.Equal(&pk2.Key.PublicKey) } -// Address implements SDK PubKey interface. +// Address implements sdk.PubKey interface. func (m *PubKey) Address() tmcrypto.Address { return m.Key.Address(m.XXX_MessageName()) } -// Type returns key type name. Implements SDK PubKey interface. +// Type returns key type name. Implements sdk.PubKey interface. func (m *PubKey) Type() string { return name } -// VerifySignature implements SDK PubKey interface. +// VerifySignature implements sdk.PubKey interface. func (m *PubKey) VerifySignature(msg []byte, sig []byte) bool { return m.Key.VerifySignature(msg, sig) } From db18ea9b68797616d54918cdda19f03d791e6979 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 3 Mar 2021 20:37:49 +0100 Subject: [PATCH 63/70] rename init.go to doc.go --- crypto/keys/internal/ecdsa/{init.go => doc.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename crypto/keys/internal/ecdsa/{init.go => doc.go} (100%) diff --git a/crypto/keys/internal/ecdsa/init.go b/crypto/keys/internal/ecdsa/doc.go similarity index 100% rename from crypto/keys/internal/ecdsa/init.go rename to crypto/keys/internal/ecdsa/doc.go From 38f7cf3cbd13b61179eff38351b6c5709de83a9b Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 3 Mar 2021 20:39:23 +0100 Subject: [PATCH 64/70] Add PubKey.Type() test --- crypto/keys/secp256r1/pubkey_internal_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crypto/keys/secp256r1/pubkey_internal_test.go b/crypto/keys/secp256r1/pubkey_internal_test.go index f5d432b8bde8..84b587d0c63b 100644 --- a/crypto/keys/secp256r1/pubkey_internal_test.go +++ b/crypto/keys/secp256r1/pubkey_internal_test.go @@ -40,6 +40,10 @@ func (suite *PKSuite) TestString() { require.Equal(prefix, pkStr[:len(prefix)]) } +func (suite *PKSuite) TestType() { + suite.Require().Equal(name, suite.pk.Type()) +} + func (suite *PKSuite) TestEquals() { require := suite.Require() From 4a93f10d5df4ecbb04df2164147158bc2296d2f7 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 3 Mar 2021 20:49:20 +0100 Subject: [PATCH 65/70] Revert "Update doc comments: SDK Interface -> sdk.Interface" This reverts commit 01f2b4f5efcd79a452483bcda152db54a8fbfee2. --- crypto/keys/internal/ecdsa/privkey.go | 2 +- crypto/keys/secp256r1/privkey.go | 6 +++--- crypto/keys/secp256r1/pubkey.go | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crypto/keys/internal/ecdsa/privkey.go b/crypto/keys/internal/ecdsa/privkey.go index 5d6e84d3b1d9..0930285b04a1 100644 --- a/crypto/keys/internal/ecdsa/privkey.go +++ b/crypto/keys/internal/ecdsa/privkey.go @@ -38,7 +38,7 @@ func (sk *PrivKey) Bytes() []byte { return bz } -// Sign hashes and signs the message usign ECDSA. Implements sdk.PrivKey interface. +// Sign hashes and signs the message usign ECDSA. Implements SDK PrivKey interface. func (sk *PrivKey) Sign(msg []byte) ([]byte, error) { digest := sha256.Sum256(msg) return sk.PrivateKey.Sign(rand.Reader, digest[:], nil) diff --git a/crypto/keys/secp256r1/privkey.go b/crypto/keys/secp256r1/privkey.go index bdfcb46a525c..8ca725420ff8 100644 --- a/crypto/keys/secp256r1/privkey.go +++ b/crypto/keys/secp256r1/privkey.go @@ -11,7 +11,7 @@ func GenPrivKey() (*PrivKey, error) { return &PrivKey{&ecdsaSK{key}}, err } -// PubKey implements sdk.PrivKey interface. +// PubKey implements SDK PrivKey interface. func (m *PrivKey) PubKey() cryptotypes.PubKey { return &PubKey{&ecdsaPK{m.Secret.PubKey()}} } @@ -21,7 +21,7 @@ func (m *PrivKey) String() string { return m.Secret.String(name) } -// Type returns key type name. Implements sdk.PrivKey interface. +// Type returns key type name. Implements SDK PrivKey interface. func (m *PrivKey) Type() string { return name } @@ -36,7 +36,7 @@ func (m *PrivKey) Bytes() []byte { return m.Secret.Bytes() } -// Equals implements sdk.PrivKey interface. +// Equals implements SDK PrivKey interface. func (m *PrivKey) Equals(other cryptotypes.LedgerPrivKey) bool { sk2, ok := other.(*PrivKey) if !ok { diff --git a/crypto/keys/secp256r1/pubkey.go b/crypto/keys/secp256r1/pubkey.go index 2668d03c85c2..c844369b057e 100644 --- a/crypto/keys/secp256r1/pubkey.go +++ b/crypto/keys/secp256r1/pubkey.go @@ -12,12 +12,12 @@ func (m *PubKey) String() string { return m.Key.String(name) } -// Bytes implements sdk.PubKey interface. +// Bytes implements SDK PubKey interface. func (m *PubKey) Bytes() []byte { return m.Key.Bytes() } -// Equals implements sdk.PubKey interface. +// Equals implements SDK PubKey interface. func (m *PubKey) Equals(other cryptotypes.PubKey) bool { pk2, ok := other.(*PubKey) if !ok { @@ -26,17 +26,17 @@ func (m *PubKey) Equals(other cryptotypes.PubKey) bool { return m.Key.Equal(&pk2.Key.PublicKey) } -// Address implements sdk.PubKey interface. +// Address implements SDK PubKey interface. func (m *PubKey) Address() tmcrypto.Address { return m.Key.Address(m.XXX_MessageName()) } -// Type returns key type name. Implements sdk.PubKey interface. +// Type returns key type name. Implements SDK PubKey interface. func (m *PubKey) Type() string { return name } -// VerifySignature implements sdk.PubKey interface. +// VerifySignature implements SDK PubKey interface. func (m *PubKey) VerifySignature(msg []byte, sig []byte) bool { return m.Key.VerifySignature(msg, sig) } From 15b866ae67bdb7ca4872f4089fcab19f9e2e3608 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 3 Mar 2021 20:54:13 +0100 Subject: [PATCH 66/70] Use cryptotypes.Address instead of tmcrypto --- crypto/keys/internal/ecdsa/pubkey.go | 7 +++---- crypto/keys/secp256r1/pubkey.go | 4 +--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/crypto/keys/internal/ecdsa/pubkey.go b/crypto/keys/internal/ecdsa/pubkey.go index 4c9b493a6b5f..4394634a30e9 100644 --- a/crypto/keys/internal/ecdsa/pubkey.go +++ b/crypto/keys/internal/ecdsa/pubkey.go @@ -8,8 +8,7 @@ import ( "fmt" "math/big" - tmcrypto "github.com/tendermint/tendermint/crypto" - + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/types/address" "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -23,11 +22,11 @@ type PubKey struct { ecdsa.PublicKey // cache - address tmcrypto.Address + address cryptotypes.Address } // Address creates an ADR-28 address for ECDSA keys. protoName is a concrete proto structure id. -func (pk *PubKey) Address(protoName string) tmcrypto.Address { +func (pk *PubKey) Address(protoName string) cryptotypes.Address { if pk.address == nil { pk.address = address.Hash(protoName, pk.Bytes()) } diff --git a/crypto/keys/secp256r1/pubkey.go b/crypto/keys/secp256r1/pubkey.go index c844369b057e..10d6c594cf2e 100644 --- a/crypto/keys/secp256r1/pubkey.go +++ b/crypto/keys/secp256r1/pubkey.go @@ -1,8 +1,6 @@ package secp256r1 import ( - tmcrypto "github.com/tendermint/tendermint/crypto" - ecdsa "github.com/cosmos/cosmos-sdk/crypto/keys/internal/ecdsa" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" ) @@ -27,7 +25,7 @@ func (m *PubKey) Equals(other cryptotypes.PubKey) bool { } // Address implements SDK PubKey interface. -func (m *PubKey) Address() tmcrypto.Address { +func (m *PubKey) Address() cryptotypes.Address { return m.Key.Address(m.XXX_MessageName()) } From c9cbbf0f614780fa92b6b561633e7a5c99eb46a5 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 3 Mar 2021 21:10:34 +0100 Subject: [PATCH 67/70] Revert "Use cryptotypes.Address instead of tmcrypto" This reverts commit 15b866ae67bdb7ca4872f4089fcab19f9e2e3608. This issue will be solved in https://github.com/cosmos/cosmos-sdk/issues/8775 --- crypto/keys/internal/ecdsa/pubkey.go | 7 ++++--- crypto/keys/secp256r1/pubkey.go | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/crypto/keys/internal/ecdsa/pubkey.go b/crypto/keys/internal/ecdsa/pubkey.go index 4394634a30e9..4c9b493a6b5f 100644 --- a/crypto/keys/internal/ecdsa/pubkey.go +++ b/crypto/keys/internal/ecdsa/pubkey.go @@ -8,7 +8,8 @@ import ( "fmt" "math/big" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + tmcrypto "github.com/tendermint/tendermint/crypto" + "github.com/cosmos/cosmos-sdk/types/address" "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -22,11 +23,11 @@ type PubKey struct { ecdsa.PublicKey // cache - address cryptotypes.Address + address tmcrypto.Address } // Address creates an ADR-28 address for ECDSA keys. protoName is a concrete proto structure id. -func (pk *PubKey) Address(protoName string) cryptotypes.Address { +func (pk *PubKey) Address(protoName string) tmcrypto.Address { if pk.address == nil { pk.address = address.Hash(protoName, pk.Bytes()) } diff --git a/crypto/keys/secp256r1/pubkey.go b/crypto/keys/secp256r1/pubkey.go index 10d6c594cf2e..c844369b057e 100644 --- a/crypto/keys/secp256r1/pubkey.go +++ b/crypto/keys/secp256r1/pubkey.go @@ -1,6 +1,8 @@ package secp256r1 import ( + tmcrypto "github.com/tendermint/tendermint/crypto" + ecdsa "github.com/cosmos/cosmos-sdk/crypto/keys/internal/ecdsa" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" ) @@ -25,7 +27,7 @@ func (m *PubKey) Equals(other cryptotypes.PubKey) bool { } // Address implements SDK PubKey interface. -func (m *PubKey) Address() cryptotypes.Address { +func (m *PubKey) Address() tmcrypto.Address { return m.Key.Address(m.XXX_MessageName()) } From 52c0f90c7cc24f296902e4601c6ce1d3f872abd4 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Wed, 3 Mar 2021 21:12:55 +0100 Subject: [PATCH 68/70] add link to ANSI X9.62 --- proto/cosmos/crypto/secp256r1/keys.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto/cosmos/crypto/secp256r1/keys.proto b/proto/cosmos/crypto/secp256r1/keys.proto index d491791f0bf0..800b817e9495 100644 --- a/proto/cosmos/crypto/secp256r1/keys.proto +++ b/proto/cosmos/crypto/secp256r1/keys.proto @@ -11,7 +11,7 @@ option (gogoproto.goproto_getters_all) = false; // PubKey defines a secp256r1 ECDSA public key. message PubKey { // Point on secp256r1 curve in a compressed representation as specified in section - // 4.3.6 of ANSI X9.62. + // 4.3.6 of ANSI X9.62: https://webstore.ansi.org/standards/ascx9/ansix9621998 bytes key = 1 [(gogoproto.customtype) = "ecdsaPK"]; } From 3f3f8f93fe5168792427d27e5c9ffab924835c2e Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 4 Mar 2021 12:14:59 +0100 Subject: [PATCH 69/70] move init.go -> doc.go --- crypto/keys/secp256r1/{init.go => doc.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename crypto/keys/secp256r1/{init.go => doc.go} (100%) diff --git a/crypto/keys/secp256r1/init.go b/crypto/keys/secp256r1/doc.go similarity index 100% rename from crypto/keys/secp256r1/init.go rename to crypto/keys/secp256r1/doc.go From 594c186f0b9f26ef4e951175774dacaef8c30284 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 4 Mar 2021 13:16:54 +0100 Subject: [PATCH 70/70] use proto.MessageName() --- crypto/keys/secp256r1/pubkey.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crypto/keys/secp256r1/pubkey.go b/crypto/keys/secp256r1/pubkey.go index c844369b057e..d75c0f5298b7 100644 --- a/crypto/keys/secp256r1/pubkey.go +++ b/crypto/keys/secp256r1/pubkey.go @@ -1,6 +1,7 @@ package secp256r1 import ( + "github.com/gogo/protobuf/proto" tmcrypto "github.com/tendermint/tendermint/crypto" ecdsa "github.com/cosmos/cosmos-sdk/crypto/keys/internal/ecdsa" @@ -28,7 +29,7 @@ func (m *PubKey) Equals(other cryptotypes.PubKey) bool { // Address implements SDK PubKey interface. func (m *PubKey) Address() tmcrypto.Address { - return m.Key.Address(m.XXX_MessageName()) + return m.Key.Address(proto.MessageName(m)) } // Type returns key type name. Implements SDK PubKey interface.