diff --git a/CHANGELOG.md b/CHANGELOG.md index 084c8a8e6502..7a146f35db77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -113,6 +113,7 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i * [#19833](https://github.com/cosmos/cosmos-sdk/pull/19833) Fix some places in which we call Remove inside a Walk. * [#19851](https://github.com/cosmos/cosmos-sdk/pull/19851) Fix some places in which we call Remove inside a Walk (x/staking and x/gov). * (baseapp) [#19970](https://github.com/cosmos/cosmos-sdk/pull/19970) Fix default config values to use no-op mempool as default. +* (crypto) [#20027](https://github.com/cosmos/cosmos-sdk/pull/20027) secp256r1 keys now implement gogoproto's customtype interface. * (x/bank) [#20028](https://github.com/cosmos/cosmos-sdk/pull/20028) Align query with multi denoms for send-enabled. ### API Breaking Changes diff --git a/crypto/keys/secp256r1/privkey.go b/crypto/keys/secp256r1/privkey.go index 0e8ef46ca310..463a7c063c8d 100644 --- a/crypto/keys/secp256r1/privkey.go +++ b/crypto/keys/secp256r1/privkey.go @@ -1,10 +1,14 @@ package secp256r1 import ( + "encoding/base64" + "github.com/cosmos/cosmos-sdk/crypto/keys/internal/ecdsa" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" ) +var _ customProtobufType = (*ecdsaSK)(nil) + // GenPrivKey generates a new secp256r1 private key. It uses operating system randomness. func GenPrivKey() (*PrivKey, error) { key, err := ecdsa.GenPrivKey(secp256r1) @@ -52,6 +56,27 @@ type ecdsaSK struct { ecdsa.PrivKey } +// Marshal implements customProtobufType. +func (sk ecdsaSK) Marshal() ([]byte, error) { + return sk.PrivKey.Bytes(), nil +} + +// MarshalJSON implements customProtobufType. +func (sk ecdsaSK) MarshalJSON() ([]byte, error) { + b64 := base64.StdEncoding.EncodeToString(sk.PrivKey.Bytes()) + return []byte(b64), nil +} + +// UnmarshalJSON implements customProtobufType. +func (sk *ecdsaSK) UnmarshalJSON(data []byte) error { + bz, err := base64.StdEncoding.DecodeString(string(data)) + if err != nil { + return err + } + + return sk.PrivKey.Unmarshal(bz, secp256r1, fieldSize) +} + // Size implements proto.Marshaler interface func (sk *ecdsaSK) Size() int { if sk == nil { diff --git a/crypto/keys/secp256r1/privkey_internal_test.go b/crypto/keys/secp256r1/privkey_internal_test.go index 902ee6dafbf8..52ea3239dac6 100644 --- a/crypto/keys/secp256r1/privkey_internal_test.go +++ b/crypto/keys/secp256r1/privkey_internal_test.go @@ -113,3 +113,14 @@ func (suite *SKSuite) TestSize() { var nilPk *ecdsaSK require.Equal(0, nilPk.Size(), "nil value must have zero size") } + +func (suite *SKSuite) TestJson() { + require := suite.Require() + asd := suite.sk.(*PrivKey) + bz, err := asd.Secret.MarshalJSON() + require.NoError(err) + + sk := &ecdsaSK{} + require.NoError(sk.UnmarshalJSON(bz)) + require.Equal(suite.sk.(*PrivKey).Secret, sk) +} diff --git a/crypto/keys/secp256r1/pubkey.go b/crypto/keys/secp256r1/pubkey.go index cacec514c3d7..c0d4cfc956b8 100644 --- a/crypto/keys/secp256r1/pubkey.go +++ b/crypto/keys/secp256r1/pubkey.go @@ -1,6 +1,8 @@ package secp256r1 import ( + "encoding/base64" + cmtcrypto "github.com/cometbft/cometbft/crypto" "github.com/cosmos/gogoproto/proto" @@ -8,6 +10,20 @@ import ( cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" ) +// customProtobufType is here to make sure that ecdsaPK and ecdsaSK implement the +// gogoproto customtype interface. +type customProtobufType interface { + Marshal() ([]byte, error) + MarshalTo(data []byte) (n int, err error) + Unmarshal(data []byte) error + Size() int + + MarshalJSON() ([]byte, error) + UnmarshalJSON(data []byte) error +} + +var _ customProtobufType = (*ecdsaPK)(nil) + // String implements proto.Message interface. func (m *PubKey) String() string { return m.Key.String(name) @@ -49,6 +65,27 @@ type ecdsaPK struct { ecdsa.PubKey } +// Marshal implements customProtobufType. +func (pk ecdsaPK) Marshal() ([]byte, error) { + return pk.PubKey.Bytes(), nil +} + +// MarshalJSON implements customProtobufType. +func (pk ecdsaPK) MarshalJSON() ([]byte, error) { + b64 := base64.StdEncoding.EncodeToString(pk.PubKey.Bytes()) + return []byte(b64), nil +} + +// UnmarshalJSON implements customProtobufType. +func (pk *ecdsaPK) UnmarshalJSON(data []byte) error { + bz, err := base64.StdEncoding.DecodeString(string(data)) + if err != nil { + return err + } + + return pk.PubKey.Unmarshal(bz, secp256r1, pubKeySize) +} + // Size implements proto.Marshaler interface func (pk *ecdsaPK) Size() int { if pk == nil { diff --git a/crypto/keys/secp256r1/pubkey_internal_test.go b/crypto/keys/secp256r1/pubkey_internal_test.go index d3d2ed3823eb..77f4a66e5114 100644 --- a/crypto/keys/secp256r1/pubkey_internal_test.go +++ b/crypto/keys/secp256r1/pubkey_internal_test.go @@ -126,3 +126,14 @@ func (suite *PKSuite) TestSize() { var nilPk *ecdsaPK require.Equal(0, nilPk.Size(), "nil value must have zero size") } + +func (suite *PKSuite) TestJson() { + require := suite.Require() + + bz, err := suite.pk.Key.MarshalJSON() + require.NoError(err) + + pk := &ecdsaPK{} + require.NoError(pk.UnmarshalJSON(bz)) + require.Equal(suite.pk.Key, pk) +}