Merge PR #5439: Keybase: Multiple Signature Algorithms
This commit is contained in:
parent
d452e9398b
commit
f367087731
18
CHANGELOG.md
18
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`
|
||||
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.
|
||||
* 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.
|
||||
* (baseapp) [\#5455](https://github.com/cosmos/cosmos-sdk/issues/5455) An `sdk.Context` is passed into the `router.Route()`
|
||||
function.
|
||||
|
@ -177,10 +186,13 @@ that allows for arbitrary vesting periods.
|
|||
* `IncrementSequenceDecorator`: Increments the account sequence for each signer to prevent replay attacks.
|
||||
* (cli) [\#5223](https://github.com/cosmos/cosmos-sdk/issues/5223) Cosmos Ledger App v2.0.0 is now supported. The changes are backwards compatible and App v1.5.x is still supported.
|
||||
* (x/staking) [\#5380](https://github.com/cosmos/cosmos-sdk/pull/5380) Introduced ability to store historical info entries in staking keeper, allows applications to introspect specified number of past headers and validator sets
|
||||
* Introduces new parameter `HistoricalEntries` which allows applications to determine how many recent historical info entries they want to persist in store. Default value is 0.
|
||||
* Introduces cli commands and rest routes to query historical information at a given height
|
||||
* Introduces new parameter `HistoricalEntries` which allows applications to determine how many recent historical info entries they want to persist in store. Default value is 0.
|
||||
* 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).
|
||||
* (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.
|
||||
* An `ApproxSqrt` function was also added for convenience around the common case of n=2.
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ const (
|
|||
flagIndex = "index"
|
||||
flagMultisig = "multisig"
|
||||
flagNoSort = "nosort"
|
||||
flagHDPath = "hd-path"
|
||||
flagKeyAlgo = "algo"
|
||||
|
||||
// DefaultKeyPass contains the default key password for genesis transactions
|
||||
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(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().String(flagHDPath, "", "Manual HD Path derivation (overrides BIP44 config)")
|
||||
cmd.Flags().Uint32(flagAccount, 0, "Account 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().String(flagKeyAlgo, string(keys.Secp256k1), "Key signing algorithm to generate keys for")
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
@ -112,6 +116,14 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keys.Keybase, inBuf *bufio.
|
|||
interactive := viper.GetBool(flagInteractive)
|
||||
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) {
|
||||
_, err = kb.Get(name)
|
||||
if err == nil {
|
||||
|
@ -164,7 +176,7 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keys.Keybase, inBuf *bufio.
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = kb.CreateOffline(name, pk)
|
||||
_, err = kb.CreateOffline(name, pk, algo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -174,8 +186,26 @@ func RunAddCmd(cmd *cobra.Command, args []string, kb keys.Keybase, inBuf *bufio.
|
|||
account := uint32(viper.GetInt(flagAccount))
|
||||
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 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()
|
||||
info, err := kb.CreateLedger(name, keys.Secp256k1, bech32PrefixAccAddr, account, index)
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/cosmos/cosmos-sdk/tests"
|
||||
)
|
||||
|
||||
|
@ -44,13 +45,13 @@ func Test_runDeleteCmd(t *testing.T) {
|
|||
if runningUnattended {
|
||||
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)
|
||||
|
||||
if runningUnattended {
|
||||
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)
|
||||
|
||||
if runningUnattended {
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/cosmos/cosmos-sdk/tests"
|
||||
)
|
||||
|
||||
|
@ -32,7 +33,7 @@ func Test_runExportCmd(t *testing.T) {
|
|||
if runningUnattended {
|
||||
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)
|
||||
|
||||
// Now enter password
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/cosmos/cosmos-sdk/tests"
|
||||
)
|
||||
|
||||
|
@ -36,7 +37,7 @@ func Test_runListCmd(t *testing.T) {
|
|||
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)
|
||||
|
||||
defer func() {
|
||||
|
|
|
@ -58,13 +58,13 @@ func Test_runShowCmd(t *testing.T) {
|
|||
if runningUnattended {
|
||||
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)
|
||||
|
||||
if runningUnattended {
|
||||
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)
|
||||
|
||||
// Now try single key
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/cosmos/cosmos-sdk/tests"
|
||||
)
|
||||
|
||||
|
@ -38,9 +39,9 @@ func Test_runUpdateCmd(t *testing.T) {
|
|||
|
||||
kb, err := NewKeyBaseFromHomeFlag()
|
||||
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)
|
||||
_, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", 0, 1)
|
||||
_, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", "1", keys.Secp256k1)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Try again now that we have keys
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
||||
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/mintkey"
|
||||
"github.com/cosmos/cosmos-sdk/types"
|
||||
|
@ -57,7 +56,7 @@ const (
|
|||
var (
|
||||
// ErrUnsupportedSigningAlgo is raised when the caller tries to use a
|
||||
// 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
|
||||
// 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
|
||||
// with the given password.
|
||||
func (kb dbKeybase) CreateAccount(
|
||||
name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32,
|
||||
name, mnemonic, bip39Passwd, encryptPasswd, hdPath string, algo SigningAlgo,
|
||||
) (Info, error) {
|
||||
|
||||
return kb.base.CreateAccount(kb, name, mnemonic, bip39Passwd, encryptPasswd, account, index)
|
||||
}
|
||||
|
||||
// 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)
|
||||
return kb.base.CreateAccount(kb, name, mnemonic, bip39Passwd, encryptPasswd, hdPath, algo)
|
||||
}
|
||||
|
||||
// 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
|
||||
// created key info.
|
||||
func (kb dbKeybase) CreateOffline(name string, pub tmcrypto.PubKey) (Info, error) {
|
||||
return kb.base.writeOfflineKey(kb, name, pub), nil
|
||||
func (kb dbKeybase) CreateOffline(name string, pub tmcrypto.PubKey, algo SigningAlgo) (Info, error) {
|
||||
return kb.base.writeOfflineKey(kb, name, pub, algo), nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
priv, err = mintkey.UnarmorDecryptPrivKey(i.PrivKeyArmor, passphrase)
|
||||
priv, _, err = mintkey.UnarmorDecryptPrivKey(i.PrivKeyArmor, passphrase)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -238,7 +229,7 @@ func (kb dbKeybase) ExportPrivateKeyObject(name string, passphrase string) (tmcr
|
|||
return nil, err
|
||||
}
|
||||
|
||||
priv, err = mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase)
|
||||
priv, _, err = mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -272,7 +263,7 @@ func (kb dbKeybase) ExportPubKey(name string) (armor string, err error) {
|
|||
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.
|
||||
|
@ -285,7 +276,12 @@ func (kb dbKeybase) ExportPrivKey(name string, decryptPassphrase string,
|
|||
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
|
||||
|
@ -296,12 +292,12 @@ func (kb dbKeybase) ImportPrivKey(name string, armor string, passphrase string)
|
|||
return errors.New("Cannot overwrite key " + name)
|
||||
}
|
||||
|
||||
privKey, err := mintkey.UnarmorDecryptPrivKey(armor, passphrase)
|
||||
privKey, algo, err := mintkey.UnarmorDecryptPrivKey(armor, passphrase)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "couldn't import private key")
|
||||
}
|
||||
|
||||
kb.writeLocalKey(name, privKey, passphrase)
|
||||
kb.writeLocalKey(name, privKey, passphrase, SigningAlgo(algo))
|
||||
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)
|
||||
}
|
||||
|
||||
pubBytes, err := mintkey.UnarmorPubKeyBytes(armor)
|
||||
pubBytes, algo, err := mintkey.UnarmorPubKeyBytes(armor)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -339,7 +335,7 @@ func (kb dbKeybase) ImportPubKey(name string, armor string) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
kb.base.writeOfflineKey(kb, name, pubKey)
|
||||
kb.base.writeOfflineKey(kb, name, pubKey, SigningAlgo(algo))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -355,7 +351,7 @@ func (kb dbKeybase) Delete(name, passphrase string, skipPass bool) error {
|
|||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -382,7 +378,7 @@ func (kb dbKeybase) Update(name, oldpass string, getNewpass func() (string, erro
|
|||
case localInfo:
|
||||
linfo := i
|
||||
|
||||
key, err := mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, oldpass)
|
||||
key, _, err := mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, oldpass)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -392,7 +388,7 @@ func (kb dbKeybase) Update(name, oldpass string, getNewpass func() (string, erro
|
|||
return err
|
||||
}
|
||||
|
||||
kb.writeLocalKey(name, key, newpass)
|
||||
kb.writeLocalKey(name, key, newpass, i.GetAlgo())
|
||||
return nil
|
||||
|
||||
default:
|
||||
|
@ -405,13 +401,23 @@ func (kb dbKeybase) CloseDB() {
|
|||
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
|
||||
privArmor := mintkey.EncryptArmorPrivKey(priv, passphrase)
|
||||
privArmor := mintkey.EncryptArmorPrivKey(priv, passphrase, string(algo))
|
||||
|
||||
// make Info
|
||||
pub := priv.PubKey()
|
||||
info := newLocalInfo(name, pub, privArmor)
|
||||
info := newLocalInfo(name, pub, privArmor, algo)
|
||||
|
||||
kb.writeInfo(name, info)
|
||||
return info
|
||||
|
|
|
@ -17,7 +17,10 @@ import (
|
|||
|
||||
type (
|
||||
kbOptions struct {
|
||||
keygenFunc PrivKeyGenFunc
|
||||
keygenFunc PrivKeyGenFunc
|
||||
deriveFunc DeriveKeyFunc
|
||||
supportedAlgos []SigningAlgo
|
||||
supportedAlgosLedger []SigningAlgo
|
||||
}
|
||||
|
||||
// baseKeybase is an auxiliary type that groups Keybase storage agnostic features
|
||||
|
@ -32,7 +35,7 @@ type (
|
|||
}
|
||||
|
||||
writeLocalKeyer interface {
|
||||
writeLocalKey(name string, priv tmcrypto.PrivKey, passphrase string) Info
|
||||
writeLocalKey(name string, priv tmcrypto.PrivKey, passphrase string, algo SigningAlgo) Info
|
||||
}
|
||||
|
||||
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
|
||||
func newBaseKeybase(optionsFns ...KeybaseOption) baseKeybase {
|
||||
// Default options for keybase
|
||||
options := kbOptions{keygenFunc: baseSecpPrivKeyGen}
|
||||
options := kbOptions{
|
||||
keygenFunc: StdPrivKeyGen,
|
||||
deriveFunc: StdDeriveKey,
|
||||
supportedAlgos: []SigningAlgo{Secp256k1},
|
||||
supportedAlgosLedger: []SigningAlgo{Secp256k1},
|
||||
}
|
||||
|
||||
for _, optionFn := range optionsFns {
|
||||
optionFn(&options)
|
||||
|
@ -59,9 +88,20 @@ func newBaseKeybase(optionsFns ...KeybaseOption) baseKeybase {
|
|||
return baseKeybase{options: options}
|
||||
}
|
||||
|
||||
// baseSecpPrivKeyGen generates a secp256k1 private key from the given bytes
|
||||
func baseSecpPrivKeyGen(bz [32]byte) tmcrypto.PrivKey {
|
||||
return secp256k1.PrivKeySecp256k1(bz)
|
||||
// StdPrivKeyGen is the default PrivKeyGen function in the keybase.
|
||||
// For now, it only supports Secp256k1
|
||||
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
|
||||
|
@ -111,29 +151,26 @@ func (kb baseKeybase) DecodeSignature(info Info, msg []byte) (sig []byte, pub tm
|
|||
|
||||
// CreateAccount creates an account Info object.
|
||||
func (kb baseKeybase) CreateAccount(
|
||||
keyWriter keyWriter, name, mnemonic, bip39Passwd, encryptPasswd string, account, index uint32,
|
||||
) (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,
|
||||
keyWriter keyWriter, name, mnemonic, bip39Passphrase, encryptPasswd, hdPath string, algo SigningAlgo,
|
||||
) (Info, error) {
|
||||
|
||||
// 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 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var info Info
|
||||
|
||||
if passwd != "" {
|
||||
info = keyWriter.writeLocalKey(name, kb.options.keygenFunc(derivedPriv), passwd)
|
||||
if encryptPasswd != "" {
|
||||
info = keyWriter.writeLocalKey(name, privKey, encryptPasswd, algo)
|
||||
} else {
|
||||
info = kb.writeOfflineKey(keyWriter, name, kb.options.keygenFunc(derivedPriv).PubKey())
|
||||
info = kb.writeOfflineKey(keyWriter, name, privKey.PubKey(), algo)
|
||||
}
|
||||
|
||||
return info, nil
|
||||
|
@ -145,7 +182,7 @@ func (kb baseKeybase) CreateLedger(
|
|||
w infoWriter, name string, algo SigningAlgo, hrp string, account, index uint32,
|
||||
) (Info, error) {
|
||||
|
||||
if !IsAlgoSupported(algo) {
|
||||
if !IsSupportedAlgorithm(kb.SupportedAlgosLedger(), algo) {
|
||||
return nil, ErrUnsupportedSigningAlgo
|
||||
}
|
||||
|
||||
|
@ -157,7 +194,7 @@ func (kb baseKeybase) CreateLedger(
|
|||
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.
|
||||
|
@ -169,7 +206,7 @@ func (kb baseKeybase) CreateMnemonic(
|
|||
return nil, "", ErrUnsupportedLanguage
|
||||
}
|
||||
|
||||
if !IsAlgoSupported(algo) {
|
||||
if !IsSupportedAlgorithm(kb.SupportedAlgos(), algo) {
|
||||
return nil, "", ErrUnsupportedSigningAlgo
|
||||
}
|
||||
|
||||
|
@ -185,37 +222,22 @@ func (kb baseKeybase) CreateMnemonic(
|
|||
return nil, "", err
|
||||
}
|
||||
|
||||
info, err = kb.persistDerivedKey(
|
||||
keyWriter,
|
||||
bip39.NewSeed(mnemonic, DefaultBIP39Passphrase), passwd,
|
||||
name, types.GetConfig().GetFullFundraiserPath(),
|
||||
)
|
||||
info, err = kb.CreateAccount(keyWriter, name, mnemonic, DefaultBIP39Passphrase, passwd, types.GetConfig().GetFullFundraiserPath(), algo)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
return info, mnemonic, err
|
||||
}
|
||||
|
||||
// Derive computes a BIP39 seed from the mnemonic and bip39Passphrase. It creates
|
||||
// a private key from the seed using the BIP44 params.
|
||||
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)
|
||||
func (kb baseKeybase) writeLedgerKey(w infoWriter, name string, pub tmcrypto.PubKey, path hd.BIP44Params, algo SigningAlgo) Info {
|
||||
info := newLedgerInfo(name, pub, path, algo)
|
||||
w.writeInfo(name, info)
|
||||
return info
|
||||
}
|
||||
|
||||
func (kb baseKeybase) writeOfflineKey(w infoWriter, name string, pub tmcrypto.PubKey) Info {
|
||||
info := newOfflineInfo(name, pub)
|
||||
func (kb baseKeybase) writeOfflineKey(w infoWriter, name string, pub tmcrypto.PubKey, algo SigningAlgo) Info {
|
||||
info := newOfflineInfo(name, pub, algo)
|
||||
w.writeInfo(name, info)
|
||||
return info
|
||||
}
|
||||
|
@ -226,10 +248,28 @@ func (kb baseKeybase) writeMultisigKey(w infoWriter, name string, pub tmcrypto.P
|
|||
return info
|
||||
}
|
||||
|
||||
// ComputeDerivedKey derives and returns the private key for the given seed and HD path.
|
||||
func ComputeDerivedKey(seed []byte, fullHdPath string) ([32]byte, error) {
|
||||
// StdDeriveKey is the default DeriveKey function in the keybase.
|
||||
// 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)
|
||||
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.
|
||||
|
@ -237,9 +277,22 @@ func CreateHDPath(account uint32, index uint32) *hd.BIP44Params {
|
|||
return hd.NewFundraiserParams(account, types.GetConfig().GetCoinType(), index)
|
||||
}
|
||||
|
||||
// IsAlgoSupported returns whether the signing algorithm is supported.
|
||||
//
|
||||
// TODO: Refactor this to be configurable to support interchangeable key signing
|
||||
// and addressing.
|
||||
// Ref: https://github.com/cosmos/cosmos-sdk/issues/4941
|
||||
func IsAlgoSupported(algo SigningAlgo) bool { return algo == Secp256k1 }
|
||||
// SupportedAlgos returns a list of supported signing algorithms.
|
||||
func (kb baseKeybase) SupportedAlgos() []SigningAlgo {
|
||||
return kb.options.supportedAlgos
|
||||
}
|
||||
|
||||
// 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(
|
||||
"some_account",
|
||||
"malarkey pair crucial catch public canyon evil outer stage ten gym tornado",
|
||||
"", "", 0, 1)
|
||||
"", "", CreateHDPath(0, 0).String(), Secp256k1)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Invalid mnemonic", err.Error())
|
||||
}
|
||||
|
||||
func TestCreateLedgerUnsupportedAlgo(t *testing.T) {
|
||||
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)
|
||||
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) {
|
||||
kb := NewInMemory()
|
||||
kb := NewInMemory(WithSupportedAlgosLedger([]SigningAlgo{Secp256k1, Ed25519}))
|
||||
|
||||
// test_cover and test_unit will result in different answers
|
||||
// test_cover does not compile some dependencies so ledger is disabled
|
||||
// test_unit may add a ledger mock
|
||||
// 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)
|
||||
|
||||
if err != nil {
|
||||
|
@ -92,7 +110,21 @@ func TestCreateLedger(t *testing.T) {
|
|||
// TestKeyManagement makes sure we can manipulate these keys well
|
||||
func TestKeyManagement(t *testing.T) {
|
||||
// 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
|
||||
n1, n2, n3 := "personal", "business", "other"
|
||||
|
@ -152,10 +184,12 @@ func TestKeyManagement(t *testing.T) {
|
|||
o1 := "offline"
|
||||
priv1 := ed25519.GenPrivKey()
|
||||
pub1 := priv1.PubKey()
|
||||
i, err = cstore.CreateOffline(o1, pub1)
|
||||
i, err = cstore.CreateOffline(o1, pub1, algo)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, pub1, i.GetPubKey())
|
||||
require.Equal(t, o1, i.GetName())
|
||||
iOffline := i.(*offlineInfo)
|
||||
require.Equal(t, algo, iOffline.GetAlgo())
|
||||
keyS, err = cstore.List()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(keyS))
|
||||
|
@ -393,7 +427,8 @@ func TestSeedPhrase(t *testing.T) {
|
|||
|
||||
// let us re-create it from the mnemonic-phrase
|
||||
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.Equal(t, n2, newInfo.GetName())
|
||||
require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address())
|
||||
|
@ -402,7 +437,11 @@ func TestSeedPhrase(t *testing.T) {
|
|||
|
||||
func ExampleNew() {
|
||||
// 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))
|
||||
|
||||
sec := Secp256k1
|
||||
|
|
|
@ -20,7 +20,6 @@ import (
|
|||
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
||||
|
||||
"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/mintkey"
|
||||
"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
|
||||
// with the given password.
|
||||
func (kb keyringKeybase) CreateAccount(
|
||||
name, mnemonic, bip39Passwd, encryptPasswd string, account, index uint32,
|
||||
name, mnemonic, bip39Passwd, encryptPasswd, hdPath string, algo SigningAlgo,
|
||||
) (Info, error) {
|
||||
|
||||
return kb.base.CreateAccount(kb, name, mnemonic, bip39Passwd, encryptPasswd, account, index)
|
||||
}
|
||||
|
||||
// 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)
|
||||
return kb.base.CreateAccount(kb, name, mnemonic, bip39Passwd, encryptPasswd, hdPath, algo)
|
||||
}
|
||||
|
||||
// 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
|
||||
// created key info.
|
||||
func (kb keyringKeybase) CreateOffline(name string, pub tmcrypto.PubKey) (Info, error) {
|
||||
return kb.base.writeOfflineKey(kb, name, pub), nil
|
||||
func (kb keyringKeybase) CreateOffline(name string, pub tmcrypto.PubKey, algo SigningAlgo) (Info, error) {
|
||||
return kb.base.writeOfflineKey(kb, name, pub, algo), nil
|
||||
}
|
||||
|
||||
// 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 mintkey.ArmorPubKeyBytes(bz.GetPubKey().Bytes()), nil
|
||||
return mintkey.ArmorPubKeyBytes(bz.GetPubKey().Bytes(), string(bz.GetAlgo())), nil
|
||||
}
|
||||
|
||||
// Import imports armored private key.
|
||||
|
@ -330,7 +320,12 @@ func (kb keyringKeybase) ExportPrivKey(name, decryptPassphrase, encryptPassphras
|
|||
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
|
||||
|
@ -341,13 +336,13 @@ func (kb keyringKeybase) ImportPrivKey(name, armor, passphrase string) error {
|
|||
return fmt.Errorf("cannot overwrite key: %s", name)
|
||||
}
|
||||
|
||||
privKey, err := mintkey.UnarmorDecryptPrivKey(armor, passphrase)
|
||||
privKey, algo, err := mintkey.UnarmorDecryptPrivKey(armor, passphrase)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to decrypt private key")
|
||||
}
|
||||
|
||||
// NOTE: The keyring keystore has no need for a passphrase.
|
||||
kb.writeLocalKey(name, privKey, "")
|
||||
kb.writeLocalKey(name, privKey, "", SigningAlgo(algo))
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
@ -380,7 +375,7 @@ func (kb keyringKeybase) ImportPubKey(name string, armor string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
kb.base.writeOfflineKey(kb, name, pubKey)
|
||||
kb.base.writeOfflineKey(kb, name, pubKey, SigningAlgo(algo))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -419,7 +414,7 @@ func (kb keyringKeybase) Update(name, oldpass string, getNewpass func() (string,
|
|||
|
||||
switch linfo := info.(type) {
|
||||
case localInfo:
|
||||
key, err := mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, oldpass)
|
||||
key, _, err := mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, oldpass)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -429,7 +424,7 @@ func (kb keyringKeybase) Update(name, oldpass string, getNewpass func() (string,
|
|||
return err
|
||||
}
|
||||
|
||||
kb.writeLocalKey(name, key, newpass)
|
||||
kb.writeLocalKey(name, key, newpass, linfo.GetAlgo())
|
||||
return nil
|
||||
|
||||
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.
|
||||
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
|
||||
pub := priv.PubKey()
|
||||
info := newLocalInfo(name, pub, string(priv.Bytes()))
|
||||
info := newLocalInfo(name, pub, string(priv.Bytes()), algo)
|
||||
|
||||
kb.writeInfo(name, info)
|
||||
return info
|
||||
|
|
|
@ -79,7 +79,7 @@ func TestLazyKeyManagementKeyRing(t *testing.T) {
|
|||
o1 := "offline"
|
||||
priv1 := ed25519.GenPrivKey()
|
||||
pub1 := priv1.PubKey()
|
||||
i, err = kb.CreateOffline(o1, pub1)
|
||||
i, err = kb.CreateOffline(o1, pub1, Ed25519)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, pub1, i.GetPubKey())
|
||||
require.Equal(t, o1, i.GetName())
|
||||
|
@ -209,10 +209,11 @@ func TestLazyExportImportPubKeyKeyRing(t *testing.T) {
|
|||
defer cleanup()
|
||||
kb, err := NewTestKeyring("keybasename", dir)
|
||||
require.NoError(t, err)
|
||||
algo := Secp256k1
|
||||
|
||||
// CreateMnemonic a private-public key pair and ensure consistency
|
||||
notPasswd := "n9y25ah7"
|
||||
info, _, err := kb.CreateMnemonic("john", English, notPasswd, Secp256k1)
|
||||
info, _, err := kb.CreateMnemonic("john", English, notPasswd, algo)
|
||||
require.Nil(t, err)
|
||||
require.NotEqual(t, info, "")
|
||||
require.Equal(t, info.GetName(), "john")
|
||||
|
@ -318,7 +319,8 @@ func TestLazySeedPhraseKeyRing(t *testing.T) {
|
|||
|
||||
// let us re-create it from the mnemonic-phrase
|
||||
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.Equal(t, n2, newInfo.GetName())
|
||||
require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address())
|
||||
|
|
|
@ -4,9 +4,13 @@ package keys
|
|||
type SigningAlgo string
|
||||
|
||||
const (
|
||||
// MultiAlgo implies that a pubkey is a multisignature
|
||||
MultiAlgo = SigningAlgo("multi")
|
||||
// Secp256k1 uses the Bitcoin secp256k1 ECDSA parameters.
|
||||
Secp256k1 = SigningAlgo("secp256k1")
|
||||
// Ed25519 represents the Ed25519 signature system.
|
||||
// It is currently not supported for end-user keys (wallets/ledgers).
|
||||
Ed25519 = SigningAlgo("ed25519")
|
||||
// Sr25519 represents the Sr25519 signature system.
|
||||
Sr25519 = SigningAlgo("sr25519")
|
||||
)
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"github.com/tendermint/tendermint/crypto"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -96,17 +95,7 @@ func (lkb lazyKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd
|
|||
defer db.Close()
|
||||
|
||||
return newDBKeybase(db,
|
||||
lkb.options...).CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, account, index)
|
||||
}
|
||||
|
||||
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)
|
||||
lkb.options...).CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, hdPath, algo)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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) {
|
||||
|
@ -221,4 +210,14 @@ func (lkb lazyKeybase) ExportPrivKey(name string, decryptPassphrase string,
|
|||
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() {}
|
||||
|
|
|
@ -89,7 +89,7 @@ func TestLazyKeyManagement(t *testing.T) {
|
|||
o1 := "offline"
|
||||
priv1 := ed25519.GenPrivKey()
|
||||
pub1 := priv1.PubKey()
|
||||
i, err = kb.CreateOffline(o1, pub1)
|
||||
i, err = kb.CreateOffline(o1, pub1, algo)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, pub1, i.GetPubKey())
|
||||
require.Equal(t, o1, i.GetName())
|
||||
|
@ -245,10 +245,11 @@ func TestLazyExportImportPubKey(t *testing.T) {
|
|||
dir, cleanup := tests.NewTestCaseDir(t)
|
||||
defer cleanup()
|
||||
kb := New("keybasename", dir)
|
||||
algo := Secp256k1
|
||||
|
||||
// CreateMnemonic a private-public key pair and ensure consistency
|
||||
notPasswd := "n9y25ah7"
|
||||
info, _, err := kb.CreateMnemonic("john", English, notPasswd, Secp256k1)
|
||||
info, _, err := kb.CreateMnemonic("john", English, notPasswd, algo)
|
||||
require.Nil(t, err)
|
||||
require.NotEqual(t, info, "")
|
||||
require.Equal(t, info.GetName(), "john")
|
||||
|
@ -368,7 +369,8 @@ func TestLazySeedPhrase(t *testing.T) {
|
|||
|
||||
// let us re-create it from the mnemonic-phrase
|
||||
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.Equal(t, n2, newInfo.GetName())
|
||||
require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address())
|
||||
|
@ -421,9 +423,9 @@ func TestKeygenOverride(t *testing.T) {
|
|||
CryptoCdc = testCdc
|
||||
|
||||
overrideCalled := false
|
||||
dummyFunc := func(bz [32]byte) crypto.PrivKey {
|
||||
dummyFunc := func(bz []byte, algo SigningAlgo) (crypto.PrivKey, error) {
|
||||
overrideCalled = true
|
||||
return testPriv(bz[:])
|
||||
return testPriv(bz[:]), nil
|
||||
}
|
||||
|
||||
kb := New("keybasename", dir, WithKeygenFunc(dummyFunc))
|
||||
|
|
|
@ -20,6 +20,11 @@ const (
|
|||
blockTypePrivKey = "TENDERMINT PRIVATE KEY"
|
||||
blockTypeKeyInfo = "TENDERMINT KEY INFO"
|
||||
blockTypePubKey = "TENDERMINT PUBLIC KEY"
|
||||
|
||||
defaultAlgo = "secp256k1"
|
||||
|
||||
headerVersion = "version"
|
||||
headerType = "type"
|
||||
)
|
||||
|
||||
// Make bcrypt security parameter var, so it can be changed within the lcd test
|
||||
|
@ -42,36 +47,58 @@ var BcryptSecurityParameter = 12
|
|||
|
||||
// Armor the InfoBytes
|
||||
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
|
||||
func ArmorPubKeyBytes(bz []byte) string {
|
||||
return armorBytes(bz, blockTypePubKey)
|
||||
}
|
||||
|
||||
func armorBytes(bz []byte, blockType string) string {
|
||||
func ArmorPubKeyBytes(bz []byte, algo string) string {
|
||||
header := map[string]string{
|
||||
"type": "Info",
|
||||
"version": "0.0.0",
|
||||
headerVersion: "0.0.1",
|
||||
}
|
||||
return armor.EncodeArmor(blockType, header, bz)
|
||||
if algo != "" {
|
||||
header[headerType] = algo
|
||||
}
|
||||
return armor.EncodeArmor(blockTypePubKey, header, bz)
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// remove armor
|
||||
|
||||
// Unarmor the InfoBytes
|
||||
func UnarmorInfoBytes(armorStr string) (bz []byte, err error) {
|
||||
return unarmorBytes(armorStr, blockTypeKeyInfo)
|
||||
func UnarmorInfoBytes(armorStr string) ([]byte, error) {
|
||||
bz, header, err := unarmorBytes(armorStr, blockTypeKeyInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if header[headerVersion] != "0.0.0" {
|
||||
return nil, fmt.Errorf("unrecognized version: %v", header[headerVersion])
|
||||
}
|
||||
return bz, nil
|
||||
}
|
||||
|
||||
// Unarmor the PubKeyBytes
|
||||
func UnarmorPubKeyBytes(armorStr string) (bz []byte, err error) {
|
||||
return unarmorBytes(armorStr, blockTypePubKey)
|
||||
// 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, err error) {
|
||||
func unarmorBytes(armorStr, blockType string) (bz []byte, header map[string]string, err error) {
|
||||
bType, header, bz, err := armor.DecodeArmor(armorStr)
|
||||
if err != nil {
|
||||
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)
|
||||
return
|
||||
}
|
||||
if header["version"] != "0.0.0" {
|
||||
err = fmt.Errorf("unrecognized version: %v", header["version"])
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -91,12 +114,15 @@ func unarmorBytes(armorStr, blockType string) (bz []byte, err error) {
|
|||
// encrypt/decrypt with armor
|
||||
|
||||
// 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)
|
||||
header := map[string]string{
|
||||
"kdf": "bcrypt",
|
||||
"salt": fmt.Sprintf("%X", saltBytes),
|
||||
}
|
||||
if algo != "" {
|
||||
header[headerType] = algo
|
||||
}
|
||||
armorStr := armor.EncodeArmor(blockTypePrivKey, header, encBytes)
|
||||
return armorStr
|
||||
}
|
||||
|
@ -115,28 +141,31 @@ func encryptPrivKey(privKey crypto.PrivKey, passphrase string) (saltBytes []byte
|
|||
return saltBytes, xsalsa20symmetric.EncryptSymmetric(privKeyBytes, key)
|
||||
}
|
||||
|
||||
// Unarmor and decrypt the private key.
|
||||
func UnarmorDecryptPrivKey(armorStr string, passphrase string) (crypto.PrivKey, error) {
|
||||
var privKey crypto.PrivKey
|
||||
// UnarmorDecryptPrivKey returns the privkey byte slice, a string of the algo type, and an error
|
||||
func UnarmorDecryptPrivKey(armorStr string, passphrase string) (privKey crypto.PrivKey, algo string, err error) {
|
||||
blockType, header, encBytes, err := armor.DecodeArmor(armorStr)
|
||||
if err != nil {
|
||||
return privKey, err
|
||||
return privKey, "", err
|
||||
}
|
||||
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" {
|
||||
return privKey, fmt.Errorf("unrecognized KDF type: %v", header["KDF"])
|
||||
return privKey, "", fmt.Errorf("unrecognized KDF type: %v", header["KDF"])
|
||||
}
|
||||
if header["salt"] == "" {
|
||||
return privKey, fmt.Errorf("missing salt bytes")
|
||||
return privKey, "", fmt.Errorf("missing salt bytes")
|
||||
}
|
||||
saltBytes, err := hex.DecodeString(header["salt"])
|
||||
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)
|
||||
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) {
|
||||
|
|
|
@ -13,11 +13,12 @@ import (
|
|||
|
||||
func TestArmorUnarmorPrivKey(t *testing.T) {
|
||||
priv := secp256k1.GenPrivKey()
|
||||
armor := mintkey.EncryptArmorPrivKey(priv, "passphrase")
|
||||
_, err := mintkey.UnarmorDecryptPrivKey(armor, "wrongpassphrase")
|
||||
armor := mintkey.EncryptArmorPrivKey(priv, "passphrase", "")
|
||||
_, _, err := mintkey.UnarmorDecryptPrivKey(armor, "wrongpassphrase")
|
||||
require.Error(t, err)
|
||||
decrypted, err := mintkey.UnarmorDecryptPrivKey(armor, "passphrase")
|
||||
decrypted, algo, err := mintkey.UnarmorDecryptPrivKey(armor, "passphrase")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, string(keys.Secp256k1), algo)
|
||||
require.True(t, priv.Equals(decrypted))
|
||||
}
|
||||
|
||||
|
@ -28,10 +29,11 @@ func TestArmorUnarmorPubKey(t *testing.T) {
|
|||
// Add keys and see they return in alphabetical order
|
||||
info, _, err := cstore.CreateMnemonic("Bob", keys.English, "passphrase", keys.Secp256k1)
|
||||
require.NoError(t, err)
|
||||
armor := mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes())
|
||||
pubBytes, err := mintkey.UnarmorPubKeyBytes(armor)
|
||||
armor := mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes(), "")
|
||||
pubBytes, algo, err := mintkey.UnarmorPubKeyBytes(armor)
|
||||
require.NoError(t, err)
|
||||
pub, err := cryptoAmino.PubKeyFromBytes(pubBytes)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, string(keys.Secp256k1), algo)
|
||||
require.True(t, pub.Equals(info.GetPubKey()))
|
||||
}
|
||||
|
|
|
@ -31,21 +31,15 @@ type Keybase interface {
|
|||
// same name.
|
||||
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.
|
||||
CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (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)
|
||||
CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, hdPath string, algo SigningAlgo) (Info, error)
|
||||
|
||||
// CreateLedger creates, stores, and returns a new Ledger key reference
|
||||
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(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(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(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()
|
||||
}
|
||||
|
@ -118,6 +118,8 @@ type Info interface {
|
|||
GetPubKey() crypto.PubKey
|
||||
// Address
|
||||
GetAddress() types.AccAddress
|
||||
// Algo
|
||||
GetAlgo() SigningAlgo
|
||||
// Bip44 Path
|
||||
GetPath() (*hd.BIP44Params, error)
|
||||
}
|
||||
|
@ -132,15 +134,17 @@ var (
|
|||
// localInfo is the public information about a locally stored key
|
||||
type localInfo struct {
|
||||
Name string `json:"name"`
|
||||
Algo SigningAlgo `json:"algo"`
|
||||
PubKey crypto.PubKey `json:"pubkey"`
|
||||
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{
|
||||
Name: name,
|
||||
PubKey: pub,
|
||||
PrivKeyArmor: privArmor,
|
||||
Algo: algo,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,6 +168,11 @@ func (i localInfo) GetAddress() types.AccAddress {
|
|||
return i.PubKey.Address().Bytes()
|
||||
}
|
||||
|
||||
// GetType implements Info interface
|
||||
func (i localInfo) GetAlgo() SigningAlgo {
|
||||
return i.Algo
|
||||
}
|
||||
|
||||
// GetType implements Info interface
|
||||
func (i localInfo) GetPath() (*hd.BIP44Params, error) {
|
||||
return nil, fmt.Errorf("BIP44 Paths are not available for this type")
|
||||
|
@ -174,13 +183,15 @@ type ledgerInfo struct {
|
|||
Name string `json:"name"`
|
||||
PubKey crypto.PubKey `json:"pubkey"`
|
||||
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{
|
||||
Name: name,
|
||||
PubKey: pub,
|
||||
Path: path,
|
||||
Algo: algo,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,6 +215,11 @@ func (i ledgerInfo) GetAddress() types.AccAddress {
|
|||
return i.PubKey.Address().Bytes()
|
||||
}
|
||||
|
||||
// GetPath implements Info interface
|
||||
func (i ledgerInfo) GetAlgo() SigningAlgo {
|
||||
return i.Algo
|
||||
}
|
||||
|
||||
// GetPath implements Info interface
|
||||
func (i ledgerInfo) GetPath() (*hd.BIP44Params, error) {
|
||||
tmp := i.Path
|
||||
|
@ -213,13 +229,15 @@ func (i ledgerInfo) GetPath() (*hd.BIP44Params, error) {
|
|||
// offlineInfo is the public information about an offline key
|
||||
type offlineInfo struct {
|
||||
Name string `json:"name"`
|
||||
Algo SigningAlgo `json:"algo"`
|
||||
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{
|
||||
Name: name,
|
||||
PubKey: pub,
|
||||
Algo: algo,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,6 +256,11 @@ func (i offlineInfo) GetPubKey() crypto.PubKey {
|
|||
return i.PubKey
|
||||
}
|
||||
|
||||
// GetAlgo returns the signing algorithm for the key
|
||||
func (i offlineInfo) GetAlgo() SigningAlgo {
|
||||
return i.Algo
|
||||
}
|
||||
|
||||
// GetAddress implements Info interface
|
||||
func (i offlineInfo) GetAddress() types.AccAddress {
|
||||
return i.PubKey.Address().Bytes()
|
||||
|
@ -299,6 +322,11 @@ func (i multiInfo) GetAddress() types.AccAddress {
|
|||
return i.PubKey.Address().Bytes()
|
||||
}
|
||||
|
||||
// GetPath implements Info interface
|
||||
func (i multiInfo) GetAlgo() SigningAlgo {
|
||||
return MultiAlgo
|
||||
}
|
||||
|
||||
// GetPath implements Info interface
|
||||
func (i multiInfo) GetPath() (*hd.BIP44Params, error) {
|
||||
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 (
|
||||
// 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 func(bz [32]byte) crypto.PrivKey
|
||||
PrivKeyGenFunc func(bz []byte, algo SigningAlgo) (crypto.PrivKey, error)
|
||||
|
||||
// KeybaseOption overrides options for the db
|
||||
KeybaseOption func(*kbOptions)
|
||||
|
|
|
@ -17,7 +17,7 @@ func Test_writeReadLedgerInfo(t *testing.T) {
|
|||
bz, _ := hex.DecodeString("035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A")
|
||||
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())
|
||||
|
||||
path, err := lInfo.GetPath()
|
||||
|
|
|
@ -17,7 +17,7 @@ func TestGenerateCoinKey(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
// 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.Equal(t, addr, info.GetAddress())
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ func TestGenerateSaveCoinKey(t *testing.T) {
|
|||
require.Equal(t, addr, info.GetAddress())
|
||||
|
||||
// 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.Equal(t, addr, info.GetAddress())
|
||||
}
|
||||
|
|
|
@ -312,7 +312,7 @@ func DefaultSigVerificationGasConsumer(
|
|||
var multisignature multisig.Multisignature
|
||||
codec.Cdc.MustUnmarshalBinaryBare(sig, &multisignature)
|
||||
|
||||
consumeMultisignatureVerificationGas(meter, multisignature, pubkey, params)
|
||||
ConsumeMultisignatureVerificationGas(meter, multisignature, pubkey, params)
|
||||
return nil
|
||||
|
||||
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,
|
||||
params types.Params) {
|
||||
size := sig.BitArray.Size()
|
||||
|
|
Loading…
Reference in New Issue