Merge PR #5439: Keybase: Multiple Signature Algorithms
This commit is contained in:
parent
d452e9398b
commit
f367087731
14
CHANGELOG.md
14
CHANGELOG.md
|
@ -101,7 +101,16 @@ if the provided arguments are invalid.
|
||||||
* (modules) [\#5299](https://github.com/cosmos/cosmos-sdk/pull/5299) `HandleDoubleSign` along with params `MaxEvidenceAge`
|
* (modules) [\#5299](https://github.com/cosmos/cosmos-sdk/pull/5299) `HandleDoubleSign` along with params `MaxEvidenceAge`
|
||||||
and `DoubleSignJailEndTime` have moved from the `x/slashing` module to the `x/evidence` module.
|
and `DoubleSignJailEndTime` have moved from the `x/slashing` module to the `x/evidence` module.
|
||||||
* (keys) [\#4941](https://github.com/cosmos/cosmos-sdk/issues/4941) Initializing a new keybase through `NewKeyringFromHomeFlag`, `NewKeyringFromDir`, `NewKeyBaseFromHomeFlag`, `NewKeyBaseFromDir`, or `NewInMemory` functions now accept optional parameters of type `KeybaseOption`. These optional parameters are also added on the keys subcommands functions, which are now public, and allows these options to be set on the commands or ignored to default to previous behavior.
|
* (keys) [\#4941](https://github.com/cosmos/cosmos-sdk/issues/4941) Initializing a new keybase through `NewKeyringFromHomeFlag`, `NewKeyringFromDir`, `NewKeyBaseFromHomeFlag`, `NewKeyBaseFromDir`, or `NewInMemory` functions now accept optional parameters of type `KeybaseOption`. These optional parameters are also added on the keys subcommands functions, which are now public, and allows these options to be set on the commands or ignored to default to previous behavior.
|
||||||
* The option introduced in this PR is `WithKeygenFunc` which allows a custom bytes to key implementation to be defined when keys are created.
|
* [\#5439](https://github.com/cosmos/cosmos-sdk/pull/5439) Further modularization was done to the `keybase`
|
||||||
|
package to make it more suitable for use with different key formats and algorithms:
|
||||||
|
* The `WithKeygenFunc` function added as a `KeybaseOption` which allows a custom bytes to key
|
||||||
|
implementation to be defined when keys are created.
|
||||||
|
* The `WithDeriveFunc` function added as a `KeybaseOption` allows custom logic for deriving a key
|
||||||
|
from a mnemonic, bip39 password, and HD Path.
|
||||||
|
* BIP44 is no longer build into `keybase.CreateAccount()`. It is however the default when using
|
||||||
|
the `client/keys` add command.
|
||||||
|
* `SupportedAlgos` and `SupportedAlgosLedger` functions return a slice of `SigningAlgo`s that are
|
||||||
|
supported by the keybase and the ledger integration respectively.
|
||||||
* (simapp) [\#5419](https://github.com/cosmos/cosmos-sdk/pull/5419) simapp/helpers.GenTx() now accepts a gas argument.
|
* (simapp) [\#5419](https://github.com/cosmos/cosmos-sdk/pull/5419) simapp/helpers.GenTx() now accepts a gas argument.
|
||||||
* (baseapp) [\#5455](https://github.com/cosmos/cosmos-sdk/issues/5455) An `sdk.Context` is passed into the `router.Route()`
|
* (baseapp) [\#5455](https://github.com/cosmos/cosmos-sdk/issues/5455) An `sdk.Context` is passed into the `router.Route()`
|
||||||
function.
|
function.
|
||||||
|
@ -181,6 +190,9 @@ that allows for arbitrary vesting periods.
|
||||||
* Introduces cli commands and rest routes to query historical information at a given height
|
* Introduces cli commands and rest routes to query historical information at a given height
|
||||||
* (modules) [\#5249](https://github.com/cosmos/cosmos-sdk/pull/5249) Funds are now allowed to be directly sent to the community pool (via the distribution module account).
|
* (modules) [\#5249](https://github.com/cosmos/cosmos-sdk/pull/5249) Funds are now allowed to be directly sent to the community pool (via the distribution module account).
|
||||||
* (keys) [\#4941](https://github.com/cosmos/cosmos-sdk/issues/4941) Introduce keybase option to allow overriding the default private key implementation of a key generated through the `keys add` cli command.
|
* (keys) [\#4941](https://github.com/cosmos/cosmos-sdk/issues/4941) Introduce keybase option to allow overriding the default private key implementation of a key generated through the `keys add` cli command.
|
||||||
|
* (keys) [\#5439](https://github.com/cosmos/cosmos-sdk/pull/5439) Flags `--algo` and `--hd-path` are added to
|
||||||
|
`keys add` command in order to make use of keybase modularized. By default, it uses (0, 0) bip44
|
||||||
|
HD path and secp256k1 keys, so is non-breaking.
|
||||||
* (types) [\#5447](https://github.com/cosmos/cosmos-sdk/pull/5447) Added `ApproxRoot` function to sdk.Decimal type in order to get the nth root for a decimal number, where n is a positive integer.
|
* (types) [\#5447](https://github.com/cosmos/cosmos-sdk/pull/5447) Added `ApproxRoot` function to sdk.Decimal type in order to get the nth root for a decimal number, where n is a positive integer.
|
||||||
* An `ApproxSqrt` function was also added for convenience around the common case of n=2.
|
* An `ApproxSqrt` function was also added for convenience around the common case of n=2.
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,8 @@ const (
|
||||||
flagIndex = "index"
|
flagIndex = "index"
|
||||||
flagMultisig = "multisig"
|
flagMultisig = "multisig"
|
||||||
flagNoSort = "nosort"
|
flagNoSort = "nosort"
|
||||||
|
flagHDPath = "hd-path"
|
||||||
|
flagKeyAlgo = "algo"
|
||||||
|
|
||||||
// DefaultKeyPass contains the default key password for genesis transactions
|
// DefaultKeyPass contains the default key password for genesis transactions
|
||||||
DefaultKeyPass = "12345678"
|
DefaultKeyPass = "12345678"
|
||||||
|
@ -71,9 +73,11 @@ the flag --nosort is set.
|
||||||
cmd.Flags().Bool(flagRecover, false, "Provide seed phrase to recover existing key instead of creating")
|
cmd.Flags().Bool(flagRecover, false, "Provide seed phrase to recover existing key instead of creating")
|
||||||
cmd.Flags().Bool(flagNoBackup, false, "Don't print out seed phrase (if others are watching the terminal)")
|
cmd.Flags().Bool(flagNoBackup, false, "Don't print out seed phrase (if others are watching the terminal)")
|
||||||
cmd.Flags().Bool(flagDryRun, false, "Perform action, but don't add key to local keystore")
|
cmd.Flags().Bool(flagDryRun, false, "Perform action, but don't add key to local keystore")
|
||||||
|
cmd.Flags().String(flagHDPath, "", "Manual HD Path derivation (overrides BIP44 config)")
|
||||||
cmd.Flags().Uint32(flagAccount, 0, "Account number for HD derivation")
|
cmd.Flags().Uint32(flagAccount, 0, "Account number for HD derivation")
|
||||||
cmd.Flags().Uint32(flagIndex, 0, "Address index number for HD derivation")
|
cmd.Flags().Uint32(flagIndex, 0, "Address index number for HD derivation")
|
||||||
cmd.Flags().Bool(flags.FlagIndentResponse, false, "Add indent to JSON response")
|
cmd.Flags().Bool(flags.FlagIndentResponse, false, "Add indent to JSON response")
|
||||||
|
cmd.Flags().String(flagKeyAlgo, string(keys.Secp256k1), "Key signing algorithm to generate keys for")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,6 +116,14 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keys.Keybase, inBuf *bufio.
|
||||||
interactive := viper.GetBool(flagInteractive)
|
interactive := viper.GetBool(flagInteractive)
|
||||||
showMnemonic := !viper.GetBool(flagNoBackup)
|
showMnemonic := !viper.GetBool(flagNoBackup)
|
||||||
|
|
||||||
|
algo := keys.SigningAlgo(viper.GetString(flagKeyAlgo))
|
||||||
|
if algo == keys.SigningAlgo("") {
|
||||||
|
algo = keys.Secp256k1
|
||||||
|
}
|
||||||
|
if !keys.IsSupportedAlgorithm(kb.SupportedAlgos(), algo) {
|
||||||
|
return keys.ErrUnsupportedSigningAlgo
|
||||||
|
}
|
||||||
|
|
||||||
if !viper.GetBool(flagDryRun) {
|
if !viper.GetBool(flagDryRun) {
|
||||||
_, err = kb.Get(name)
|
_, err = kb.Get(name)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -164,7 +176,7 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keys.Keybase, inBuf *bufio.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = kb.CreateOffline(name, pk)
|
_, err = kb.CreateOffline(name, pk, algo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -174,8 +186,26 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keys.Keybase, inBuf *bufio.
|
||||||
account := uint32(viper.GetInt(flagAccount))
|
account := uint32(viper.GetInt(flagAccount))
|
||||||
index := uint32(viper.GetInt(flagIndex))
|
index := uint32(viper.GetInt(flagIndex))
|
||||||
|
|
||||||
|
useBIP44 := !viper.IsSet(flagHDPath)
|
||||||
|
var hdPath string
|
||||||
|
|
||||||
|
if useBIP44 {
|
||||||
|
hdPath = keys.CreateHDPath(account, index).String()
|
||||||
|
} else {
|
||||||
|
hdPath = viper.GetString(flagHDPath)
|
||||||
|
}
|
||||||
|
|
||||||
// If we're using ledger, only thing we need is the path and the bech32 prefix.
|
// If we're using ledger, only thing we need is the path and the bech32 prefix.
|
||||||
if viper.GetBool(flags.FlagUseLedger) {
|
if viper.GetBool(flags.FlagUseLedger) {
|
||||||
|
|
||||||
|
if !useBIP44 {
|
||||||
|
return errors.New("cannot set custom bip32 path with ledger")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !keys.IsSupportedAlgorithm(kb.SupportedAlgosLedger(), algo) {
|
||||||
|
return keys.ErrUnsupportedSigningAlgo
|
||||||
|
}
|
||||||
|
|
||||||
bech32PrefixAccAddr := sdk.GetConfig().GetBech32AccountAddrPrefix()
|
bech32PrefixAccAddr := sdk.GetConfig().GetBech32AccountAddrPrefix()
|
||||||
info, err := kb.CreateLedger(name, keys.Secp256k1, bech32PrefixAccAddr, account, index)
|
info, err := kb.CreateLedger(name, keys.Secp256k1, bech32PrefixAccAddr, account, index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -240,7 +270,7 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keys.Keybase, inBuf *bufio.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := kb.CreateAccount(name, mnemonic, bip39Passphrase, DefaultKeyPass, account, index)
|
info, err := kb.CreateAccount(name, mnemonic, bip39Passphrase, DefaultKeyPass, hdPath, algo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||||
|
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||||
"github.com/cosmos/cosmos-sdk/tests"
|
"github.com/cosmos/cosmos-sdk/tests"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -44,13 +45,13 @@ func Test_runDeleteCmd(t *testing.T) {
|
||||||
if runningUnattended {
|
if runningUnattended {
|
||||||
mockIn.Reset("testpass1\ntestpass1\n")
|
mockIn.Reset("testpass1\ntestpass1\n")
|
||||||
}
|
}
|
||||||
_, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", 0, 0)
|
_, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", "0", keys.Secp256k1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
if runningUnattended {
|
if runningUnattended {
|
||||||
mockIn.Reset("testpass1\ntestpass1\n")
|
mockIn.Reset("testpass1\ntestpass1\n")
|
||||||
}
|
}
|
||||||
_, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", 0, 1)
|
_, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", "1", keys.Secp256k1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
if runningUnattended {
|
if runningUnattended {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||||
|
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||||
"github.com/cosmos/cosmos-sdk/tests"
|
"github.com/cosmos/cosmos-sdk/tests"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -32,7 +33,7 @@ func Test_runExportCmd(t *testing.T) {
|
||||||
if runningUnattended {
|
if runningUnattended {
|
||||||
mockIn.Reset("testpass1\ntestpass1\n")
|
mockIn.Reset("testpass1\ntestpass1\n")
|
||||||
}
|
}
|
||||||
_, err = kb.CreateAccount("keyname1", tests.TestMnemonic, "", "123456789", 0, 0)
|
_, err = kb.CreateAccount("keyname1", tests.TestMnemonic, "", "123456789", "", keys.Secp256k1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Now enter password
|
// Now enter password
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||||
|
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||||
"github.com/cosmos/cosmos-sdk/tests"
|
"github.com/cosmos/cosmos-sdk/tests"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -36,7 +37,7 @@ func Test_runListCmd(t *testing.T) {
|
||||||
mockIn.Reset("testpass1\ntestpass1\n")
|
mockIn.Reset("testpass1\ntestpass1\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = kb.CreateAccount("something", tests.TestMnemonic, "", "", 0, 0)
|
_, err = kb.CreateAccount("something", tests.TestMnemonic, "", "", "", keys.Secp256k1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|
|
@ -58,13 +58,13 @@ func Test_runShowCmd(t *testing.T) {
|
||||||
if runningUnattended {
|
if runningUnattended {
|
||||||
mockIn.Reset("testpass1\ntestpass1\n")
|
mockIn.Reset("testpass1\ntestpass1\n")
|
||||||
}
|
}
|
||||||
_, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", 0, 0)
|
_, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", "0", keys.Secp256k1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
if runningUnattended {
|
if runningUnattended {
|
||||||
mockIn.Reset("testpass1\n")
|
mockIn.Reset("testpass1\n")
|
||||||
}
|
}
|
||||||
_, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", 0, 1)
|
_, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", "1", keys.Secp256k1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Now try single key
|
// Now try single key
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||||
|
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||||
"github.com/cosmos/cosmos-sdk/tests"
|
"github.com/cosmos/cosmos-sdk/tests"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -38,9 +39,9 @@ func Test_runUpdateCmd(t *testing.T) {
|
||||||
|
|
||||||
kb, err := NewKeyBaseFromHomeFlag()
|
kb, err := NewKeyBaseFromHomeFlag()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
_, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", 0, 0)
|
_, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", "0", keys.Secp256k1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
_, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", 0, 1)
|
_, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", "1", keys.Secp256k1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Try again now that we have keys
|
// Try again now that we have keys
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
||||||
dbm "github.com/tendermint/tm-db"
|
dbm "github.com/tendermint/tm-db"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/keyerror"
|
"github.com/cosmos/cosmos-sdk/crypto/keys/keyerror"
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/mintkey"
|
"github.com/cosmos/cosmos-sdk/crypto/keys/mintkey"
|
||||||
"github.com/cosmos/cosmos-sdk/types"
|
"github.com/cosmos/cosmos-sdk/types"
|
||||||
|
@ -57,7 +56,7 @@ const (
|
||||||
var (
|
var (
|
||||||
// ErrUnsupportedSigningAlgo is raised when the caller tries to use a
|
// ErrUnsupportedSigningAlgo is raised when the caller tries to use a
|
||||||
// different signing scheme than secp256k1.
|
// different signing scheme than secp256k1.
|
||||||
ErrUnsupportedSigningAlgo = errors.New("unsupported signing algo: only secp256k1 is supported")
|
ErrUnsupportedSigningAlgo = errors.New("unsupported signing algo")
|
||||||
|
|
||||||
// ErrUnsupportedLanguage is raised when the caller tries to use a
|
// ErrUnsupportedLanguage is raised when the caller tries to use a
|
||||||
// different language than english for creating a mnemonic sentence.
|
// different language than english for creating a mnemonic sentence.
|
||||||
|
@ -101,18 +100,10 @@ func (kb dbKeybase) CreateMnemonic(
|
||||||
// CreateAccount converts a mnemonic to a private key and persists it, encrypted
|
// CreateAccount converts a mnemonic to a private key and persists it, encrypted
|
||||||
// with the given password.
|
// with the given password.
|
||||||
func (kb dbKeybase) CreateAccount(
|
func (kb dbKeybase) CreateAccount(
|
||||||
name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32,
|
name, mnemonic, bip39Passwd, encryptPasswd, hdPath string, algo SigningAlgo,
|
||||||
) (Info, error) {
|
) (Info, error) {
|
||||||
|
|
||||||
return kb.base.CreateAccount(kb, name, mnemonic, bip39Passwd, encryptPasswd, account, index)
|
return kb.base.CreateAccount(kb, name, mnemonic, bip39Passwd, encryptPasswd, hdPath, algo)
|
||||||
}
|
|
||||||
|
|
||||||
// Derive computes a BIP39 seed from th mnemonic and bip39Passwd.
|
|
||||||
func (kb dbKeybase) Derive(
|
|
||||||
name, mnemonic, bip39Passphrase, encryptPasswd string, params hd.BIP44Params,
|
|
||||||
) (Info, error) {
|
|
||||||
|
|
||||||
return kb.base.Derive(kb, name, mnemonic, bip39Passphrase, encryptPasswd, params)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateLedger creates a new locally-stored reference to a Ledger keypair.
|
// CreateLedger creates a new locally-stored reference to a Ledger keypair.
|
||||||
|
@ -126,8 +117,8 @@ func (kb dbKeybase) CreateLedger(
|
||||||
|
|
||||||
// CreateOffline creates a new reference to an offline keypair. It returns the
|
// CreateOffline creates a new reference to an offline keypair. It returns the
|
||||||
// created key info.
|
// created key info.
|
||||||
func (kb dbKeybase) CreateOffline(name string, pub tmcrypto.PubKey) (Info, error) {
|
func (kb dbKeybase) CreateOffline(name string, pub tmcrypto.PubKey, algo SigningAlgo) (Info, error) {
|
||||||
return kb.base.writeOfflineKey(kb, name, pub), nil
|
return kb.base.writeOfflineKey(kb, name, pub, algo), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateMulti creates a new reference to a multisig (offline) keypair. It
|
// CreateMulti creates a new reference to a multisig (offline) keypair. It
|
||||||
|
@ -199,7 +190,7 @@ func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, pub t
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
priv, err = mintkey.UnarmorDecryptPrivKey(i.PrivKeyArmor, passphrase)
|
priv, _, err = mintkey.UnarmorDecryptPrivKey(i.PrivKeyArmor, passphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -238,7 +229,7 @@ func (kb dbKeybase) ExportPrivateKeyObject(name string, passphrase string) (tmcr
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
priv, err = mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase)
|
priv, _, err = mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -272,7 +263,7 @@ func (kb dbKeybase) ExportPubKey(name string) (armor string, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes()), nil
|
return mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes(), string(info.GetAlgo())), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExportPrivKey returns a private key in ASCII armored format.
|
// ExportPrivKey returns a private key in ASCII armored format.
|
||||||
|
@ -285,7 +276,12 @@ func (kb dbKeybase) ExportPrivKey(name string, decryptPassphrase string,
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return mintkey.EncryptArmorPrivKey(priv, encryptPassphrase), nil
|
info, err := kb.Get(name)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return mintkey.EncryptArmorPrivKey(priv, encryptPassphrase, string(info.GetAlgo())), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImportPrivKey imports a private key in ASCII armor format. It returns an
|
// ImportPrivKey imports a private key in ASCII armor format. It returns an
|
||||||
|
@ -296,12 +292,12 @@ func (kb dbKeybase) ImportPrivKey(name string, armor string, passphrase string)
|
||||||
return errors.New("Cannot overwrite key " + name)
|
return errors.New("Cannot overwrite key " + name)
|
||||||
}
|
}
|
||||||
|
|
||||||
privKey, err := mintkey.UnarmorDecryptPrivKey(armor, passphrase)
|
privKey, algo, err := mintkey.UnarmorDecryptPrivKey(armor, passphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "couldn't import private key")
|
return errors.Wrap(err, "couldn't import private key")
|
||||||
}
|
}
|
||||||
|
|
||||||
kb.writeLocalKey(name, privKey, passphrase)
|
kb.writeLocalKey(name, privKey, passphrase, SigningAlgo(algo))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,7 +325,7 @@ func (kb dbKeybase) ImportPubKey(name string, armor string) (err error) {
|
||||||
return errors.New("Cannot overwrite data for name " + name)
|
return errors.New("Cannot overwrite data for name " + name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pubBytes, err := mintkey.UnarmorPubKeyBytes(armor)
|
pubBytes, algo, err := mintkey.UnarmorPubKeyBytes(armor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -339,7 +335,7 @@ func (kb dbKeybase) ImportPubKey(name string, armor string) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
kb.base.writeOfflineKey(kb, name, pubKey)
|
kb.base.writeOfflineKey(kb, name, pubKey, SigningAlgo(algo))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,7 +351,7 @@ func (kb dbKeybase) Delete(name, passphrase string, skipPass bool) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if linfo, ok := info.(localInfo); ok && !skipPass {
|
if linfo, ok := info.(localInfo); ok && !skipPass {
|
||||||
if _, err = mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase); err != nil {
|
if _, _, err = mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -382,7 +378,7 @@ func (kb dbKeybase) Update(name, oldpass string, getNewpass func() (string, erro
|
||||||
case localInfo:
|
case localInfo:
|
||||||
linfo := i
|
linfo := i
|
||||||
|
|
||||||
key, err := mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, oldpass)
|
key, _, err := mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, oldpass)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -392,7 +388,7 @@ func (kb dbKeybase) Update(name, oldpass string, getNewpass func() (string, erro
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
kb.writeLocalKey(name, key, newpass)
|
kb.writeLocalKey(name, key, newpass, i.GetAlgo())
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -405,13 +401,23 @@ func (kb dbKeybase) CloseDB() {
|
||||||
kb.db.Close()
|
kb.db.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kb dbKeybase) writeLocalKey(name string, priv tmcrypto.PrivKey, passphrase string) Info {
|
// SupportedAlgos returns a list of supported signing algorithms.
|
||||||
|
func (kb dbKeybase) SupportedAlgos() []SigningAlgo {
|
||||||
|
return kb.base.SupportedAlgos()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SupportedAlgosLedger returns a list of supported ledger signing algorithms.
|
||||||
|
func (kb dbKeybase) SupportedAlgosLedger() []SigningAlgo {
|
||||||
|
return kb.base.SupportedAlgosLedger()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kb dbKeybase) writeLocalKey(name string, priv tmcrypto.PrivKey, passphrase string, algo SigningAlgo) Info {
|
||||||
// encrypt private key using passphrase
|
// encrypt private key using passphrase
|
||||||
privArmor := mintkey.EncryptArmorPrivKey(priv, passphrase)
|
privArmor := mintkey.EncryptArmorPrivKey(priv, passphrase, string(algo))
|
||||||
|
|
||||||
// make Info
|
// make Info
|
||||||
pub := priv.PubKey()
|
pub := priv.PubKey()
|
||||||
info := newLocalInfo(name, pub, privArmor)
|
info := newLocalInfo(name, pub, privArmor, algo)
|
||||||
|
|
||||||
kb.writeInfo(name, info)
|
kb.writeInfo(name, info)
|
||||||
return info
|
return info
|
||||||
|
|
|
@ -18,6 +18,9 @@ import (
|
||||||
type (
|
type (
|
||||||
kbOptions struct {
|
kbOptions struct {
|
||||||
keygenFunc PrivKeyGenFunc
|
keygenFunc PrivKeyGenFunc
|
||||||
|
deriveFunc DeriveKeyFunc
|
||||||
|
supportedAlgos []SigningAlgo
|
||||||
|
supportedAlgosLedger []SigningAlgo
|
||||||
}
|
}
|
||||||
|
|
||||||
// baseKeybase is an auxiliary type that groups Keybase storage agnostic features
|
// baseKeybase is an auxiliary type that groups Keybase storage agnostic features
|
||||||
|
@ -32,7 +35,7 @@ type (
|
||||||
}
|
}
|
||||||
|
|
||||||
writeLocalKeyer interface {
|
writeLocalKeyer interface {
|
||||||
writeLocalKey(name string, priv tmcrypto.PrivKey, passphrase string) Info
|
writeLocalKey(name string, priv tmcrypto.PrivKey, passphrase string, algo SigningAlgo) Info
|
||||||
}
|
}
|
||||||
|
|
||||||
infoWriter interface {
|
infoWriter interface {
|
||||||
|
@ -47,10 +50,36 @@ func WithKeygenFunc(f PrivKeyGenFunc) KeybaseOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithDeriveFunc applies an overridden key derivation function to generate the private key.
|
||||||
|
func WithDeriveFunc(f DeriveKeyFunc) KeybaseOption {
|
||||||
|
return func(o *kbOptions) {
|
||||||
|
o.deriveFunc = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSupportedAlgos defines the list of accepted SigningAlgos.
|
||||||
|
func WithSupportedAlgos(algos []SigningAlgo) KeybaseOption {
|
||||||
|
return func(o *kbOptions) {
|
||||||
|
o.supportedAlgos = algos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSupportedAlgosLedger defines the list of accepted SigningAlgos compatible with Ledger.
|
||||||
|
func WithSupportedAlgosLedger(algos []SigningAlgo) KeybaseOption {
|
||||||
|
return func(o *kbOptions) {
|
||||||
|
o.supportedAlgosLedger = algos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// newBaseKeybase generates the base keybase with defaulting to tendermint SECP256K1 key type
|
// newBaseKeybase generates the base keybase with defaulting to tendermint SECP256K1 key type
|
||||||
func newBaseKeybase(optionsFns ...KeybaseOption) baseKeybase {
|
func newBaseKeybase(optionsFns ...KeybaseOption) baseKeybase {
|
||||||
// Default options for keybase
|
// Default options for keybase
|
||||||
options := kbOptions{keygenFunc: baseSecpPrivKeyGen}
|
options := kbOptions{
|
||||||
|
keygenFunc: StdPrivKeyGen,
|
||||||
|
deriveFunc: StdDeriveKey,
|
||||||
|
supportedAlgos: []SigningAlgo{Secp256k1},
|
||||||
|
supportedAlgosLedger: []SigningAlgo{Secp256k1},
|
||||||
|
}
|
||||||
|
|
||||||
for _, optionFn := range optionsFns {
|
for _, optionFn := range optionsFns {
|
||||||
optionFn(&options)
|
optionFn(&options)
|
||||||
|
@ -59,9 +88,20 @@ func newBaseKeybase(optionsFns ...KeybaseOption) baseKeybase {
|
||||||
return baseKeybase{options: options}
|
return baseKeybase{options: options}
|
||||||
}
|
}
|
||||||
|
|
||||||
// baseSecpPrivKeyGen generates a secp256k1 private key from the given bytes
|
// StdPrivKeyGen is the default PrivKeyGen function in the keybase.
|
||||||
func baseSecpPrivKeyGen(bz [32]byte) tmcrypto.PrivKey {
|
// For now, it only supports Secp256k1
|
||||||
return secp256k1.PrivKeySecp256k1(bz)
|
func StdPrivKeyGen(bz []byte, algo SigningAlgo) (tmcrypto.PrivKey, error) {
|
||||||
|
if algo == Secp256k1 {
|
||||||
|
return SecpPrivKeyGen(bz), nil
|
||||||
|
}
|
||||||
|
return nil, ErrUnsupportedSigningAlgo
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecpPrivKeyGen generates a secp256k1 private key from the given bytes
|
||||||
|
func SecpPrivKeyGen(bz []byte) tmcrypto.PrivKey {
|
||||||
|
var bzArr [32]byte
|
||||||
|
copy(bzArr[:], bz)
|
||||||
|
return secp256k1.PrivKeySecp256k1(bzArr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignWithLedger signs a binary message with the ledger device referenced by an Info object
|
// SignWithLedger signs a binary message with the ledger device referenced by an Info object
|
||||||
|
@ -111,29 +151,26 @@ func (kb baseKeybase) DecodeSignature(info Info, msg []byte) (sig []byte, pub tm
|
||||||
|
|
||||||
// CreateAccount creates an account Info object.
|
// CreateAccount creates an account Info object.
|
||||||
func (kb baseKeybase) CreateAccount(
|
func (kb baseKeybase) CreateAccount(
|
||||||
keyWriter keyWriter, name, mnemonic, bip39Passwd, encryptPasswd string, account, index uint32,
|
keyWriter keyWriter, name, mnemonic, bip39Passphrase, encryptPasswd, hdPath string, algo SigningAlgo,
|
||||||
) (Info, error) {
|
|
||||||
|
|
||||||
hdPath := CreateHDPath(account, index)
|
|
||||||
return kb.Derive(keyWriter, name, mnemonic, bip39Passwd, encryptPasswd, *hdPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (kb baseKeybase) persistDerivedKey(
|
|
||||||
keyWriter keyWriter, seed []byte, passwd, name, fullHdPath string,
|
|
||||||
) (Info, error) {
|
) (Info, error) {
|
||||||
|
|
||||||
// create master key and derive first key for keyring
|
// create master key and derive first key for keyring
|
||||||
derivedPriv, err := ComputeDerivedKey(seed, fullHdPath)
|
derivedPriv, err := kb.options.deriveFunc(mnemonic, bip39Passphrase, hdPath, algo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
privKey, err := kb.options.keygenFunc(derivedPriv, algo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var info Info
|
var info Info
|
||||||
|
|
||||||
if passwd != "" {
|
if encryptPasswd != "" {
|
||||||
info = keyWriter.writeLocalKey(name, kb.options.keygenFunc(derivedPriv), passwd)
|
info = keyWriter.writeLocalKey(name, privKey, encryptPasswd, algo)
|
||||||
} else {
|
} else {
|
||||||
info = kb.writeOfflineKey(keyWriter, name, kb.options.keygenFunc(derivedPriv).PubKey())
|
info = kb.writeOfflineKey(keyWriter, name, privKey.PubKey(), algo)
|
||||||
}
|
}
|
||||||
|
|
||||||
return info, nil
|
return info, nil
|
||||||
|
@ -145,7 +182,7 @@ func (kb baseKeybase) CreateLedger(
|
||||||
w infoWriter, name string, algo SigningAlgo, hrp string, account, index uint32,
|
w infoWriter, name string, algo SigningAlgo, hrp string, account, index uint32,
|
||||||
) (Info, error) {
|
) (Info, error) {
|
||||||
|
|
||||||
if !IsAlgoSupported(algo) {
|
if !IsSupportedAlgorithm(kb.SupportedAlgosLedger(), algo) {
|
||||||
return nil, ErrUnsupportedSigningAlgo
|
return nil, ErrUnsupportedSigningAlgo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +194,7 @@ func (kb baseKeybase) CreateLedger(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return kb.writeLedgerKey(w, name, priv.PubKey(), *hdPath), nil
|
return kb.writeLedgerKey(w, name, priv.PubKey(), *hdPath, algo), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateMnemonic generates a new key with the given algorithm and language pair.
|
// CreateMnemonic generates a new key with the given algorithm and language pair.
|
||||||
|
@ -169,7 +206,7 @@ func (kb baseKeybase) CreateMnemonic(
|
||||||
return nil, "", ErrUnsupportedLanguage
|
return nil, "", ErrUnsupportedLanguage
|
||||||
}
|
}
|
||||||
|
|
||||||
if !IsAlgoSupported(algo) {
|
if !IsSupportedAlgorithm(kb.SupportedAlgos(), algo) {
|
||||||
return nil, "", ErrUnsupportedSigningAlgo
|
return nil, "", ErrUnsupportedSigningAlgo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,37 +222,22 @@ func (kb baseKeybase) CreateMnemonic(
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err = kb.persistDerivedKey(
|
info, err = kb.CreateAccount(keyWriter, name, mnemonic, DefaultBIP39Passphrase, passwd, types.GetConfig().GetFullFundraiserPath(), algo)
|
||||||
keyWriter,
|
if err != nil {
|
||||||
bip39.NewSeed(mnemonic, DefaultBIP39Passphrase), passwd,
|
return nil, "", err
|
||||||
name, types.GetConfig().GetFullFundraiserPath(),
|
}
|
||||||
)
|
|
||||||
|
|
||||||
return info, mnemonic, err
|
return info, mnemonic, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Derive computes a BIP39 seed from the mnemonic and bip39Passphrase. It creates
|
func (kb baseKeybase) writeLedgerKey(w infoWriter, name string, pub tmcrypto.PubKey, path hd.BIP44Params, algo SigningAlgo) Info {
|
||||||
// a private key from the seed using the BIP44 params.
|
info := newLedgerInfo(name, pub, path, algo)
|
||||||
func (kb baseKeybase) Derive(
|
|
||||||
keyWriter keyWriter, name, mnemonic, bip39Passphrase, encryptPasswd string, params hd.BIP44Params, // nolint:interfacer
|
|
||||||
) (Info, error) {
|
|
||||||
|
|
||||||
seed, err := bip39.NewSeedWithErrorChecking(mnemonic, bip39Passphrase)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return kb.persistDerivedKey(keyWriter, seed, encryptPasswd, name, params.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (kb baseKeybase) writeLedgerKey(w infoWriter, name string, pub tmcrypto.PubKey, path hd.BIP44Params) Info {
|
|
||||||
info := newLedgerInfo(name, pub, path)
|
|
||||||
w.writeInfo(name, info)
|
w.writeInfo(name, info)
|
||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kb baseKeybase) writeOfflineKey(w infoWriter, name string, pub tmcrypto.PubKey) Info {
|
func (kb baseKeybase) writeOfflineKey(w infoWriter, name string, pub tmcrypto.PubKey, algo SigningAlgo) Info {
|
||||||
info := newOfflineInfo(name, pub)
|
info := newOfflineInfo(name, pub, algo)
|
||||||
w.writeInfo(name, info)
|
w.writeInfo(name, info)
|
||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
|
@ -226,10 +248,28 @@ func (kb baseKeybase) writeMultisigKey(w infoWriter, name string, pub tmcrypto.P
|
||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
|
|
||||||
// ComputeDerivedKey derives and returns the private key for the given seed and HD path.
|
// StdDeriveKey is the default DeriveKey function in the keybase.
|
||||||
func ComputeDerivedKey(seed []byte, fullHdPath string) ([32]byte, error) {
|
// For now, it only supports Secp256k1
|
||||||
|
func StdDeriveKey(mnemonic string, bip39Passphrase, hdPath string, algo SigningAlgo) ([]byte, error) {
|
||||||
|
if algo == Secp256k1 {
|
||||||
|
return SecpDeriveKey(mnemonic, bip39Passphrase, hdPath)
|
||||||
|
}
|
||||||
|
return nil, ErrUnsupportedSigningAlgo
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecpDeriveKey derives and returns the secp256k1 private key for the given seed and HD path.
|
||||||
|
func SecpDeriveKey(mnemonic string, bip39Passphrase, hdPath string) ([]byte, error) {
|
||||||
|
seed, err := bip39.NewSeedWithErrorChecking(mnemonic, bip39Passphrase)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
masterPriv, ch := hd.ComputeMastersFromSeed(seed)
|
masterPriv, ch := hd.ComputeMastersFromSeed(seed)
|
||||||
return hd.DerivePrivateKeyForPath(masterPriv, ch, fullHdPath)
|
if len(hdPath) == 0 {
|
||||||
|
return masterPriv[:], nil
|
||||||
|
}
|
||||||
|
derivedKey, err := hd.DerivePrivateKeyForPath(masterPriv, ch, hdPath)
|
||||||
|
return derivedKey[:], err
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateHDPath returns BIP 44 object from account and index parameters.
|
// CreateHDPath returns BIP 44 object from account and index parameters.
|
||||||
|
@ -237,9 +277,22 @@ func CreateHDPath(account uint32, index uint32) *hd.BIP44Params {
|
||||||
return hd.NewFundraiserParams(account, types.GetConfig().GetCoinType(), index)
|
return hd.NewFundraiserParams(account, types.GetConfig().GetCoinType(), index)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsAlgoSupported returns whether the signing algorithm is supported.
|
// SupportedAlgos returns a list of supported signing algorithms.
|
||||||
//
|
func (kb baseKeybase) SupportedAlgos() []SigningAlgo {
|
||||||
// TODO: Refactor this to be configurable to support interchangeable key signing
|
return kb.options.supportedAlgos
|
||||||
// and addressing.
|
}
|
||||||
// Ref: https://github.com/cosmos/cosmos-sdk/issues/4941
|
|
||||||
func IsAlgoSupported(algo SigningAlgo) bool { return algo == Secp256k1 }
|
// SupportedAlgosLedger returns a list of supported ledger signing algorithms.
|
||||||
|
func (kb baseKeybase) SupportedAlgosLedger() []SigningAlgo {
|
||||||
|
return kb.options.supportedAlgosLedger
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSupportedAlgorithm returns whether the signing algorithm is in the passed-in list of supported algorithms.
|
||||||
|
func IsSupportedAlgorithm(supported []SigningAlgo, algo SigningAlgo) bool {
|
||||||
|
for _, supportedAlgo := range supported {
|
||||||
|
if algo == supportedAlgo {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -38,25 +38,43 @@ func TestCreateAccountInvalidMnemonic(t *testing.T) {
|
||||||
_, err := kb.CreateAccount(
|
_, err := kb.CreateAccount(
|
||||||
"some_account",
|
"some_account",
|
||||||
"malarkey pair crucial catch public canyon evil outer stage ten gym tornado",
|
"malarkey pair crucial catch public canyon evil outer stage ten gym tornado",
|
||||||
"", "", 0, 1)
|
"", "", CreateHDPath(0, 0).String(), Secp256k1)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Equal(t, "Invalid mnemonic", err.Error())
|
assert.Equal(t, "Invalid mnemonic", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateLedgerUnsupportedAlgo(t *testing.T) {
|
func TestCreateLedgerUnsupportedAlgo(t *testing.T) {
|
||||||
kb := NewInMemory()
|
kb := NewInMemory()
|
||||||
|
|
||||||
|
supportedLedgerAlgos := kb.SupportedAlgosLedger()
|
||||||
|
for _, supportedAlgo := range supportedLedgerAlgos {
|
||||||
|
if Ed25519 == supportedAlgo {
|
||||||
|
assert.FailNow(t, "Was not an unsupported algorithm")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_, err := kb.CreateLedger("some_account", Ed25519, "cosmos", 0, 1)
|
_, err := kb.CreateLedger("some_account", Ed25519, "cosmos", 0, 1)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Equal(t, "unsupported signing algo: only secp256k1 is supported", err.Error())
|
assert.Equal(t, "unsupported signing algo", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateLedger(t *testing.T) {
|
func TestCreateLedger(t *testing.T) {
|
||||||
kb := NewInMemory()
|
kb := NewInMemory(WithSupportedAlgosLedger([]SigningAlgo{Secp256k1, Ed25519}))
|
||||||
|
|
||||||
// test_cover and test_unit will result in different answers
|
// test_cover and test_unit will result in different answers
|
||||||
// test_cover does not compile some dependencies so ledger is disabled
|
// test_cover does not compile some dependencies so ledger is disabled
|
||||||
// test_unit may add a ledger mock
|
// test_unit may add a ledger mock
|
||||||
// both cases are acceptable
|
// both cases are acceptable
|
||||||
|
supportedLedgerAlgos := kb.SupportedAlgosLedger()
|
||||||
|
secpSupported := false
|
||||||
|
edSupported := false
|
||||||
|
for _, supportedAlgo := range supportedLedgerAlgos {
|
||||||
|
secpSupported = secpSupported || (supportedAlgo == Secp256k1)
|
||||||
|
edSupported = edSupported || (supportedAlgo == Ed25519)
|
||||||
|
}
|
||||||
|
assert.True(t, secpSupported)
|
||||||
|
assert.True(t, edSupported)
|
||||||
|
|
||||||
ledger, err := kb.CreateLedger("some_account", Secp256k1, "cosmos", 3, 1)
|
ledger, err := kb.CreateLedger("some_account", Secp256k1, "cosmos", 3, 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -92,7 +110,21 @@ func TestCreateLedger(t *testing.T) {
|
||||||
// TestKeyManagement makes sure we can manipulate these keys well
|
// TestKeyManagement makes sure we can manipulate these keys well
|
||||||
func TestKeyManagement(t *testing.T) {
|
func TestKeyManagement(t *testing.T) {
|
||||||
// make the storage with reasonable defaults
|
// make the storage with reasonable defaults
|
||||||
cstore := NewInMemory()
|
cstore := NewInMemory(WithSupportedAlgos([]SigningAlgo{Secp256k1, Sr25519}))
|
||||||
|
|
||||||
|
// Test modified supported algos
|
||||||
|
supportedAlgos := cstore.SupportedAlgos()
|
||||||
|
secpSupported := false
|
||||||
|
edSupported := false
|
||||||
|
srSupported := false
|
||||||
|
for _, supportedAlgo := range supportedAlgos {
|
||||||
|
secpSupported = secpSupported || (supportedAlgo == Secp256k1)
|
||||||
|
edSupported = edSupported || (supportedAlgo == Ed25519)
|
||||||
|
srSupported = srSupported || (supportedAlgo == Sr25519)
|
||||||
|
}
|
||||||
|
assert.True(t, secpSupported)
|
||||||
|
assert.False(t, edSupported)
|
||||||
|
assert.True(t, srSupported)
|
||||||
|
|
||||||
algo := Secp256k1
|
algo := Secp256k1
|
||||||
n1, n2, n3 := "personal", "business", "other"
|
n1, n2, n3 := "personal", "business", "other"
|
||||||
|
@ -152,10 +184,12 @@ func TestKeyManagement(t *testing.T) {
|
||||||
o1 := "offline"
|
o1 := "offline"
|
||||||
priv1 := ed25519.GenPrivKey()
|
priv1 := ed25519.GenPrivKey()
|
||||||
pub1 := priv1.PubKey()
|
pub1 := priv1.PubKey()
|
||||||
i, err = cstore.CreateOffline(o1, pub1)
|
i, err = cstore.CreateOffline(o1, pub1, algo)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
require.Equal(t, pub1, i.GetPubKey())
|
require.Equal(t, pub1, i.GetPubKey())
|
||||||
require.Equal(t, o1, i.GetName())
|
require.Equal(t, o1, i.GetName())
|
||||||
|
iOffline := i.(*offlineInfo)
|
||||||
|
require.Equal(t, algo, iOffline.GetAlgo())
|
||||||
keyS, err = cstore.List()
|
keyS, err = cstore.List()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 2, len(keyS))
|
require.Equal(t, 2, len(keyS))
|
||||||
|
@ -393,7 +427,8 @@ func TestSeedPhrase(t *testing.T) {
|
||||||
|
|
||||||
// let us re-create it from the mnemonic-phrase
|
// let us re-create it from the mnemonic-phrase
|
||||||
params := *hd.NewFundraiserParams(0, sdk.CoinType, 0)
|
params := *hd.NewFundraiserParams(0, sdk.CoinType, 0)
|
||||||
newInfo, err := cstore.Derive(n2, mnemonic, DefaultBIP39Passphrase, p2, params)
|
hdPath := params.String()
|
||||||
|
newInfo, err := cstore.CreateAccount(n2, mnemonic, DefaultBIP39Passphrase, p2, hdPath, Secp256k1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, n2, newInfo.GetName())
|
require.Equal(t, n2, newInfo.GetName())
|
||||||
require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address())
|
require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address())
|
||||||
|
@ -402,7 +437,11 @@ func TestSeedPhrase(t *testing.T) {
|
||||||
|
|
||||||
func ExampleNew() {
|
func ExampleNew() {
|
||||||
// Select the encryption and storage for your cryptostore
|
// Select the encryption and storage for your cryptostore
|
||||||
customKeyGenFunc := func(bz [32]byte) crypto.PrivKey { return secp256k1.PrivKeySecp256k1(bz) }
|
customKeyGenFunc := func(bz []byte, algo SigningAlgo) (crypto.PrivKey, error) {
|
||||||
|
var bzArr [32]byte
|
||||||
|
copy(bzArr[:], bz)
|
||||||
|
return secp256k1.PrivKeySecp256k1(bzArr), nil
|
||||||
|
}
|
||||||
cstore := NewInMemory(WithKeygenFunc(customKeyGenFunc))
|
cstore := NewInMemory(WithKeygenFunc(customKeyGenFunc))
|
||||||
|
|
||||||
sec := Secp256k1
|
sec := Secp256k1
|
||||||
|
|
|
@ -20,7 +20,6 @@ import (
|
||||||
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/input"
|
"github.com/cosmos/cosmos-sdk/client/input"
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/keyerror"
|
"github.com/cosmos/cosmos-sdk/crypto/keys/keyerror"
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/mintkey"
|
"github.com/cosmos/cosmos-sdk/crypto/keys/mintkey"
|
||||||
"github.com/cosmos/cosmos-sdk/types"
|
"github.com/cosmos/cosmos-sdk/types"
|
||||||
|
@ -90,19 +89,10 @@ func (kb keyringKeybase) CreateMnemonic(
|
||||||
// CreateAccount converts a mnemonic to a private key and persists it, encrypted
|
// CreateAccount converts a mnemonic to a private key and persists it, encrypted
|
||||||
// with the given password.
|
// with the given password.
|
||||||
func (kb keyringKeybase) CreateAccount(
|
func (kb keyringKeybase) CreateAccount(
|
||||||
name, mnemonic, bip39Passwd, encryptPasswd string, account, index uint32,
|
name, mnemonic, bip39Passwd, encryptPasswd, hdPath string, algo SigningAlgo,
|
||||||
) (Info, error) {
|
) (Info, error) {
|
||||||
|
|
||||||
return kb.base.CreateAccount(kb, name, mnemonic, bip39Passwd, encryptPasswd, account, index)
|
return kb.base.CreateAccount(kb, name, mnemonic, bip39Passwd, encryptPasswd, hdPath, algo)
|
||||||
}
|
|
||||||
|
|
||||||
// Derive computes a BIP39 seed from th mnemonic and bip39Passphrase. It creates
|
|
||||||
// a private key from the seed using the BIP44 params.
|
|
||||||
func (kb keyringKeybase) Derive(
|
|
||||||
name, mnemonic, bip39Passphrase, encryptPasswd string, params hd.BIP44Params,
|
|
||||||
) (info Info, err error) {
|
|
||||||
|
|
||||||
return kb.base.Derive(kb, name, mnemonic, bip39Passphrase, encryptPasswd, params)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateLedger creates a new locally-stored reference to a Ledger keypair.
|
// CreateLedger creates a new locally-stored reference to a Ledger keypair.
|
||||||
|
@ -116,8 +106,8 @@ func (kb keyringKeybase) CreateLedger(
|
||||||
|
|
||||||
// CreateOffline creates a new reference to an offline keypair. It returns the
|
// CreateOffline creates a new reference to an offline keypair. It returns the
|
||||||
// created key info.
|
// created key info.
|
||||||
func (kb keyringKeybase) CreateOffline(name string, pub tmcrypto.PubKey) (Info, error) {
|
func (kb keyringKeybase) CreateOffline(name string, pub tmcrypto.PubKey, algo SigningAlgo) (Info, error) {
|
||||||
return kb.base.writeOfflineKey(kb, name, pub), nil
|
return kb.base.writeOfflineKey(kb, name, pub, algo), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateMulti creates a new reference to a multisig (offline) keypair. It
|
// CreateMulti creates a new reference to a multisig (offline) keypair. It
|
||||||
|
@ -284,7 +274,7 @@ func (kb keyringKeybase) ExportPubKey(name string) (armor string, err error) {
|
||||||
return "", fmt.Errorf("no key to export with name: %s", name)
|
return "", fmt.Errorf("no key to export with name: %s", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return mintkey.ArmorPubKeyBytes(bz.GetPubKey().Bytes()), nil
|
return mintkey.ArmorPubKeyBytes(bz.GetPubKey().Bytes(), string(bz.GetAlgo())), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Import imports armored private key.
|
// Import imports armored private key.
|
||||||
|
@ -330,7 +320,12 @@ func (kb keyringKeybase) ExportPrivKey(name, decryptPassphrase, encryptPassphras
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return mintkey.EncryptArmorPrivKey(priv, encryptPassphrase), nil
|
info, err := kb.Get(name)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return mintkey.EncryptArmorPrivKey(priv, encryptPassphrase, string(info.GetAlgo())), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImportPrivKey imports a private key in ASCII armor format. An error is returned
|
// ImportPrivKey imports a private key in ASCII armor format. An error is returned
|
||||||
|
@ -341,13 +336,13 @@ func (kb keyringKeybase) ImportPrivKey(name, armor, passphrase string) error {
|
||||||
return fmt.Errorf("cannot overwrite key: %s", name)
|
return fmt.Errorf("cannot overwrite key: %s", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
privKey, err := mintkey.UnarmorDecryptPrivKey(armor, passphrase)
|
privKey, algo, err := mintkey.UnarmorDecryptPrivKey(armor, passphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to decrypt private key")
|
return errors.Wrap(err, "failed to decrypt private key")
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: The keyring keystore has no need for a passphrase.
|
// NOTE: The keyring keystore has no need for a passphrase.
|
||||||
kb.writeLocalKey(name, privKey, "")
|
kb.writeLocalKey(name, privKey, "", SigningAlgo(algo))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,7 +365,7 @@ func (kb keyringKeybase) ImportPubKey(name string, armor string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pubBytes, err := mintkey.UnarmorPubKeyBytes(armor)
|
pubBytes, algo, err := mintkey.UnarmorPubKeyBytes(armor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -380,7 +375,7 @@ func (kb keyringKeybase) ImportPubKey(name string, armor string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
kb.base.writeOfflineKey(kb, name, pubKey)
|
kb.base.writeOfflineKey(kb, name, pubKey, SigningAlgo(algo))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,7 +414,7 @@ func (kb keyringKeybase) Update(name, oldpass string, getNewpass func() (string,
|
||||||
|
|
||||||
switch linfo := info.(type) {
|
switch linfo := info.(type) {
|
||||||
case localInfo:
|
case localInfo:
|
||||||
key, err := mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, oldpass)
|
key, _, err := mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, oldpass)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -429,7 +424,7 @@ func (kb keyringKeybase) Update(name, oldpass string, getNewpass func() (string,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
kb.writeLocalKey(name, key, newpass)
|
kb.writeLocalKey(name, key, newpass, linfo.GetAlgo())
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -437,13 +432,23 @@ func (kb keyringKeybase) Update(name, oldpass string, getNewpass func() (string,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SupportedAlgos returns a list of supported signing algorithms.
|
||||||
|
func (kb keyringKeybase) SupportedAlgos() []SigningAlgo {
|
||||||
|
return kb.base.SupportedAlgos()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SupportedAlgosLedger returns a list of supported ledger signing algorithms.
|
||||||
|
func (kb keyringKeybase) SupportedAlgosLedger() []SigningAlgo {
|
||||||
|
return kb.base.SupportedAlgosLedger()
|
||||||
|
}
|
||||||
|
|
||||||
// CloseDB releases the lock and closes the storage backend.
|
// CloseDB releases the lock and closes the storage backend.
|
||||||
func (kb keyringKeybase) CloseDB() {}
|
func (kb keyringKeybase) CloseDB() {}
|
||||||
|
|
||||||
func (kb keyringKeybase) writeLocalKey(name string, priv tmcrypto.PrivKey, _ string) Info {
|
func (kb keyringKeybase) writeLocalKey(name string, priv tmcrypto.PrivKey, _ string, algo SigningAlgo) Info {
|
||||||
// encrypt private key using keyring
|
// encrypt private key using keyring
|
||||||
pub := priv.PubKey()
|
pub := priv.PubKey()
|
||||||
info := newLocalInfo(name, pub, string(priv.Bytes()))
|
info := newLocalInfo(name, pub, string(priv.Bytes()), algo)
|
||||||
|
|
||||||
kb.writeInfo(name, info)
|
kb.writeInfo(name, info)
|
||||||
return info
|
return info
|
||||||
|
|
|
@ -79,7 +79,7 @@ func TestLazyKeyManagementKeyRing(t *testing.T) {
|
||||||
o1 := "offline"
|
o1 := "offline"
|
||||||
priv1 := ed25519.GenPrivKey()
|
priv1 := ed25519.GenPrivKey()
|
||||||
pub1 := priv1.PubKey()
|
pub1 := priv1.PubKey()
|
||||||
i, err = kb.CreateOffline(o1, pub1)
|
i, err = kb.CreateOffline(o1, pub1, Ed25519)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
require.Equal(t, pub1, i.GetPubKey())
|
require.Equal(t, pub1, i.GetPubKey())
|
||||||
require.Equal(t, o1, i.GetName())
|
require.Equal(t, o1, i.GetName())
|
||||||
|
@ -209,10 +209,11 @@ func TestLazyExportImportPubKeyKeyRing(t *testing.T) {
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
kb, err := NewTestKeyring("keybasename", dir)
|
kb, err := NewTestKeyring("keybasename", dir)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
algo := Secp256k1
|
||||||
|
|
||||||
// CreateMnemonic a private-public key pair and ensure consistency
|
// CreateMnemonic a private-public key pair and ensure consistency
|
||||||
notPasswd := "n9y25ah7"
|
notPasswd := "n9y25ah7"
|
||||||
info, _, err := kb.CreateMnemonic("john", English, notPasswd, Secp256k1)
|
info, _, err := kb.CreateMnemonic("john", English, notPasswd, algo)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
require.NotEqual(t, info, "")
|
require.NotEqual(t, info, "")
|
||||||
require.Equal(t, info.GetName(), "john")
|
require.Equal(t, info.GetName(), "john")
|
||||||
|
@ -318,7 +319,8 @@ func TestLazySeedPhraseKeyRing(t *testing.T) {
|
||||||
|
|
||||||
// let us re-create it from the mnemonic-phrase
|
// let us re-create it from the mnemonic-phrase
|
||||||
params := *hd.NewFundraiserParams(0, sdk.CoinType, 0)
|
params := *hd.NewFundraiserParams(0, sdk.CoinType, 0)
|
||||||
newInfo, err := kb.Derive(n2, mnemonic, DefaultBIP39Passphrase, p2, params)
|
hdPath := params.String()
|
||||||
|
newInfo, err := kb.CreateAccount(n2, mnemonic, DefaultBIP39Passphrase, p2, hdPath, Secp256k1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, n2, newInfo.GetName())
|
require.Equal(t, n2, newInfo.GetName())
|
||||||
require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address())
|
require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address())
|
||||||
|
|
|
@ -4,9 +4,13 @@ package keys
|
||||||
type SigningAlgo string
|
type SigningAlgo string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// MultiAlgo implies that a pubkey is a multisignature
|
||||||
|
MultiAlgo = SigningAlgo("multi")
|
||||||
// Secp256k1 uses the Bitcoin secp256k1 ECDSA parameters.
|
// Secp256k1 uses the Bitcoin secp256k1 ECDSA parameters.
|
||||||
Secp256k1 = SigningAlgo("secp256k1")
|
Secp256k1 = SigningAlgo("secp256k1")
|
||||||
// Ed25519 represents the Ed25519 signature system.
|
// Ed25519 represents the Ed25519 signature system.
|
||||||
// It is currently not supported for end-user keys (wallets/ledgers).
|
// It is currently not supported for end-user keys (wallets/ledgers).
|
||||||
Ed25519 = SigningAlgo("ed25519")
|
Ed25519 = SigningAlgo("ed25519")
|
||||||
|
// Sr25519 represents the Sr25519 signature system.
|
||||||
|
Sr25519 = SigningAlgo("sr25519")
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"github.com/tendermint/tendermint/crypto"
|
"github.com/tendermint/tendermint/crypto"
|
||||||
cmn "github.com/tendermint/tendermint/libs/common"
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -88,7 +87,7 @@ func (lkb lazyKeybase) CreateMnemonic(name string, language Language, passwd str
|
||||||
return newDBKeybase(db, lkb.options...).CreateMnemonic(name, language, passwd, algo)
|
return newDBKeybase(db, lkb.options...).CreateMnemonic(name, language, passwd, algo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lkb lazyKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (Info, error) {
|
func (lkb lazyKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, hdPath string, algo SigningAlgo) (Info, error) {
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -96,17 +95,7 @@ func (lkb lazyKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
return newDBKeybase(db,
|
return newDBKeybase(db,
|
||||||
lkb.options...).CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, account, index)
|
lkb.options...).CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, hdPath, algo)
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) Derive(name, mnemonic, bip39Passwd, encryptPasswd string, params hd.BIP44Params) (Info, error) {
|
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return newDBKeybase(db, lkb.options...).Derive(name, mnemonic, bip39Passwd, encryptPasswd, params)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lkb lazyKeybase) CreateLedger(name string, algo SigningAlgo, hrp string, account, index uint32) (info Info, err error) {
|
func (lkb lazyKeybase) CreateLedger(name string, algo SigningAlgo, hrp string, account, index uint32) (info Info, err error) {
|
||||||
|
@ -119,14 +108,14 @@ func (lkb lazyKeybase) CreateLedger(name string, algo SigningAlgo, hrp string, a
|
||||||
return newDBKeybase(db, lkb.options...).CreateLedger(name, algo, hrp, account, index)
|
return newDBKeybase(db, lkb.options...).CreateLedger(name, algo, hrp, account, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lkb lazyKeybase) CreateOffline(name string, pubkey crypto.PubKey) (info Info, err error) {
|
func (lkb lazyKeybase) CreateOffline(name string, pubkey crypto.PubKey, algo SigningAlgo) (info Info, err error) {
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
return newDBKeybase(db, lkb.options...).CreateOffline(name, pubkey)
|
return newDBKeybase(db, lkb.options...).CreateOffline(name, pubkey, algo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lkb lazyKeybase) CreateMulti(name string, pubkey crypto.PubKey) (info Info, err error) {
|
func (lkb lazyKeybase) CreateMulti(name string, pubkey crypto.PubKey) (info Info, err error) {
|
||||||
|
@ -221,4 +210,14 @@ func (lkb lazyKeybase) ExportPrivKey(name string, decryptPassphrase string,
|
||||||
return newDBKeybase(db, lkb.options...).ExportPrivKey(name, decryptPassphrase, encryptPassphrase)
|
return newDBKeybase(db, lkb.options...).ExportPrivKey(name, decryptPassphrase, encryptPassphrase)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SupportedAlgos returns a list of supported signing algorithms.
|
||||||
|
func (lkb lazyKeybase) SupportedAlgos() []SigningAlgo {
|
||||||
|
return newBaseKeybase(lkb.options...).SupportedAlgos()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SupportedAlgosLedger returns a list of supported ledger signing algorithms.
|
||||||
|
func (lkb lazyKeybase) SupportedAlgosLedger() []SigningAlgo {
|
||||||
|
return newBaseKeybase(lkb.options...).SupportedAlgosLedger()
|
||||||
|
}
|
||||||
|
|
||||||
func (lkb lazyKeybase) CloseDB() {}
|
func (lkb lazyKeybase) CloseDB() {}
|
||||||
|
|
|
@ -89,7 +89,7 @@ func TestLazyKeyManagement(t *testing.T) {
|
||||||
o1 := "offline"
|
o1 := "offline"
|
||||||
priv1 := ed25519.GenPrivKey()
|
priv1 := ed25519.GenPrivKey()
|
||||||
pub1 := priv1.PubKey()
|
pub1 := priv1.PubKey()
|
||||||
i, err = kb.CreateOffline(o1, pub1)
|
i, err = kb.CreateOffline(o1, pub1, algo)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
require.Equal(t, pub1, i.GetPubKey())
|
require.Equal(t, pub1, i.GetPubKey())
|
||||||
require.Equal(t, o1, i.GetName())
|
require.Equal(t, o1, i.GetName())
|
||||||
|
@ -245,10 +245,11 @@ func TestLazyExportImportPubKey(t *testing.T) {
|
||||||
dir, cleanup := tests.NewTestCaseDir(t)
|
dir, cleanup := tests.NewTestCaseDir(t)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
kb := New("keybasename", dir)
|
kb := New("keybasename", dir)
|
||||||
|
algo := Secp256k1
|
||||||
|
|
||||||
// CreateMnemonic a private-public key pair and ensure consistency
|
// CreateMnemonic a private-public key pair and ensure consistency
|
||||||
notPasswd := "n9y25ah7"
|
notPasswd := "n9y25ah7"
|
||||||
info, _, err := kb.CreateMnemonic("john", English, notPasswd, Secp256k1)
|
info, _, err := kb.CreateMnemonic("john", English, notPasswd, algo)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
require.NotEqual(t, info, "")
|
require.NotEqual(t, info, "")
|
||||||
require.Equal(t, info.GetName(), "john")
|
require.Equal(t, info.GetName(), "john")
|
||||||
|
@ -368,7 +369,8 @@ func TestLazySeedPhrase(t *testing.T) {
|
||||||
|
|
||||||
// let us re-create it from the mnemonic-phrase
|
// let us re-create it from the mnemonic-phrase
|
||||||
params := *hd.NewFundraiserParams(0, sdk.CoinType, 0)
|
params := *hd.NewFundraiserParams(0, sdk.CoinType, 0)
|
||||||
newInfo, err := kb.Derive(n2, mnemonic, DefaultBIP39Passphrase, p2, params)
|
hdPath := params.String()
|
||||||
|
newInfo, err := kb.CreateAccount(n2, mnemonic, DefaultBIP39Passphrase, p2, hdPath, algo)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, n2, newInfo.GetName())
|
require.Equal(t, n2, newInfo.GetName())
|
||||||
require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address())
|
require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address())
|
||||||
|
@ -421,9 +423,9 @@ func TestKeygenOverride(t *testing.T) {
|
||||||
CryptoCdc = testCdc
|
CryptoCdc = testCdc
|
||||||
|
|
||||||
overrideCalled := false
|
overrideCalled := false
|
||||||
dummyFunc := func(bz [32]byte) crypto.PrivKey {
|
dummyFunc := func(bz []byte, algo SigningAlgo) (crypto.PrivKey, error) {
|
||||||
overrideCalled = true
|
overrideCalled = true
|
||||||
return testPriv(bz[:])
|
return testPriv(bz[:]), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
kb := New("keybasename", dir, WithKeygenFunc(dummyFunc))
|
kb := New("keybasename", dir, WithKeygenFunc(dummyFunc))
|
||||||
|
|
|
@ -20,6 +20,11 @@ const (
|
||||||
blockTypePrivKey = "TENDERMINT PRIVATE KEY"
|
blockTypePrivKey = "TENDERMINT PRIVATE KEY"
|
||||||
blockTypeKeyInfo = "TENDERMINT KEY INFO"
|
blockTypeKeyInfo = "TENDERMINT KEY INFO"
|
||||||
blockTypePubKey = "TENDERMINT PUBLIC KEY"
|
blockTypePubKey = "TENDERMINT PUBLIC KEY"
|
||||||
|
|
||||||
|
defaultAlgo = "secp256k1"
|
||||||
|
|
||||||
|
headerVersion = "version"
|
||||||
|
headerType = "type"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Make bcrypt security parameter var, so it can be changed within the lcd test
|
// Make bcrypt security parameter var, so it can be changed within the lcd test
|
||||||
|
@ -42,36 +47,58 @@ var BcryptSecurityParameter = 12
|
||||||
|
|
||||||
// Armor the InfoBytes
|
// Armor the InfoBytes
|
||||||
func ArmorInfoBytes(bz []byte) string {
|
func ArmorInfoBytes(bz []byte) string {
|
||||||
return armorBytes(bz, blockTypeKeyInfo)
|
header := map[string]string{
|
||||||
|
headerType: "Info",
|
||||||
|
headerVersion: "0.0.0",
|
||||||
|
}
|
||||||
|
return armor.EncodeArmor(blockTypeKeyInfo, header, bz)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Armor the PubKeyBytes
|
// Armor the PubKeyBytes
|
||||||
func ArmorPubKeyBytes(bz []byte) string {
|
func ArmorPubKeyBytes(bz []byte, algo string) string {
|
||||||
return armorBytes(bz, blockTypePubKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
func armorBytes(bz []byte, blockType string) string {
|
|
||||||
header := map[string]string{
|
header := map[string]string{
|
||||||
"type": "Info",
|
headerVersion: "0.0.1",
|
||||||
"version": "0.0.0",
|
|
||||||
}
|
}
|
||||||
return armor.EncodeArmor(blockType, header, bz)
|
if algo != "" {
|
||||||
|
header[headerType] = algo
|
||||||
|
}
|
||||||
|
return armor.EncodeArmor(blockTypePubKey, header, bz)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
// remove armor
|
// remove armor
|
||||||
|
|
||||||
// Unarmor the InfoBytes
|
// Unarmor the InfoBytes
|
||||||
func UnarmorInfoBytes(armorStr string) (bz []byte, err error) {
|
func UnarmorInfoBytes(armorStr string) ([]byte, error) {
|
||||||
return unarmorBytes(armorStr, blockTypeKeyInfo)
|
bz, header, err := unarmorBytes(armorStr, blockTypeKeyInfo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unarmor the PubKeyBytes
|
if header[headerVersion] != "0.0.0" {
|
||||||
func UnarmorPubKeyBytes(armorStr string) (bz []byte, err error) {
|
return nil, fmt.Errorf("unrecognized version: %v", header[headerVersion])
|
||||||
return unarmorBytes(armorStr, blockTypePubKey)
|
}
|
||||||
|
return bz, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func unarmorBytes(armorStr, blockType string) (bz []byte, err error) {
|
// UnarmorPubKeyBytes returns the pubkey byte slice, a string of the algo type, and an error
|
||||||
|
func UnarmorPubKeyBytes(armorStr string) (bz []byte, algo string, err error) {
|
||||||
|
bz, header, err := unarmorBytes(armorStr, blockTypePubKey)
|
||||||
|
switch header[headerVersion] {
|
||||||
|
case "0.0.0":
|
||||||
|
return bz, defaultAlgo, err
|
||||||
|
case "0.0.1":
|
||||||
|
if header[headerType] == "" {
|
||||||
|
header[headerType] = defaultAlgo
|
||||||
|
}
|
||||||
|
return bz, header[headerType], err
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("unrecognized version: %v", header[headerVersion])
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unarmorBytes(armorStr, blockType string) (bz []byte, header map[string]string, err error) {
|
||||||
bType, header, bz, err := armor.DecodeArmor(armorStr)
|
bType, header, bz, err := armor.DecodeArmor(armorStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -80,10 +107,6 @@ func unarmorBytes(armorStr, blockType string) (bz []byte, err error) {
|
||||||
err = fmt.Errorf("unrecognized armor type %q, expected: %q", bType, blockType)
|
err = fmt.Errorf("unrecognized armor type %q, expected: %q", bType, blockType)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if header["version"] != "0.0.0" {
|
|
||||||
err = fmt.Errorf("unrecognized version: %v", header["version"])
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,12 +114,15 @@ func unarmorBytes(armorStr, blockType string) (bz []byte, err error) {
|
||||||
// encrypt/decrypt with armor
|
// encrypt/decrypt with armor
|
||||||
|
|
||||||
// Encrypt and armor the private key.
|
// Encrypt and armor the private key.
|
||||||
func EncryptArmorPrivKey(privKey crypto.PrivKey, passphrase string) string {
|
func EncryptArmorPrivKey(privKey crypto.PrivKey, passphrase string, algo string) string {
|
||||||
saltBytes, encBytes := encryptPrivKey(privKey, passphrase)
|
saltBytes, encBytes := encryptPrivKey(privKey, passphrase)
|
||||||
header := map[string]string{
|
header := map[string]string{
|
||||||
"kdf": "bcrypt",
|
"kdf": "bcrypt",
|
||||||
"salt": fmt.Sprintf("%X", saltBytes),
|
"salt": fmt.Sprintf("%X", saltBytes),
|
||||||
}
|
}
|
||||||
|
if algo != "" {
|
||||||
|
header[headerType] = algo
|
||||||
|
}
|
||||||
armorStr := armor.EncodeArmor(blockTypePrivKey, header, encBytes)
|
armorStr := armor.EncodeArmor(blockTypePrivKey, header, encBytes)
|
||||||
return armorStr
|
return armorStr
|
||||||
}
|
}
|
||||||
|
@ -115,28 +141,31 @@ func encryptPrivKey(privKey crypto.PrivKey, passphrase string) (saltBytes []byte
|
||||||
return saltBytes, xsalsa20symmetric.EncryptSymmetric(privKeyBytes, key)
|
return saltBytes, xsalsa20symmetric.EncryptSymmetric(privKeyBytes, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unarmor and decrypt the private key.
|
// UnarmorDecryptPrivKey returns the privkey byte slice, a string of the algo type, and an error
|
||||||
func UnarmorDecryptPrivKey(armorStr string, passphrase string) (crypto.PrivKey, error) {
|
func UnarmorDecryptPrivKey(armorStr string, passphrase string) (privKey crypto.PrivKey, algo string, err error) {
|
||||||
var privKey crypto.PrivKey
|
|
||||||
blockType, header, encBytes, err := armor.DecodeArmor(armorStr)
|
blockType, header, encBytes, err := armor.DecodeArmor(armorStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return privKey, err
|
return privKey, "", err
|
||||||
}
|
}
|
||||||
if blockType != blockTypePrivKey {
|
if blockType != blockTypePrivKey {
|
||||||
return privKey, fmt.Errorf("unrecognized armor type: %v", blockType)
|
return privKey, "", fmt.Errorf("unrecognized armor type: %v", blockType)
|
||||||
}
|
}
|
||||||
if header["kdf"] != "bcrypt" {
|
if header["kdf"] != "bcrypt" {
|
||||||
return privKey, fmt.Errorf("unrecognized KDF type: %v", header["KDF"])
|
return privKey, "", fmt.Errorf("unrecognized KDF type: %v", header["KDF"])
|
||||||
}
|
}
|
||||||
if header["salt"] == "" {
|
if header["salt"] == "" {
|
||||||
return privKey, fmt.Errorf("missing salt bytes")
|
return privKey, "", fmt.Errorf("missing salt bytes")
|
||||||
}
|
}
|
||||||
saltBytes, err := hex.DecodeString(header["salt"])
|
saltBytes, err := hex.DecodeString(header["salt"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return privKey, fmt.Errorf("error decoding salt: %v", err.Error())
|
return privKey, "", fmt.Errorf("error decoding salt: %v", err.Error())
|
||||||
}
|
}
|
||||||
privKey, err = decryptPrivKey(saltBytes, encBytes, passphrase)
|
privKey, err = decryptPrivKey(saltBytes, encBytes, passphrase)
|
||||||
return privKey, err
|
|
||||||
|
if header[headerType] == "" {
|
||||||
|
header[headerType] = defaultAlgo
|
||||||
|
}
|
||||||
|
return privKey, header[headerType], err
|
||||||
}
|
}
|
||||||
|
|
||||||
func decryptPrivKey(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) {
|
func decryptPrivKey(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) {
|
||||||
|
|
|
@ -13,11 +13,12 @@ import (
|
||||||
|
|
||||||
func TestArmorUnarmorPrivKey(t *testing.T) {
|
func TestArmorUnarmorPrivKey(t *testing.T) {
|
||||||
priv := secp256k1.GenPrivKey()
|
priv := secp256k1.GenPrivKey()
|
||||||
armor := mintkey.EncryptArmorPrivKey(priv, "passphrase")
|
armor := mintkey.EncryptArmorPrivKey(priv, "passphrase", "")
|
||||||
_, err := mintkey.UnarmorDecryptPrivKey(armor, "wrongpassphrase")
|
_, _, err := mintkey.UnarmorDecryptPrivKey(armor, "wrongpassphrase")
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
decrypted, err := mintkey.UnarmorDecryptPrivKey(armor, "passphrase")
|
decrypted, algo, err := mintkey.UnarmorDecryptPrivKey(armor, "passphrase")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, string(keys.Secp256k1), algo)
|
||||||
require.True(t, priv.Equals(decrypted))
|
require.True(t, priv.Equals(decrypted))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,10 +29,11 @@ func TestArmorUnarmorPubKey(t *testing.T) {
|
||||||
// Add keys and see they return in alphabetical order
|
// Add keys and see they return in alphabetical order
|
||||||
info, _, err := cstore.CreateMnemonic("Bob", keys.English, "passphrase", keys.Secp256k1)
|
info, _, err := cstore.CreateMnemonic("Bob", keys.English, "passphrase", keys.Secp256k1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
armor := mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes())
|
armor := mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes(), "")
|
||||||
pubBytes, err := mintkey.UnarmorPubKeyBytes(armor)
|
pubBytes, algo, err := mintkey.UnarmorPubKeyBytes(armor)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
pub, err := cryptoAmino.PubKeyFromBytes(pubBytes)
|
pub, err := cryptoAmino.PubKeyFromBytes(pubBytes)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, string(keys.Secp256k1), algo)
|
||||||
require.True(t, pub.Equals(info.GetPubKey()))
|
require.True(t, pub.Equals(info.GetPubKey()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,21 +31,15 @@ type Keybase interface {
|
||||||
// same name.
|
// same name.
|
||||||
CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, seed string, err error)
|
CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, seed string, err error)
|
||||||
|
|
||||||
// CreateAccount converts a mnemonic to a private key using a BIP44 path 44'/118'/{account}'/0/{index}
|
// CreateAccount converts a mnemonic to a private key and BIP 32 HD Path
|
||||||
// and persists it, encrypted with the given password.
|
// and persists it, encrypted with the given password.
|
||||||
CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (Info, error)
|
CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, hdPath string, algo SigningAlgo) (Info, error)
|
||||||
|
|
||||||
// Derive computes a BIP39 seed from th mnemonic and bip39Passwd.
|
|
||||||
// Derive private key from the seed using the BIP44 params.
|
|
||||||
// Encrypt the key to disk using encryptPasswd.
|
|
||||||
// See https://github.com/cosmos/cosmos-sdk/issues/2095
|
|
||||||
Derive(name, mnemonic, bip39Passwd, encryptPasswd string, params hd.BIP44Params) (Info, error)
|
|
||||||
|
|
||||||
// CreateLedger creates, stores, and returns a new Ledger key reference
|
// CreateLedger creates, stores, and returns a new Ledger key reference
|
||||||
CreateLedger(name string, algo SigningAlgo, hrp string, account, index uint32) (info Info, err error)
|
CreateLedger(name string, algo SigningAlgo, hrp string, account, index uint32) (info Info, err error)
|
||||||
|
|
||||||
// CreateOffline creates, stores, and returns a new offline key reference
|
// CreateOffline creates, stores, and returns a new offline key reference
|
||||||
CreateOffline(name string, pubkey crypto.PubKey) (info Info, err error)
|
CreateOffline(name string, pubkey crypto.PubKey, algo SigningAlgo) (info Info, err error)
|
||||||
|
|
||||||
// CreateMulti creates, stores, and returns a new multsig (offline) key reference
|
// CreateMulti creates, stores, and returns a new multsig (offline) key reference
|
||||||
CreateMulti(name string, pubkey crypto.PubKey) (info Info, err error)
|
CreateMulti(name string, pubkey crypto.PubKey) (info Info, err error)
|
||||||
|
@ -81,6 +75,12 @@ type Keybase interface {
|
||||||
// ExportPrivateKeyObject *only* works on locally-stored keys. Temporary method until we redo the exporting API
|
// ExportPrivateKeyObject *only* works on locally-stored keys. Temporary method until we redo the exporting API
|
||||||
ExportPrivateKeyObject(name string, passphrase string) (crypto.PrivKey, error)
|
ExportPrivateKeyObject(name string, passphrase string) (crypto.PrivKey, error)
|
||||||
|
|
||||||
|
// SupportedAlgos returns a list of signing algorithms supported by the keybase
|
||||||
|
SupportedAlgos() []SigningAlgo
|
||||||
|
|
||||||
|
// SupportedAlgosLedger returns a list of signing algorithms supported by the keybase's ledger integration
|
||||||
|
SupportedAlgosLedger() []SigningAlgo
|
||||||
|
|
||||||
// CloseDB closes the database.
|
// CloseDB closes the database.
|
||||||
CloseDB()
|
CloseDB()
|
||||||
}
|
}
|
||||||
|
@ -118,6 +118,8 @@ type Info interface {
|
||||||
GetPubKey() crypto.PubKey
|
GetPubKey() crypto.PubKey
|
||||||
// Address
|
// Address
|
||||||
GetAddress() types.AccAddress
|
GetAddress() types.AccAddress
|
||||||
|
// Algo
|
||||||
|
GetAlgo() SigningAlgo
|
||||||
// Bip44 Path
|
// Bip44 Path
|
||||||
GetPath() (*hd.BIP44Params, error)
|
GetPath() (*hd.BIP44Params, error)
|
||||||
}
|
}
|
||||||
|
@ -132,15 +134,17 @@ var (
|
||||||
// localInfo is the public information about a locally stored key
|
// localInfo is the public information about a locally stored key
|
||||||
type localInfo struct {
|
type localInfo struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
Algo SigningAlgo `json:"algo"`
|
||||||
PubKey crypto.PubKey `json:"pubkey"`
|
PubKey crypto.PubKey `json:"pubkey"`
|
||||||
PrivKeyArmor string `json:"privkey.armor"`
|
PrivKeyArmor string `json:"privkey.armor"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func newLocalInfo(name string, pub crypto.PubKey, privArmor string) Info {
|
func newLocalInfo(name string, pub crypto.PubKey, privArmor string, algo SigningAlgo) Info {
|
||||||
return &localInfo{
|
return &localInfo{
|
||||||
Name: name,
|
Name: name,
|
||||||
PubKey: pub,
|
PubKey: pub,
|
||||||
PrivKeyArmor: privArmor,
|
PrivKeyArmor: privArmor,
|
||||||
|
Algo: algo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,6 +168,11 @@ func (i localInfo) GetAddress() types.AccAddress {
|
||||||
return i.PubKey.Address().Bytes()
|
return i.PubKey.Address().Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetType implements Info interface
|
||||||
|
func (i localInfo) GetAlgo() SigningAlgo {
|
||||||
|
return i.Algo
|
||||||
|
}
|
||||||
|
|
||||||
// GetType implements Info interface
|
// GetType implements Info interface
|
||||||
func (i localInfo) GetPath() (*hd.BIP44Params, error) {
|
func (i localInfo) GetPath() (*hd.BIP44Params, error) {
|
||||||
return nil, fmt.Errorf("BIP44 Paths are not available for this type")
|
return nil, fmt.Errorf("BIP44 Paths are not available for this type")
|
||||||
|
@ -174,13 +183,15 @@ type ledgerInfo struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
PubKey crypto.PubKey `json:"pubkey"`
|
PubKey crypto.PubKey `json:"pubkey"`
|
||||||
Path hd.BIP44Params `json:"path"`
|
Path hd.BIP44Params `json:"path"`
|
||||||
|
Algo SigningAlgo `json:"algo"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func newLedgerInfo(name string, pub crypto.PubKey, path hd.BIP44Params) Info {
|
func newLedgerInfo(name string, pub crypto.PubKey, path hd.BIP44Params, algo SigningAlgo) Info {
|
||||||
return &ledgerInfo{
|
return &ledgerInfo{
|
||||||
Name: name,
|
Name: name,
|
||||||
PubKey: pub,
|
PubKey: pub,
|
||||||
Path: path,
|
Path: path,
|
||||||
|
Algo: algo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,6 +215,11 @@ func (i ledgerInfo) GetAddress() types.AccAddress {
|
||||||
return i.PubKey.Address().Bytes()
|
return i.PubKey.Address().Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPath implements Info interface
|
||||||
|
func (i ledgerInfo) GetAlgo() SigningAlgo {
|
||||||
|
return i.Algo
|
||||||
|
}
|
||||||
|
|
||||||
// GetPath implements Info interface
|
// GetPath implements Info interface
|
||||||
func (i ledgerInfo) GetPath() (*hd.BIP44Params, error) {
|
func (i ledgerInfo) GetPath() (*hd.BIP44Params, error) {
|
||||||
tmp := i.Path
|
tmp := i.Path
|
||||||
|
@ -213,13 +229,15 @@ func (i ledgerInfo) GetPath() (*hd.BIP44Params, error) {
|
||||||
// offlineInfo is the public information about an offline key
|
// offlineInfo is the public information about an offline key
|
||||||
type offlineInfo struct {
|
type offlineInfo struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
Algo SigningAlgo `json:"algo"`
|
||||||
PubKey crypto.PubKey `json:"pubkey"`
|
PubKey crypto.PubKey `json:"pubkey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func newOfflineInfo(name string, pub crypto.PubKey) Info {
|
func newOfflineInfo(name string, pub crypto.PubKey, algo SigningAlgo) Info {
|
||||||
return &offlineInfo{
|
return &offlineInfo{
|
||||||
Name: name,
|
Name: name,
|
||||||
PubKey: pub,
|
PubKey: pub,
|
||||||
|
Algo: algo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,6 +256,11 @@ func (i offlineInfo) GetPubKey() crypto.PubKey {
|
||||||
return i.PubKey
|
return i.PubKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAlgo returns the signing algorithm for the key
|
||||||
|
func (i offlineInfo) GetAlgo() SigningAlgo {
|
||||||
|
return i.Algo
|
||||||
|
}
|
||||||
|
|
||||||
// GetAddress implements Info interface
|
// GetAddress implements Info interface
|
||||||
func (i offlineInfo) GetAddress() types.AccAddress {
|
func (i offlineInfo) GetAddress() types.AccAddress {
|
||||||
return i.PubKey.Address().Bytes()
|
return i.PubKey.Address().Bytes()
|
||||||
|
@ -299,6 +322,11 @@ func (i multiInfo) GetAddress() types.AccAddress {
|
||||||
return i.PubKey.Address().Bytes()
|
return i.PubKey.Address().Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPath implements Info interface
|
||||||
|
func (i multiInfo) GetAlgo() SigningAlgo {
|
||||||
|
return MultiAlgo
|
||||||
|
}
|
||||||
|
|
||||||
// GetPath implements Info interface
|
// GetPath implements Info interface
|
||||||
func (i multiInfo) GetPath() (*hd.BIP44Params, error) {
|
func (i multiInfo) GetPath() (*hd.BIP44Params, error) {
|
||||||
return nil, fmt.Errorf("BIP44 Paths are not available for this type")
|
return nil, fmt.Errorf("BIP44 Paths are not available for this type")
|
||||||
|
@ -316,8 +344,10 @@ func unmarshalInfo(bz []byte) (info Info, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
// DeriveKeyFunc defines the function to derive a new key from a seed and hd path
|
||||||
|
DeriveKeyFunc func(mnemonic string, bip39Passphrase, hdPath string, algo SigningAlgo) ([]byte, error)
|
||||||
// PrivKeyGenFunc defines the function to convert derived key bytes to a tendermint private key
|
// PrivKeyGenFunc defines the function to convert derived key bytes to a tendermint private key
|
||||||
PrivKeyGenFunc func(bz [32]byte) crypto.PrivKey
|
PrivKeyGenFunc func(bz []byte, algo SigningAlgo) (crypto.PrivKey, error)
|
||||||
|
|
||||||
// KeybaseOption overrides options for the db
|
// KeybaseOption overrides options for the db
|
||||||
KeybaseOption func(*kbOptions)
|
KeybaseOption func(*kbOptions)
|
||||||
|
|
|
@ -17,7 +17,7 @@ func Test_writeReadLedgerInfo(t *testing.T) {
|
||||||
bz, _ := hex.DecodeString("035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A")
|
bz, _ := hex.DecodeString("035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A")
|
||||||
copy(tmpKey[:], bz)
|
copy(tmpKey[:], bz)
|
||||||
|
|
||||||
lInfo := newLedgerInfo("some_name", tmpKey, *hd.NewFundraiserParams(5, types.CoinType, 1))
|
lInfo := newLedgerInfo("some_name", tmpKey, *hd.NewFundraiserParams(5, types.CoinType, 1), Secp256k1)
|
||||||
assert.Equal(t, TypeLedger, lInfo.GetType())
|
assert.Equal(t, TypeLedger, lInfo.GetType())
|
||||||
|
|
||||||
path, err := lInfo.GetPath()
|
path, err := lInfo.GetPath()
|
||||||
|
|
|
@ -17,7 +17,7 @@ func TestGenerateCoinKey(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Test creation
|
// Test creation
|
||||||
info, err := keys.NewInMemoryKeyBase().CreateAccount("xxx", mnemonic, "", "012345678", 0, 0)
|
info, err := keys.NewInMemoryKeyBase().CreateAccount("xxx", mnemonic, "", "012345678", crkeys.CreateHDPath(0, 0).String(), crkeys.Secp256k1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, addr, info.GetAddress())
|
require.Equal(t, addr, info.GetAddress())
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ func TestGenerateSaveCoinKey(t *testing.T) {
|
||||||
require.Equal(t, addr, info.GetAddress())
|
require.Equal(t, addr, info.GetAddress())
|
||||||
|
|
||||||
// Test in-memory recovery
|
// Test in-memory recovery
|
||||||
info, err = keys.NewInMemoryKeyBase().CreateAccount("xxx", mnemonic, "", "012345678", 0, 0)
|
info, err = keys.NewInMemoryKeyBase().CreateAccount("xxx", mnemonic, "", "012345678", crkeys.CreateHDPath(0, 0).String(), crkeys.Secp256k1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, addr, info.GetAddress())
|
require.Equal(t, addr, info.GetAddress())
|
||||||
}
|
}
|
||||||
|
|
|
@ -312,7 +312,7 @@ func DefaultSigVerificationGasConsumer(
|
||||||
var multisignature multisig.Multisignature
|
var multisignature multisig.Multisignature
|
||||||
codec.Cdc.MustUnmarshalBinaryBare(sig, &multisignature)
|
codec.Cdc.MustUnmarshalBinaryBare(sig, &multisignature)
|
||||||
|
|
||||||
consumeMultisignatureVerificationGas(meter, multisignature, pubkey, params)
|
ConsumeMultisignatureVerificationGas(meter, multisignature, pubkey, params)
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -320,7 +320,8 @@ func DefaultSigVerificationGasConsumer(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func consumeMultisignatureVerificationGas(meter sdk.GasMeter,
|
// ConsumeMultisignatureVerificationGas consumes gas from a GasMeter for verifying a multisig pubkey signature
|
||||||
|
func ConsumeMultisignatureVerificationGas(meter sdk.GasMeter,
|
||||||
sig multisig.Multisignature, pubkey multisig.PubKeyMultisigThreshold,
|
sig multisig.Multisignature, pubkey multisig.PubKeyMultisigThreshold,
|
||||||
params types.Params) {
|
params types.Params) {
|
||||||
size := sig.BitArray.Size()
|
size := sig.BitArray.Size()
|
||||||
|
|
Loading…
Reference in New Issue