From deef5eb90c1dec9b598455f7fcd1086e0e8ecb72 Mon Sep 17 00:00:00 2001 From: Andrew Gouin Date: Tue, 11 Apr 2023 16:12:30 -0600 Subject: [PATCH] Add sr25519 support (#1120) * Migrate to cometbft * Additional replaces * Register comet proto types * Add sr25519 support * bump ictest * Add keys test * Update supported algos comment --- cmd/keys.go | 42 ++- cregistry/chain_info.go | 32 +- go.mod | 2 +- interchaintest/go.mod | 16 +- interchaintest/go.sum | 32 +- interchaintest/relayer.go | 8 +- proto/cosmos/crypto/sr25519/keys.proto | 20 ++ relayer/chain.go | 4 +- relayer/chains/cosmos/keys.go | 30 +- relayer/chains/cosmos/keys/sr25519/algo.go | 46 +++ relayer/chains/cosmos/keys/sr25519/keys.pb.go | 320 ++++++++++++++++++ relayer/chains/cosmos/keys/sr25519/privkey.go | 47 +++ relayer/chains/cosmos/keys/sr25519/pubkey.go | 38 +++ relayer/chains/cosmos/keys_test.go | 104 ++++++ relayer/chains/cosmos/provider.go | 41 +-- relayer/chains/mock/mock_chain_processor.go | 3 +- relayer/chains/penumbra/keys.go | 4 +- relayer/provider/provider.go | 6 +- 18 files changed, 710 insertions(+), 85 deletions(-) create mode 100644 proto/cosmos/crypto/sr25519/keys.proto create mode 100644 relayer/chains/cosmos/keys/sr25519/algo.go create mode 100644 relayer/chains/cosmos/keys/sr25519/keys.pb.go create mode 100644 relayer/chains/cosmos/keys/sr25519/privkey.go create mode 100644 relayer/chains/cosmos/keys/sr25519/pubkey.go create mode 100644 relayer/chains/cosmos/keys_test.go diff --git a/cmd/keys.go b/cmd/keys.go index 9148946b5..aa915d065 100644 --- a/cmd/keys.go +++ b/cmd/keys.go @@ -22,6 +22,7 @@ import ( "io" "strings" + "github.com/cosmos/cosmos-sdk/crypto/hd" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/relayer/v2/relayer/chains/cosmos" "github.com/spf13/cobra" @@ -30,6 +31,7 @@ import ( const ( flagCoinType = "coin-type" + flagAlgo = "signing-algorithm" defaultCoinType uint32 = sdk.CoinType ) @@ -75,7 +77,9 @@ $ %s k a cosmoshub testkey`, appName, appName, appName)), return errKeyExists(keyName) } - coinType, err := cmd.Flags().GetInt32(flagCoinType) + cmdFlags := cmd.Flags() + + coinType, err := cmdFlags.GetInt32(flagCoinType) if err != nil { return err } @@ -88,7 +92,20 @@ $ %s k a cosmoshub testkey`, appName, appName, appName)), } } - ko, err := chain.ChainProvider.AddKey(keyName, uint32(coinType)) + algo, err := cmdFlags.GetString(flagAlgo) + if err != nil { + return err + } + + if algo == "" { + if ccp, ok := chain.ChainProvider.(*cosmos.CosmosProvider); ok { + algo = ccp.PCfg.SigningAlgorithm + } else { + algo = string(hd.Secp256k1Type) + } + } + + ko, err := chain.ChainProvider.AddKey(keyName, uint32(coinType), algo) if err != nil { return fmt.Errorf("failed to add key: %w", err) } @@ -103,6 +120,7 @@ $ %s k a cosmoshub testkey`, appName, appName, appName)), }, } cmd.Flags().Int32(flagCoinType, -1, "coin type number for HD derivation") + cmd.Flags().String(flagAlgo, "", "signing algorithm for key (secp256k1, sr25519)") return cmd } @@ -129,7 +147,9 @@ $ %s k r cosmoshub faucet-key "[mnemonic-words]"`, appName, appName)), return errKeyExists(keyName) } - coinType, err := cmd.Flags().GetInt32(flagCoinType) + cmdFlags := cmd.Flags() + + coinType, err := cmdFlags.GetInt32(flagCoinType) if err != nil { return err } @@ -142,7 +162,20 @@ $ %s k r cosmoshub faucet-key "[mnemonic-words]"`, appName, appName)), } } - address, err := chain.ChainProvider.RestoreKey(keyName, args[2], uint32(coinType)) + algo, err := cmdFlags.GetString(flagAlgo) + if err != nil { + return err + } + + if algo == "" { + if ccp, ok := chain.ChainProvider.(*cosmos.CosmosProvider); ok { + algo = ccp.PCfg.SigningAlgorithm + } else { + algo = string(hd.Secp256k1Type) + } + } + + address, err := chain.ChainProvider.RestoreKey(keyName, args[2], uint32(coinType), algo) if err != nil { return err } @@ -152,6 +185,7 @@ $ %s k r cosmoshub faucet-key "[mnemonic-words]"`, appName, appName)), }, } cmd.Flags().Int32(flagCoinType, -1, "coin type number for HD derivation") + cmd.Flags().String(flagAlgo, "", "signing algorithm for key (secp256k1, sr25519)") return cmd } diff --git a/cregistry/chain_info.go b/cregistry/chain_info.go index 978142f70..509b13271 100644 --- a/cregistry/chain_info.go +++ b/cregistry/chain_info.go @@ -55,8 +55,9 @@ type ChainInfo struct { Genesis struct { GenesisURL string `json:"genesis_url"` } `json:"genesis"` - Slip44 *int `json:"slip44"` - Codebase struct { + Slip44 *int `json:"slip44"` + SigningAlgorithm string `json:"signing-algorithm"` + Codebase struct { GitRepo string `json:"git_repo"` RecommendedVersion string `json:"recommended_version"` CompatibleVersions []string `json:"compatible_versions"` @@ -251,18 +252,19 @@ func (c ChainInfo) GetChainConfig(ctx context.Context) (*cosmos.CosmosProviderCo } return &cosmos.CosmosProviderConfig{ - Key: "default", - ChainID: c.ChainID, - RPCAddr: rpc, - AccountPrefix: c.Bech32Prefix, - KeyringBackend: "test", - GasAdjustment: 1.2, - GasPrices: gasPrices, - KeyDirectory: home, - Debug: debug, - Timeout: "20s", - OutputFormat: "json", - SignModeStr: "direct", - Slip44: c.Slip44, + Key: "default", + ChainID: c.ChainID, + RPCAddr: rpc, + AccountPrefix: c.Bech32Prefix, + KeyringBackend: "test", + GasAdjustment: 1.2, + GasPrices: gasPrices, + KeyDirectory: home, + Debug: debug, + Timeout: "20s", + OutputFormat: "json", + SignModeStr: "direct", + Slip44: c.Slip44, + SigningAlgorithm: c.SigningAlgorithm, }, nil } diff --git a/go.mod b/go.mod index a452df9fe..ab961467d 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,6 @@ require ( golang.org/x/term v0.6.0 golang.org/x/text v0.8.0 google.golang.org/grpc v1.53.0 - google.golang.org/protobuf v1.29.1 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -176,6 +175,7 @@ require ( google.golang.org/api v0.110.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44 // indirect + google.golang.org/protobuf v1.29.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect nhooyr.io/websocket v1.8.6 // indirect pgregory.net/rapid v0.5.5 // indirect diff --git a/interchaintest/go.mod b/interchaintest/go.mod index 66f66cf4e..58fc82bef 100644 --- a/interchaintest/go.mod +++ b/interchaintest/go.mod @@ -5,13 +5,13 @@ go 1.20 require ( cosmossdk.io/simapp v0.0.0-20230224204036-a6adb0821462 github.com/cometbft/cometbft v0.37.0 - github.com/cosmos/cosmos-sdk v0.47.0 + github.com/cosmos/cosmos-sdk v0.47.1 github.com/cosmos/ibc-go/v7 v7.0.0 github.com/cosmos/relayer/v2 v2.0.0 github.com/docker/docker v20.10.24+incompatible github.com/icza/dyno v0.0.0-20220812133438-f0b6f8a18845 github.com/moby/moby v20.10.22+incompatible - github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20230324180345-a06599d2eb8c + github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20230405184655-2e6d60073e71 github.com/stretchr/testify v1.8.2 go.uber.org/zap v1.24.0 golang.org/x/sync v0.1.0 @@ -27,11 +27,11 @@ require ( cosmossdk.io/core v0.5.1 // indirect cosmossdk.io/depinject v1.0.0-alpha.3 // indirect cosmossdk.io/errors v1.0.0-beta.7 // indirect - cosmossdk.io/math v1.0.0-rc.0 // indirect + cosmossdk.io/math v1.0.0 // indirect cosmossdk.io/tools/rosetta v0.2.1 // indirect filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect - github.com/99designs/keyring v1.2.1 // indirect + github.com/99designs/keyring v1.2.2 // indirect github.com/BurntSushi/toml v1.2.1 // indirect github.com/ChainSafe/go-schnorrkel v1.0.0 // indirect github.com/ChainSafe/go-schnorrkel/1 v0.0.0-00010101000000-000000000000 // indirect @@ -50,7 +50,7 @@ require ( github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce // indirect github.com/cenkalti/backoff/v4 v4.1.3 // indirect - github.com/centrifuge/go-substrate-rpc-client/v4 v4.0.10 // indirect + github.com/centrifuge/go-substrate-rpc-client/v4 v4.0.12 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chzyer/readline v1.5.1 // indirect @@ -211,7 +211,7 @@ require ( go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.8.0 // indirect golang.org/x/crypto v0.7.0 // indirect - golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0 // indirect + golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect golang.org/x/mod v0.9.0 // indirect golang.org/x/net v0.8.0 // indirect golang.org/x/oauth2 v0.5.0 // indirect @@ -223,7 +223,7 @@ require ( google.golang.org/api v0.110.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44 // indirect - google.golang.org/grpc v1.53.0 // indirect + google.golang.org/grpc v1.54.0 // indirect google.golang.org/protobuf v1.29.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect @@ -237,7 +237,7 @@ require ( modernc.org/mathutil v1.5.0 // indirect modernc.org/memory v1.5.0 // indirect modernc.org/opt v0.1.3 // indirect - modernc.org/sqlite v1.21.0 // indirect + modernc.org/sqlite v1.21.1 // indirect modernc.org/strutil v1.1.3 // indirect modernc.org/token v1.0.1 // indirect nhooyr.io/websocket v1.8.6 // indirect diff --git a/interchaintest/go.sum b/interchaintest/go.sum index 656c273e9..f64f4e541 100644 --- a/interchaintest/go.sum +++ b/interchaintest/go.sum @@ -197,8 +197,8 @@ cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z cosmossdk.io/depinject v1.0.0-alpha.3/go.mod h1:eRbcdQ7MRpIPEM5YUJh8k97nxHpYbc3sMUnEtt8HPWU= cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w= cosmossdk.io/errors v1.0.0-beta.7/go.mod h1:mz6FQMJRku4bY7aqS/Gwfcmr/ue91roMEKAmDUDpBfE= -cosmossdk.io/math v1.0.0-rc.0 h1:ml46ukocrAAoBpYKMidF0R2tQJ1Uxfns0yH8wqgMAFc= -cosmossdk.io/math v1.0.0-rc.0/go.mod h1:Ygz4wBHrgc7g0N+8+MrnTfS9LLn9aaTGa9hKopuym5k= +cosmossdk.io/math v1.0.0 h1:ro9w7eKx23om2tZz/VM2Pf+z2WAbGX1yDQQOJ6iGeJw= +cosmossdk.io/math v1.0.0/go.mod h1:Ygz4wBHrgc7g0N+8+MrnTfS9LLn9aaTGa9hKopuym5k= cosmossdk.io/simapp v0.0.0-20230224204036-a6adb0821462 h1:g8muUHnXL8vhld2Sjilyhb1UQObc+x9GVuDK43TYZns= cosmossdk.io/simapp v0.0.0-20230224204036-a6adb0821462/go.mod h1:4Dd3NLoLYoN90kZ0uyHoTHzVVk9+J0v4HhZRBNTAq2c= cosmossdk.io/tools/rosetta v0.2.1 h1:ddOMatOH+pbxWbrGJKRAawdBkPYLfKXutK9IETnjYxw= @@ -208,8 +208,8 @@ filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= -github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo87o= -github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= +github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0= +github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= @@ -348,8 +348,8 @@ github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInq github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/centrifuge/go-substrate-rpc-client/v4 v4.0.10 h1:HW3XP9G3mXr0gYPfxCAQLD29u+Ys0uIeotv9RWfnhrM= -github.com/centrifuge/go-substrate-rpc-client/v4 v4.0.10/go.mod h1:5g1oM4Zu3BOaLpsKQ+O8PAv2kNuq+kPcA1VzFbsSqxE= +github.com/centrifuge/go-substrate-rpc-client/v4 v4.0.12 h1:DCYWIBOalB0mKKfUg2HhtGgIkBbMA1fnlnkZp7fHB18= +github.com/centrifuge/go-substrate-rpc-client/v4 v4.0.12/go.mod h1:5g1oM4Zu3BOaLpsKQ+O8PAv2kNuq+kPcA1VzFbsSqxE= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -510,8 +510,8 @@ github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis= github.com/cosmos/cosmos-proto v1.0.0-beta.2 h1:X3OKvWgK9Gsejo0F1qs5l8Qn6xJV/AzgIWR2wZ8Nua8= github.com/cosmos/cosmos-proto v1.0.0-beta.2/go.mod h1:+XRCLJ14pr5HFEHIUcn51IKXD1Fy3rkEQqt4WqmN4V0= -github.com/cosmos/cosmos-sdk v0.47.0 h1:GKYtBpvjwuDEVix1vdnQpq7PuEOnItuEK0vdAL2cZ5g= -github.com/cosmos/cosmos-sdk v0.47.0/go.mod h1:FTtZbqiHCZ2vun9WrPq6qLQafNKkAuIhLAxzLjr2TiI= +github.com/cosmos/cosmos-sdk v0.47.1 h1:HnaCYtaAMWZp1SdlwwE1mPJ8kFlZ/TuEJ/ciNXH6Uno= +github.com/cosmos/cosmos-sdk v0.47.1/go.mod h1:14tO5KQaTrl2q3OxBnDRfue7TRN9zkXS0cLutrSqkOo= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= @@ -1370,8 +1370,8 @@ github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jH github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= github.com/strangelove-ventures/go-subkey v1.0.7 h1:cOP/Lajg3uxV/tvspu0m6+0Cu+DJgygkEAbx/s+f35I= github.com/strangelove-ventures/go-subkey v1.0.7/go.mod h1:E34izOIEm+sZ1YmYawYRquqBQWeZBjVB4pF7bMuhc1c= -github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20230324180345-a06599d2eb8c h1:vGl7skxBHHW5qE88Dc9q+ZOxwJJIYDNjqmQTPHiPUF0= -github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20230324180345-a06599d2eb8c/go.mod h1:/pjBA7gAa1AuMphaLp8joBjVOAHqewe8UenyQ45sh9M= +github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20230405184655-2e6d60073e71 h1:bbhg6Iol/5UR65+4kPaki+3mNUgyvcQe+ZHrleorKKY= +github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20230405184655-2e6d60073e71/go.mod h1:tkBlI3o0Z1jgkZIkckOLIHJuR+S0LbGoBEGg4NQ4Aa8= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= @@ -1528,8 +1528,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0 h1:LGJsf5LRplCck6jUCH3dBL2dmycNruWNF5xugkSlfXw= -golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -2122,8 +2122,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= +google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -2245,8 +2245,8 @@ modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.21.0 h1:4aP4MdUf15i3R3M2mx6Q90WHKz3nZLoz96zlB6tNdow= -modernc.org/sqlite v1.21.0/go.mod h1:XwQ0wZPIh1iKb5mkvCJ3szzbhk+tykC8ZWqTRTgYRwI= +modernc.org/sqlite v1.21.1 h1:GyDFqNnESLOhwwDRaHGdp2jKLDzpyT/rNLglX3ZkMSU= +modernc.org/sqlite v1.21.1/go.mod h1:XwQ0wZPIh1iKb5mkvCJ3szzbhk+tykC8ZWqTRTgYRwI= modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= modernc.org/tcl v1.15.1 h1:mOQwiEK4p7HruMZcwKTZPw/aqtGM4aY00uzWhlKKYws= diff --git a/interchaintest/relayer.go b/interchaintest/relayer.go index ded1c97ec..a57c2add3 100644 --- a/interchaintest/relayer.go +++ b/interchaintest/relayer.go @@ -85,8 +85,8 @@ func (r *Relayer) AddChainConfiguration(ctx context.Context, _ ibc.RelayerExecRe return nil } -func (r *Relayer) AddKey(ctx context.Context, _ ibc.RelayerExecReporter, chainID, keyName string, coinType string) (ibc.Wallet, error) { - res := r.sys().RunC(ctx, r.log(), "keys", "add", chainID, keyName, "--coin-type", coinType) +func (r *Relayer) AddKey(ctx context.Context, _ ibc.RelayerExecReporter, chainID, keyName, coinType, signingAlgorithm string) (ibc.Wallet, error) { + res := r.sys().RunC(ctx, r.log(), "keys", "add", chainID, keyName, "--coin-type", coinType, "--signing-algorithm", signingAlgorithm) if res.Err != nil { return nil, res.Err } @@ -99,8 +99,8 @@ func (r *Relayer) AddKey(ctx context.Context, _ ibc.RelayerExecReporter, chainID return w, nil } -func (r *Relayer) RestoreKey(ctx context.Context, _ ibc.RelayerExecReporter, chainID, keyName, coinType, mnemonic string) error { - res := r.sys().RunC(ctx, r.log(), "keys", "restore", chainID, keyName, mnemonic, "--coin-type", coinType) +func (r *Relayer) RestoreKey(ctx context.Context, _ ibc.RelayerExecReporter, chainID, keyName, coinType, signingAlgorithm, mnemonic string) error { + res := r.sys().RunC(ctx, r.log(), "keys", "restore", chainID, keyName, mnemonic, "--coin-type", coinType, "--signing-algorithm", signingAlgorithm) if res.Err != nil { return res.Err } diff --git a/proto/cosmos/crypto/sr25519/keys.proto b/proto/cosmos/crypto/sr25519/keys.proto new file mode 100644 index 000000000..eed481375 --- /dev/null +++ b/proto/cosmos/crypto/sr25519/keys.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; + +// buf:lint:ignore PACKAGE_VERSION_SUFFIX +package cosmos.crypto.sr25519; + +import "gogoproto/gogo.proto"; + +// Originally github.com/cosmos/cosmos-sdk/crypto/keys/sr25519 +option go_package = "github.com/cosmos/relayer/v2/relayer/chains/cosmos/keys/sr25519"; + +option (gogoproto.messagename_all) = true; +option (gogoproto.goproto_stringer_all) = false; +option (gogoproto.goproto_getters_all) = false; + +// PubKey defines a sr25519 ECDSA public key. +message PubKey { + option (gogoproto.goproto_stringer) = false; + + bytes key = 1 [(gogoproto.casttype) = "github.com/cometbft/cometbft/crypto/sr25519.PubKey"]; +} diff --git a/relayer/chain.go b/relayer/chain.go index 3dafdba99..a23229bd8 100644 --- a/relayer/chain.go +++ b/relayer/chain.go @@ -8,6 +8,7 @@ import ( "time" "github.com/avast/retry-go/v4" + "github.com/cosmos/cosmos-sdk/crypto/hd" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" "github.com/cosmos/relayer/v2/relayer/provider" "go.uber.org/zap" @@ -20,6 +21,7 @@ var ( RtyErr = retry.LastErrorOnly(true) defaultCoinType uint32 = 118 + defaultAlgo string = string(hd.Secp256k1Type) ) // Chain represents the necessary data for connecting to and identifying a chain and its counterparties @@ -146,7 +148,7 @@ func (c *Chain) CreateTestKey() error { if c.ChainProvider.KeyExists(c.ChainProvider.Key()) { return fmt.Errorf("key {%s} exists for chain {%s}", c.ChainProvider.Key(), c.ChainID()) } - _, err := c.ChainProvider.AddKey(c.ChainProvider.Key(), defaultCoinType) + _, err := c.ChainProvider.AddKey(c.ChainProvider.Key(), defaultCoinType, defaultAlgo) return err } diff --git a/relayer/chains/cosmos/keys.go b/relayer/chains/cosmos/keys.go index 272c96b30..0ccdd0938 100644 --- a/relayer/chains/cosmos/keys.go +++ b/relayer/chains/cosmos/keys.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/go-bip39" + "github.com/cosmos/relayer/v2/relayer/chains/cosmos/keys/sr25519" "github.com/cosmos/relayer/v2/relayer/codecs/ethermint" "github.com/cosmos/relayer/v2/relayer/codecs/injective" "github.com/cosmos/relayer/v2/relayer/provider" @@ -19,12 +20,14 @@ const ethereumCoinType = uint32(60) var ( // SupportedAlgorithms defines the list of signing algorithms used on Evmos: // - secp256k1 (Cosmos) - // - eth_secp256k1 (Ethereum) - SupportedAlgorithms = keyring.SigningAlgoList{hd.Secp256k1, ethermint.EthSecp256k1, injective.EthSecp256k1} + // - sr25519 (Cosmos) + // - eth_secp256k1 (Ethereum, Injective) + SupportedAlgorithms = keyring.SigningAlgoList{hd.Secp256k1, sr25519.Sr25519, ethermint.EthSecp256k1, injective.EthSecp256k1} // SupportedAlgorithmsLedger defines the list of signing algorithms used on Evmos for the Ledger device: // - secp256k1 (Cosmos) - // - eth_secp256k1 (Ethereum) - SupportedAlgorithmsLedger = keyring.SigningAlgoList{hd.Secp256k1, ethermint.EthSecp256k1, injective.EthSecp256k1} + // - sr25519 (Cosmos) + // - eth_secp256k1 (Ethereum, Injective) + SupportedAlgorithmsLedger = keyring.SigningAlgoList{hd.Secp256k1, sr25519.Sr25519, ethermint.EthSecp256k1, injective.EthSecp256k1} ) // KeyringAlgoOptions defines a function keys options for the ethereum Secp256k1 curve. @@ -58,8 +61,8 @@ func (cc *CosmosProvider) KeystoreCreated(path string) bool { // AddKey generates a new mnemonic which is then converted to a private key and BIP-39 HD Path and persists it to the keystore. // It fails if there is an existing key with the same address. -func (cc *CosmosProvider) AddKey(name string, coinType uint32) (output *provider.KeyOutput, err error) { - ko, err := cc.KeyAddOrRestore(name, coinType) +func (cc *CosmosProvider) AddKey(name string, coinType uint32, signingAlgorithm string) (output *provider.KeyOutput, err error) { + ko, err := cc.KeyAddOrRestore(name, coinType, signingAlgorithm) if err != nil { return nil, err } @@ -68,8 +71,8 @@ func (cc *CosmosProvider) AddKey(name string, coinType uint32) (output *provider // RestoreKey converts a mnemonic to a private key and BIP-39 HD Path and persists it to the keystore. // It fails if there is an existing key with the same address. -func (cc *CosmosProvider) RestoreKey(name, mnemonic string, coinType uint32) (address string, err error) { - ko, err := cc.KeyAddOrRestore(name, coinType, mnemonic) +func (cc *CosmosProvider) RestoreKey(name, mnemonic string, coinType uint32, signingAlgorithm string) (address string, err error) { + ko, err := cc.KeyAddOrRestore(name, coinType, signingAlgorithm, mnemonic) if err != nil { return "", err } @@ -78,10 +81,17 @@ func (cc *CosmosProvider) RestoreKey(name, mnemonic string, coinType uint32) (ad // KeyAddOrRestore either generates a new mnemonic or uses the specified mnemonic and converts it to a private key // and BIP-39 HD Path which is then persisted to the keystore. It fails if there is an existing key with the same address. -func (cc *CosmosProvider) KeyAddOrRestore(keyName string, coinType uint32, mnemonic ...string) (*provider.KeyOutput, error) { +func (cc *CosmosProvider) KeyAddOrRestore(keyName string, coinType uint32, signingAlgorithm string, mnemonic ...string) (*provider.KeyOutput, error) { var mnemonicStr string var err error - algo := keyring.SignatureAlgo(hd.Secp256k1) + + var algo keyring.SignatureAlgo + switch signingAlgorithm { + case string(hd.Sr25519Type): + algo = sr25519.Sr25519 + default: + algo = hd.Secp256k1 + } if len(mnemonic) > 0 { mnemonicStr = mnemonic[0] diff --git a/relayer/chains/cosmos/keys/sr25519/algo.go b/relayer/chains/cosmos/keys/sr25519/algo.go new file mode 100644 index 000000000..d0c0eca96 --- /dev/null +++ b/relayer/chains/cosmos/keys/sr25519/algo.go @@ -0,0 +1,46 @@ +package sr25519 + +import ( + bip39 "github.com/cosmos/go-bip39" + + tmsr25519 "github.com/cometbft/cometbft/crypto/sr25519" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/types" +) + +var Sr25519 = sr25519Algo{} + +type sr25519Algo struct { +} + +func (s sr25519Algo) Name() hd.PubKeyType { + return hd.Sr25519Type +} + +// Derive derives and returns the sr25519 private key for the given seed and HD path. +func (s sr25519Algo) Derive() hd.DeriveFn { + return func(mnemonic string, bip39Passphrase, hdPath string) ([]byte, error) { + seed, err := bip39.NewSeedWithErrorChecking(mnemonic, bip39Passphrase) + if err != nil { + return nil, err + } + + masterPriv, ch := hd.ComputeMastersFromSeed(seed) + if len(hdPath) == 0 { + return masterPriv[:], nil + } + derivedKey, err := hd.DerivePrivateKeyForPath(masterPriv, ch, hdPath) + + return derivedKey, err + } +} + +// Generate generates a sr25519 private key from the given bytes. +func (s sr25519Algo) Generate() hd.GenerateFn { + return func(bz []byte) types.PrivKey { + var bzArr = make([]byte, 32) + copy(bzArr, bz) + + return &PrivKey{PrivKey: tmsr25519.GenPrivKeyFromSecret(bzArr)} + } +} diff --git a/relayer/chains/cosmos/keys/sr25519/keys.pb.go b/relayer/chains/cosmos/keys/sr25519/keys.pb.go new file mode 100644 index 000000000..49a3599b7 --- /dev/null +++ b/relayer/chains/cosmos/keys/sr25519/keys.pb.go @@ -0,0 +1,320 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: cosmos/crypto/sr25519/keys.proto + +// buf:lint:ignore PACKAGE_VERSION_SUFFIX + +package sr25519 + +import ( + fmt "fmt" + github_com_cometbft_cometbft_crypto_sr25519 "github.com/cometbft/cometbft/crypto/sr25519" + proto "github.com/cosmos/gogoproto/proto" + _ "github.com/gogo/protobuf/gogoproto" + 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 sr25519 ECDSA public key. +type PubKey struct { + Key github_com_cometbft_cometbft_crypto_sr25519.PubKey `protobuf:"bytes,1,opt,name=key,proto3,casttype=github.com/cometbft/cometbft/crypto/sr25519.PubKey" json:"key,omitempty"` +} + +func (m *PubKey) Reset() { *m = PubKey{} } +func (*PubKey) ProtoMessage() {} +func (*PubKey) Descriptor() ([]byte, []int) { + return fileDescriptor_daddabaf35039fbd, []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.sr25519.PubKey" +} +func init() { + proto.RegisterType((*PubKey)(nil), "cosmos.crypto.sr25519.PubKey") +} + +func init() { proto.RegisterFile("cosmos/crypto/sr25519/keys.proto", fileDescriptor_daddabaf35039fbd) } + +var fileDescriptor_daddabaf35039fbd = []byte{ + // 222 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x48, 0xce, 0x2f, 0xce, + 0xcd, 0x2f, 0xd6, 0x4f, 0x2e, 0xaa, 0x2c, 0x28, 0xc9, 0xd7, 0x2f, 0x2e, 0x32, 0x32, 0x35, 0x35, + 0xb4, 0xd4, 0xcf, 0x4e, 0xad, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x85, 0xa8, + 0xd0, 0x83, 0xa8, 0xd0, 0x83, 0xaa, 0x90, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0xab, 0xd0, 0x07, + 0xb1, 0x20, 0x8a, 0x95, 0x22, 0xb8, 0xd8, 0x02, 0x4a, 0x93, 0xbc, 0x53, 0x2b, 0x85, 0x3c, 0xb8, + 0x98, 0xb3, 0x53, 0x2b, 0x25, 0x18, 0x15, 0x18, 0x35, 0x78, 0x9c, 0xcc, 0x7e, 0xdd, 0x93, 0x37, + 0x4a, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x4d, 0x2d, + 0x49, 0x4a, 0x2b, 0x41, 0x62, 0xa0, 0xd8, 0xaf, 0x07, 0x31, 0x24, 0x08, 0x64, 0x84, 0x15, 0xcb, + 0x8c, 0x05, 0xf2, 0x0c, 0x4e, 0xa9, 0x27, 0x1e, 0xca, 0x31, 0xdc, 0x78, 0x28, 0xc7, 0x70, 0xe2, + 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, + 0xe2, 0xb1, 0x1c, 0xe3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0xd9, 0xa3, 0x58, + 0x02, 0xf6, 0x59, 0x51, 0x6a, 0x4e, 0x62, 0x65, 0x6a, 0x91, 0x7e, 0x99, 0x11, 0x9c, 0x99, 0x9c, + 0x91, 0x98, 0x99, 0x57, 0x0c, 0x53, 0x00, 0xf2, 0x2b, 0xcc, 0xe2, 0x24, 0x36, 0xb0, 0x3f, 0x8c, + 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x24, 0xfd, 0x40, 0x0e, 0x18, 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 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 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 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/relayer/chains/cosmos/keys/sr25519/privkey.go b/relayer/chains/cosmos/keys/sr25519/privkey.go new file mode 100644 index 000000000..b7b6efae3 --- /dev/null +++ b/relayer/chains/cosmos/keys/sr25519/privkey.go @@ -0,0 +1,47 @@ +package sr25519 + +import ( + tmsr25519 "github.com/cometbft/cometbft/crypto/sr25519" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" +) + +const ( + PrivKeySize = 32 + PrivKeyName = "tendermint/PrivKeySr25519" +) + +type PrivKey struct { + tmsr25519.PrivKey +} + +// type conversion +func (m *PrivKey) PubKey() cryptotypes.PubKey { + pk, ok := m.PrivKey.PubKey().(tmsr25519.PubKey) + if !ok { + panic("invalid public key type for sr25519 private key") + } + return &PubKey{Key: pk} +} + +// type conversion +func (m *PrivKey) Equals(other cryptotypes.LedgerPrivKey) bool { + sk2, ok := other.(*PrivKey) + if !ok { + return false + } + return m.PrivKey.Equals(sk2.PrivKey) +} + +func (m *PrivKey) ProtoMessage() {} + +func (m *PrivKey) Reset() { + m.PrivKey = tmsr25519.PrivKey{} +} + +func (m *PrivKey) String() string { + return string(m.Bytes()) +} + +func GenPrivKey() *PrivKey { + return &PrivKey{tmsr25519.GenPrivKey()} +} diff --git a/relayer/chains/cosmos/keys/sr25519/pubkey.go b/relayer/chains/cosmos/keys/sr25519/pubkey.go new file mode 100644 index 000000000..6325f9960 --- /dev/null +++ b/relayer/chains/cosmos/keys/sr25519/pubkey.go @@ -0,0 +1,38 @@ +package sr25519 + +import ( + "bytes" + + "github.com/cometbft/cometbft/crypto" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" +) + +const PubKeyName = "tendermint/PubKeySr25519" + +func (m *PubKey) Equals(other cryptotypes.PubKey) bool { + pk2, ok := other.(*PubKey) + if !ok { + return false + } + return bytes.Equal(m.Key, pk2.Key) +} + +func (m *PubKey) Address() crypto.Address { + return m.Key.Address() +} + +func (m PubKey) Bytes() []byte { + return m.Key.Bytes() +} + +func (m PubKey) String() string { + return m.Key.String() +} + +func (m PubKey) Type() string { + return "sr25519" +} + +func (m PubKey) VerifySignature(msg []byte, sigBytes []byte) bool { + return m.Key.VerifySignature(msg, sigBytes) +} diff --git a/relayer/chains/cosmos/keys_test.go b/relayer/chains/cosmos/keys_test.go new file mode 100644 index 000000000..987931041 --- /dev/null +++ b/relayer/chains/cosmos/keys_test.go @@ -0,0 +1,104 @@ +package cosmos_test + +import ( + "path/filepath" + "testing" + + "github.com/cosmos/relayer/v2/relayer/chains/cosmos" + "github.com/cosmos/relayer/v2/relayer/provider" + "github.com/stretchr/testify/require" + "go.uber.org/zap" +) + +func testProviderWithKeystore(t *testing.T, accountPrefix string, extraCodecs []string) provider.ChainProvider { + homePath := t.TempDir() + cfg := cosmos.CosmosProviderConfig{ + ChainID: "test", + KeyDirectory: filepath.Join(homePath, "keys"), + KeyringBackend: "test", + Timeout: "10s", + AccountPrefix: accountPrefix, + ExtraCodecs: extraCodecs, + } + p, err := cfg.NewProvider(zap.NewNop(), homePath, true, "test_chain") + if err != nil { + t.Fatalf("Error creating provider: %v", err) + } + err = p.CreateKeystore(homePath) + if err != nil { + t.Fatalf("Error creating keystore: %v", err) + } + return p +} + +// TestKeyRestore restores a test mnemonic +func TestKeyRestore(t *testing.T) { + const ( + keyName = "test_key" + signatureAlgorithm = "secp256k1" + mnemonic = "blind master acoustic speak victory lend kiss grab glad help demand hood roast zone lend sponsor level cheap truck kingdom apology token hover reunion" + accountPrefix = "cosmos" + expectedAddress = "cosmos15cw268ckjj2hgq8q3jf68slwjjcjlvxy57je2u" + coinType = uint32(118) + ) + + p := testProviderWithKeystore(t, accountPrefix, nil) + + address, err := p.RestoreKey(keyName, mnemonic, coinType, signatureAlgorithm) + require.NoError(t, err) + require.Equal(t, expectedAddress, address) +} + +// TestKeyRestoreEth restores a test mnemonic +func TestKeyRestoreEth(t *testing.T) { + const ( + keyName = "test_key" + signatureAlgorithm = "secp256k1" + mnemonic = "three elevator silk family street child flip also leaf inmate call frame shock little legal october vivid enable fetch siege sell burger dolphin green" + accountPrefix = "evmos" + expectedAddress = "evmos1dea7vlekr9e34vugwkvesulglt8fx4e457vk9z" + coinType = uint32(60) + ) + + p := testProviderWithKeystore(t, accountPrefix, []string{"ethermint"}) + + address, err := p.RestoreKey(keyName, mnemonic, coinType, signatureAlgorithm) + require.NoError(t, err) + require.Equal(t, expectedAddress, address) +} + +// TestKeyRestoreInj restores a test mnemonic +func TestKeyRestoreInj(t *testing.T) { + const ( + keyName = "inj_key" + signatureAlgorithm = "secp256k1" + mnemonic = "three elevator silk family street child flip also leaf inmate call frame shock little legal october vivid enable fetch siege sell burger dolphin green" + accountPrefix = "inj" + expectedAddress = "inj1dea7vlekr9e34vugwkvesulglt8fx4e4uk2udj" + coinType = uint32(60) + ) + + p := testProviderWithKeystore(t, accountPrefix, []string{"injective"}) + + address, err := p.RestoreKey(keyName, mnemonic, coinType, signatureAlgorithm) + require.NoError(t, err) + require.Equal(t, expectedAddress, address) +} + +// TestKeyRestoreSr25519 restores a test mnemonic +func TestKeyRestoreSr25519(t *testing.T) { + const ( + keyName = "sei_key" + signatureAlgorithm = "sr25519" + mnemonic = "three elevator silk family street child flip also leaf inmate call frame shock little legal october vivid enable fetch siege sell burger dolphin green" + accountPrefix = "sei" + expectedAddress = "sei1nmlj0guznnt0qyfj4yl6q5g4xuvgly4qw0w026" + coinType = uint32(118) + ) + + p := testProviderWithKeystore(t, accountPrefix, nil) + + address, err := p.RestoreKey(keyName, mnemonic, coinType, signatureAlgorithm) + require.NoError(t, err) + require.Equal(t, expectedAddress, address) +} diff --git a/relayer/chains/cosmos/provider.go b/relayer/chains/cosmos/provider.go index 58d3ca47f..b202b3cc1 100644 --- a/relayer/chains/cosmos/provider.go +++ b/relayer/chains/cosmos/provider.go @@ -35,26 +35,27 @@ var ( const cometEncodingThreshold = "v0.37.0-alpha" type CosmosProviderConfig struct { - KeyDirectory string `json:"key-directory" yaml:"key-directory"` - Key string `json:"key" yaml:"key"` - ChainName string `json:"-" yaml:"-"` - ChainID string `json:"chain-id" yaml:"chain-id"` - RPCAddr string `json:"rpc-addr" yaml:"rpc-addr"` - AccountPrefix string `json:"account-prefix" yaml:"account-prefix"` - KeyringBackend string `json:"keyring-backend" yaml:"keyring-backend"` - GasAdjustment float64 `json:"gas-adjustment" yaml:"gas-adjustment"` - GasPrices string `json:"gas-prices" yaml:"gas-prices"` - MinGasAmount uint64 `json:"min-gas-amount" yaml:"min-gas-amount"` - Debug bool `json:"debug" yaml:"debug"` - Timeout string `json:"timeout" yaml:"timeout"` - BlockTimeout string `json:"block-timeout" yaml:"block-timeout"` - OutputFormat string `json:"output-format" yaml:"output-format"` - SignModeStr string `json:"sign-mode" yaml:"sign-mode"` - ExtraCodecs []string `json:"extra-codecs" yaml:"extra-codecs"` - Modules []module.AppModuleBasic `json:"-" yaml:"-"` - Slip44 *int `json:"coin-type" yaml:"coin-type"` - Broadcast provider.BroadcastMode `json:"broadcast-mode" yaml:"broadcast-mode"` - MinLoopDuration time.Duration `json:"min-loop-duration" yaml:"min-loop-duration"` + KeyDirectory string `json:"key-directory" yaml:"key-directory"` + Key string `json:"key" yaml:"key"` + ChainName string `json:"-" yaml:"-"` + ChainID string `json:"chain-id" yaml:"chain-id"` + RPCAddr string `json:"rpc-addr" yaml:"rpc-addr"` + AccountPrefix string `json:"account-prefix" yaml:"account-prefix"` + KeyringBackend string `json:"keyring-backend" yaml:"keyring-backend"` + GasAdjustment float64 `json:"gas-adjustment" yaml:"gas-adjustment"` + GasPrices string `json:"gas-prices" yaml:"gas-prices"` + MinGasAmount uint64 `json:"min-gas-amount" yaml:"min-gas-amount"` + Debug bool `json:"debug" yaml:"debug"` + Timeout string `json:"timeout" yaml:"timeout"` + BlockTimeout string `json:"block-timeout" yaml:"block-timeout"` + OutputFormat string `json:"output-format" yaml:"output-format"` + SignModeStr string `json:"sign-mode" yaml:"sign-mode"` + ExtraCodecs []string `json:"extra-codecs" yaml:"extra-codecs"` + Modules []module.AppModuleBasic `json:"-" yaml:"-"` + Slip44 *int `json:"coin-type" yaml:"coin-type"` + SigningAlgorithm string `json:"signing-algorithm" yaml:"signing-algorithm"` + Broadcast provider.BroadcastMode `json:"broadcast-mode" yaml:"broadcast-mode"` + MinLoopDuration time.Duration `json:"min-loop-duration" yaml:"min-loop-duration"` } func (pc CosmosProviderConfig) Validate() error { diff --git a/relayer/chains/mock/mock_chain_processor.go b/relayer/chains/mock/mock_chain_processor.go index 5c94a63d6..4faf1fe3c 100644 --- a/relayer/chains/mock/mock_chain_processor.go +++ b/relayer/chains/mock/mock_chain_processor.go @@ -4,6 +4,7 @@ import ( "context" "time" + "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/relayer/v2/relayer/chains/cosmos" "github.com/cosmos/relayer/v2/relayer/processor" "github.com/cosmos/relayer/v2/relayer/provider" @@ -49,7 +50,7 @@ func NewMockChainProcessor(ctx context.Context, log *zap.Logger, chainID string, } chainProvider, _ := chainProviderCfg.NewProvider(zap.NewNop(), "/tmp", true, "mock-chain-name-"+chainID) _ = chainProvider.Init(ctx) - _, _ = chainProvider.AddKey(chainProvider.Key(), 118) + _, _ = chainProvider.AddKey(chainProvider.Key(), 118, string(hd.Secp256k1Type)) return &MockChainProcessor{ log: log, chainID: chainID, diff --git a/relayer/chains/penumbra/keys.go b/relayer/chains/penumbra/keys.go index c9e918bbe..aa09fa7b1 100644 --- a/relayer/chains/penumbra/keys.go +++ b/relayer/chains/penumbra/keys.go @@ -58,7 +58,7 @@ func (cc *PenumbraProvider) KeystoreCreated(path string) bool { // AddKey generates a new mnemonic which is then converted to a private key and BIP-39 HD Path and persists it to the keystore. // It fails if there is an existing key with the same address. -func (cc *PenumbraProvider) AddKey(name string, coinType uint32) (output *provider.KeyOutput, err error) { +func (cc *PenumbraProvider) AddKey(name string, coinType uint32, signingAlgorithm string) (output *provider.KeyOutput, err error) { ko, err := cc.KeyAddOrRestore(name, coinType) if err != nil { return nil, err @@ -68,7 +68,7 @@ func (cc *PenumbraProvider) AddKey(name string, coinType uint32) (output *provid // RestoreKey converts a mnemonic to a private key and BIP-39 HD Path and persists it to the keystore. // It fails if there is an existing key with the same address. -func (cc *PenumbraProvider) RestoreKey(name, mnemonic string, coinType uint32) (address string, err error) { +func (cc *PenumbraProvider) RestoreKey(name, mnemonic string, coinType uint32, signingAlgorithm string) (address string, err error) { ko, err := cc.KeyAddOrRestore(name, coinType, mnemonic) if err != nil { return "", err diff --git a/relayer/provider/provider.go b/relayer/provider/provider.go index b3c3160a9..362e9e945 100644 --- a/relayer/provider/provider.go +++ b/relayer/provider/provider.go @@ -15,7 +15,7 @@ import ( chantypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" - "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) @@ -215,8 +215,8 @@ func (r RelayerTxResponse) MarshalLogObject(enc zapcore.ObjectEncoder) error { type KeyProvider interface { CreateKeystore(path string) error KeystoreCreated(path string) bool - AddKey(name string, coinType uint32) (output *KeyOutput, err error) - RestoreKey(name, mnemonic string, coinType uint32) (address string, err error) + AddKey(name string, coinType uint32, signingAlgorithm string) (output *KeyOutput, err error) + RestoreKey(name, mnemonic string, coinType uint32, signingAlgorithm string) (address string, err error) ShowAddress(name string) (address string, err error) ListAddresses() (map[string]string, error) DeleteKey(name string) error