cosmos-sdk/crypto/keys/types.go

358 lines
10 KiB
Go

package keys
import (
"fmt"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/multisig"
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
"github.com/cosmos/cosmos-sdk/types"
)
// Keybase exposes operations on a generic keystore
type Keybase interface {
// CRUD on the keystore
List() ([]Info, error)
// Get returns the public information about one key.
Get(name string) (Info, error)
// Get performs a by-address lookup and returns the public
// information about one key if there's any.
GetByAddress(address types.AccAddress) (Info, error)
// Delete removes a key.
Delete(name, passphrase string, skipPass bool) error
// Sign bytes, looking up the private key to use.
Sign(name, passphrase string, msg []byte) ([]byte, crypto.PubKey, error)
// CreateMnemonic generates a new mnemonic, derives a hierarchical deterministic
// key from that. and persists it to storage, encrypted using the provided password.
// It returns the generated mnemonic and the key Info. It returns an error if it fails to
// generate a key for the given algo type, or if another key is already stored under the
// 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 and BIP 32 HD Path
// and persists it, encrypted with the given password.
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, 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)
// The following operations will *only* work on locally-stored keys
Update(name, oldpass string, getNewpass func() (string, error)) error
// Import imports ASCII armored Info objects.
Import(name string, armor string) (err error)
// ImportPrivKey imports a private key in ASCII armor format.
// It returns an error if a key with the same name exists or a wrong encryption passphrase is
// supplied.
ImportPrivKey(name, armor, passphrase string) error
// ImportPubKey imports ASCII-armored public keys.
// Store a new Info object holding a public key only, i.e. it will
// not be possible to sign with it as it lacks the secret key.
ImportPubKey(name string, armor string) (err error)
// Export exports an Info object in ASCII armored format.
Export(name string) (armor string, err error)
// ExportPubKey returns public keys in ASCII armored format.
// Retrieve a Info object by its name and return the public key in
// a portable format.
ExportPubKey(name string) (armor string, err error)
// ExportPrivKey returns a private key in ASCII armored format.
// It returns an error if the key does not exist or a wrong encryption passphrase is supplied.
ExportPrivKey(name, decryptPassphrase, encryptPassphrase string) (armor string, err error)
// 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()
}
// KeyType reflects a human-readable type for key listing.
type KeyType uint
// Info KeyTypes
const (
TypeLocal KeyType = 0
TypeLedger KeyType = 1
TypeOffline KeyType = 2
TypeMulti KeyType = 3
)
var keyTypes = map[KeyType]string{
TypeLocal: "local",
TypeLedger: "ledger",
TypeOffline: "offline",
TypeMulti: "multi",
}
// String implements the stringer interface for KeyType.
func (kt KeyType) String() string {
return keyTypes[kt]
}
// Info is the publicly exposed information about a keypair
type Info interface {
// Human-readable type for key listing
GetType() KeyType
// Name of the key
GetName() string
// Public key
GetPubKey() crypto.PubKey
// Address
GetAddress() types.AccAddress
// Bip44 Path
GetPath() (*hd.BIP44Params, error)
// Algo
GetAlgo() SigningAlgo
}
var (
_ Info = &localInfo{}
_ Info = &ledgerInfo{}
_ Info = &offlineInfo{}
_ Info = &multiInfo{}
)
// localInfo is the public information about a locally stored key
// Note: Algo must be last field in struct for backwards amino compatibility
type localInfo struct {
Name string `json:"name"`
PubKey crypto.PubKey `json:"pubkey"`
PrivKeyArmor string `json:"privkey.armor"`
Algo SigningAlgo `json:"algo"`
}
func newLocalInfo(name string, pub crypto.PubKey, privArmor string, algo SigningAlgo) Info {
return &localInfo{
Name: name,
PubKey: pub,
PrivKeyArmor: privArmor,
Algo: algo,
}
}
// GetType implements Info interface
func (i localInfo) GetType() KeyType {
return TypeLocal
}
// GetType implements Info interface
func (i localInfo) GetName() string {
return i.Name
}
// GetType implements Info interface
func (i localInfo) GetPubKey() crypto.PubKey {
return i.PubKey
}
// GetType implements Info interface
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")
}
// ledgerInfo is the public information about a Ledger key
// Note: Algo must be last field in struct for backwards amino compatibility
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, algo SigningAlgo) Info {
return &ledgerInfo{
Name: name,
PubKey: pub,
Path: path,
Algo: algo,
}
}
// GetType implements Info interface
func (i ledgerInfo) GetType() KeyType {
return TypeLedger
}
// GetName implements Info interface
func (i ledgerInfo) GetName() string {
return i.Name
}
// GetPubKey implements Info interface
func (i ledgerInfo) GetPubKey() crypto.PubKey {
return i.PubKey
}
// GetAddress implements Info interface
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
return &tmp, nil
}
// offlineInfo is the public information about an offline key
// Note: Algo must be last field in struct for backwards amino compatibility
type offlineInfo struct {
Name string `json:"name"`
PubKey crypto.PubKey `json:"pubkey"`
Algo SigningAlgo `json:"algo"`
}
func newOfflineInfo(name string, pub crypto.PubKey, algo SigningAlgo) Info {
return &offlineInfo{
Name: name,
PubKey: pub,
Algo: algo,
}
}
// GetType implements Info interface
func (i offlineInfo) GetType() KeyType {
return TypeOffline
}
// GetName implements Info interface
func (i offlineInfo) GetName() string {
return i.Name
}
// GetPubKey implements Info interface
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()
}
// GetPath implements Info interface
func (i offlineInfo) GetPath() (*hd.BIP44Params, error) {
return nil, fmt.Errorf("BIP44 Paths are not available for this type")
}
type multisigPubKeyInfo struct {
PubKey crypto.PubKey `json:"pubkey"`
Weight uint `json:"weight"`
}
// multiInfo is the public information about a multisig key
type multiInfo struct {
Name string `json:"name"`
PubKey crypto.PubKey `json:"pubkey"`
Threshold uint `json:"threshold"`
PubKeys []multisigPubKeyInfo `json:"pubkeys"`
}
// NewMultiInfo creates a new multiInfo instance
func NewMultiInfo(name string, pub crypto.PubKey) Info {
multiPK := pub.(multisig.PubKeyMultisigThreshold)
pubKeys := make([]multisigPubKeyInfo, len(multiPK.PubKeys))
for i, pk := range multiPK.PubKeys {
// TODO: Recursively check pk for total weight?
pubKeys[i] = multisigPubKeyInfo{pk, 1}
}
return &multiInfo{
Name: name,
PubKey: pub,
Threshold: multiPK.K,
PubKeys: pubKeys,
}
}
// GetType implements Info interface
func (i multiInfo) GetType() KeyType {
return TypeMulti
}
// GetName implements Info interface
func (i multiInfo) GetName() string {
return i.Name
}
// GetPubKey implements Info interface
func (i multiInfo) GetPubKey() crypto.PubKey {
return i.PubKey
}
// GetAddress implements Info interface
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")
}
// encoding info
func marshalInfo(i Info) []byte {
return CryptoCdc.MustMarshalBinaryLengthPrefixed(i)
}
// decoding info
func unmarshalInfo(bz []byte) (info Info, err error) {
err = CryptoCdc.UnmarshalBinaryLengthPrefixed(bz, &info)
return
}
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 []byte, algo SigningAlgo) (crypto.PrivKey, error)
// KeybaseOption overrides options for the db
KeybaseOption func(*kbOptions)
)