diff --git a/crypto/types/codec.go b/crypto/types/codec.go new file mode 100644 index 000000000..2796d7174 --- /dev/null +++ b/crypto/types/codec.go @@ -0,0 +1,15 @@ +package types + +import ( + "github.com/tendermint/tendermint/crypto" +) + +// PublicKeyCodec defines a type which can encode and decode crypto.PubKey's +// to and from protobuf PublicKey's +type PublicKeyCodec interface { + // Encode encodes the crypto.PubKey as a protobuf PublicKey or returns an error + Encode(key crypto.PubKey) (*PublicKey, error) + + // Decode decodes a crypto.PubKey from a protobuf PublicKey or returns an error + Decode(key *PublicKey) (crypto.PubKey, error) +} diff --git a/go.sum b/go.sum index 3bae58262..f3859f336 100644 --- a/go.sum +++ b/go.sum @@ -78,7 +78,6 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/confio/ics23 v0.6.0 h1:bQsi55t2+xjW6EWDl83IBF1VWurplbUu+OT6pukeiEo= github.com/confio/ics23-iavl v0.6.0 h1:vVRCuVaP38FCw1kTeEdFuGuiY+2vAGTBQoH7Zxkq/ws= github.com/confio/ics23-iavl v0.6.0/go.mod h1:mmXAxD1vWoO0VP8YHu6mM1QHGv71NQqa1iSVm4HeKcY= github.com/confio/ics23/go v0.0.0-20200323120010-7d9a00f0a2fa/go.mod h1:W1I3XC8d9N8OTu/ct5VJ84ylcOunZwMXsWkd27nvVts= @@ -467,8 +466,6 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.0 h1:jlIyCplCJFULU/01vCkhKuTyc3OorI3bJFuw6obfgho= -github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= diff --git a/std/pubkey.go b/std/pubkey.go new file mode 100644 index 000000000..0c86f1548 --- /dev/null +++ b/std/pubkey.go @@ -0,0 +1,90 @@ +package std + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/crypto/types/multisig" + + "github.com/tendermint/tendermint/crypto" + ed255192 "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/tendermint/tendermint/crypto/secp256k1" + "github.com/tendermint/tendermint/crypto/sr25519" +) + +// DefaultPublicKeyCodec implements the standard PublicKeyCodec for the SDK which +// supports a standard set of public key types +type DefaultPublicKeyCodec struct{} + +var _ types.PublicKeyCodec = DefaultPublicKeyCodec{} + +// Decode implements the PublicKeyCodec.Decode method +func (cdc DefaultPublicKeyCodec) Decode(key *types.PublicKey) (crypto.PubKey, error) { + switch key := key.Sum.(type) { + case *types.PublicKey_Secp256K1: + n := len(key.Secp256K1) + if n != secp256k1.PubKeySecp256k1Size { + return nil, fmt.Errorf("wrong length %d for secp256k1 public key", n) + } + var res secp256k1.PubKeySecp256k1 + copy(res[:], key.Secp256K1) + return res, nil + case *types.PublicKey_Ed25519: + n := len(key.Ed25519) + if n != ed255192.PubKeyEd25519Size { + return nil, fmt.Errorf("wrong length %d for ed25519 public key", n) + } + var res ed255192.PubKeyEd25519 + copy(res[:], key.Ed25519) + return res, nil + case *types.PublicKey_Sr25519: + n := len(key.Sr25519) + if n != sr25519.PubKeySr25519Size { + return nil, fmt.Errorf("wrong length %d for sr25519 public key", n) + } + var res sr25519.PubKeySr25519 + copy(res[:], key.Sr25519) + return res, nil + case *types.PublicKey_Multisig: + pubKeys := key.Multisig.PubKeys + resKeys := make([]crypto.PubKey, len(pubKeys)) + for i, k := range pubKeys { + dk, err := cdc.Decode(k) + if err != nil { + return nil, err + } + resKeys[i] = dk + } + return multisig.NewPubKeyMultisigThreshold(int(key.Multisig.K), resKeys), nil + default: + return nil, fmt.Errorf("can't decode PubKey of type %T. Use a custom PublicKeyCodec instead", key) + } +} + +// Encode implements the PublicKeyCodec.Encode method +func (cdc DefaultPublicKeyCodec) Encode(key crypto.PubKey) (*types.PublicKey, error) { + switch key := key.(type) { + case secp256k1.PubKeySecp256k1: + return &types.PublicKey{Sum: &types.PublicKey_Secp256K1{Secp256K1: key[:]}}, nil + case ed255192.PubKeyEd25519: + return &types.PublicKey{Sum: &types.PublicKey_Ed25519{Ed25519: key[:]}}, nil + case sr25519.PubKeySr25519: + return &types.PublicKey{Sum: &types.PublicKey_Sr25519{Sr25519: key[:]}}, nil + case multisig.PubKeyMultisigThreshold: + pubKeys := key.PubKeys + resKeys := make([]*types.PublicKey, len(pubKeys)) + for i, k := range pubKeys { + dk, err := cdc.Encode(k) + if err != nil { + return nil, err + } + resKeys[i] = dk + } + return &types.PublicKey{Sum: &types.PublicKey_Multisig{Multisig: &types.PubKeyMultisigThreshold{ + K: uint32(key.K), + PubKeys: resKeys, + }}}, nil + default: + return nil, fmt.Errorf("can't encode PubKey of type %T. Use a custom PublicKeyCodec instead", key) + } +} diff --git a/std/pubkey_test.go b/std/pubkey_test.go new file mode 100644 index 000000000..22397a4b7 --- /dev/null +++ b/std/pubkey_test.go @@ -0,0 +1,41 @@ +package std_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/std" + + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/tendermint/tendermint/crypto/secp256k1" + "github.com/tendermint/tendermint/crypto/sr25519" + + "github.com/cosmos/cosmos-sdk/crypto/types/multisig" +) + +func roundTripTest(t *testing.T, pubKey crypto.PubKey) { + cdc := std.DefaultPublicKeyCodec{} + + pubKeyEnc, err := cdc.Encode(pubKey) + require.NoError(t, err) + pubKeyDec, err := cdc.Decode(pubKeyEnc) + require.NoError(t, err) + require.Equal(t, pubKey, pubKeyDec) +} + +func TestDefaultPublicKeyCodec(t *testing.T) { + pubKeySecp256k1 := secp256k1.GenPrivKey().PubKey() + roundTripTest(t, pubKeySecp256k1) + + pubKeyEd25519 := ed25519.GenPrivKey().PubKey() + roundTripTest(t, pubKeyEd25519) + + pubKeySr25519 := sr25519.GenPrivKey().PubKey() + roundTripTest(t, pubKeySr25519) + + pubKeyMultisig := multisig.NewPubKeyMultisigThreshold(2, []crypto.PubKey{ + pubKeySecp256k1, pubKeyEd25519, pubKeySr25519, + }) + roundTripTest(t, pubKeyMultisig) +}