From 1572b8e0c3fccfae10b64cdd7c9c6f3b8eea9df2 Mon Sep 17 00:00:00 2001 From: Shreyans Tatiya <118096592+Percobain@users.noreply.github.com> Date: Wed, 16 Jul 2025 20:45:54 +0530 Subject: [PATCH] feat: Add NewPubKeyFromBytes for secp256r1 to create PubKey from bytes (#24919) Co-authored-by: Alex | Interchain Labs --- CHANGELOG.md | 1 + crypto/keys/secp256r1/pubkey.go | 18 +++++++++++++++ crypto/keys/secp256r1/pubkey_internal_test.go | 22 +++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a36289a0d7..3e87afb19f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features +* (crypto) [#24919](https://github.com/cosmos/cosmos-sdk/pull/24919) add `NewPubKeyFromBytes` function to the `secp256r1` package to create `PubKey` from bytes * (server) [#24720](https://github.com/cosmos/cosmos-sdk/pull/24720) add `verbose_log_level` flag for configuring the log level when switching to verbose logging mode during sensitive operations (such as chain upgrades). * (crypto) [#24861](https://github.com/cosmos/cosmos-sdk/pull/24861) add `PubKeyFromCometTypeAndBytes` helper function to convert from `comet/v2` PubKeys to the `cryptotypes.Pubkey` interface. diff --git a/crypto/keys/secp256r1/pubkey.go b/crypto/keys/secp256r1/pubkey.go index bc8bb5dfb5..8890e30d7a 100644 --- a/crypto/keys/secp256r1/pubkey.go +++ b/crypto/keys/secp256r1/pubkey.go @@ -6,8 +6,11 @@ import ( cmtcrypto "github.com/cometbft/cometbft/v2/crypto" "github.com/cosmos/gogoproto/proto" + errorsmod "cosmossdk.io/errors" + ecdsa "github.com/cosmos/cosmos-sdk/crypto/keys/internal/ecdsa" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/types/errors" ) // customProtobufType is here to make sure that ecdsaPK and ecdsaSK implement the @@ -99,3 +102,18 @@ func (pk *ecdsaPK) Size() int { func (pk *ecdsaPK) Unmarshal(bz []byte) error { return pk.PubKey.Unmarshal(bz, secp256r1, pubKeySize) } + +// NewPubKeyFromBytes creates a secp256r1 PubKey from bytes. +func NewPubKeyFromBytes(bytes []byte) (*PubKey, error) { + if len(bytes) != pubKeySize { + return nil, errorsmod.Wrapf(errors.ErrInvalidPubKey, + "wrong secp256r1 pubkey size, expecting %d bytes, got %d", + pubKeySize, len(bytes)) + } + pk := &ecdsaPK{} + err := pk.Unmarshal(bytes) + if err != nil { + return nil, errorsmod.Wrap(errors.ErrInvalidPubKey, err.Error()) + } + return &PubKey{Key: pk}, nil +} diff --git a/crypto/keys/secp256r1/pubkey_internal_test.go b/crypto/keys/secp256r1/pubkey_internal_test.go index 77f4a66e51..e9c2f8b3c4 100644 --- a/crypto/keys/secp256r1/pubkey_internal_test.go +++ b/crypto/keys/secp256r1/pubkey_internal_test.go @@ -137,3 +137,25 @@ func (suite *PKSuite) TestJson() { require.NoError(pk.UnmarshalJSON(bz)) require.Equal(suite.pk.Key, pk) } + +func (suite *PKSuite) TestNewPubKeyFromBytes() { + require := suite.Require() + + originalBytes := suite.pk.Bytes() + newPk, err := NewPubKeyFromBytes(originalBytes) + require.NoError(err) + require.NotNil(newPk) + require.True(newPk.Equals(suite.pk)) + require.Equal(originalBytes, newPk.Bytes()) + + _, err = NewPubKeyFromBytes([]byte{1, 2, 3}) + require.Error(err) + + _, err = NewPubKeyFromBytes(nil) + require.Error(err) + + invalidBytes := make([]byte, pubKeySize) + invalidBytes[0] = 0x04 + _, err = NewPubKeyFromBytes(invalidBytes) + require.Error(err) +}