forked from cerc-io/laconicd-deprecated
Update keybase back to cosmos-sdk with support (#147)
* Migrate keybase back to Cosmos-sdk using temporary fork * Cleaned up other affected code * Change to updated tendermint * fmt * Change auth codec update * clean up codec registration to respective packages * Fix import fmt * Remove no longer necessary replace * Fix function comment
This commit is contained in:
@@ -1,25 +0,0 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
cosmosKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
|
||||
emintCrypto "github.com/cosmos/ethermint/crypto"
|
||||
)
|
||||
|
||||
var cdc *codec.Codec
|
||||
|
||||
func init() {
|
||||
cdc = codec.New()
|
||||
cryptoAmino.RegisterAmino(cdc)
|
||||
cdc.RegisterInterface((*cosmosKeys.Info)(nil), nil)
|
||||
emintCrypto.RegisterCodec(cdc)
|
||||
cdc.RegisterConcrete(hd.BIP44Params{}, "crypto/keys/hd/BIP44Params", nil)
|
||||
cdc.RegisterConcrete(localInfo{}, "crypto/keys/localInfo", nil)
|
||||
cdc.RegisterConcrete(ledgerInfo{}, "crypto/keys/ledgerInfo", nil)
|
||||
cdc.RegisterConcrete(offlineInfo{}, "crypto/keys/offlineInfo", nil)
|
||||
// cdc.RegisterConcrete(multiInfo{}, "crypto/keys/multiInfo", nil)
|
||||
cdc.Seal()
|
||||
}
|
||||
@@ -1,512 +0,0 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto"
|
||||
cosmosKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/keyerror"
|
||||
"github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/ethermint/crypto/keys/mintkey"
|
||||
|
||||
bip39 "github.com/cosmos/go-bip39"
|
||||
|
||||
emintCrypto "github.com/cosmos/ethermint/crypto"
|
||||
tmcrypto "github.com/tendermint/tendermint/crypto"
|
||||
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
)
|
||||
|
||||
var _ cosmosKeys.Keybase = dbKeybase{}
|
||||
|
||||
// Language is a language to create the BIP 39 mnemonic in.
|
||||
// Currently, only english is supported though.
|
||||
// Find a list of all supported languages in the BIP 39 spec (word lists).
|
||||
type Language int
|
||||
|
||||
//noinspection ALL
|
||||
const (
|
||||
// English is the default language to create a mnemonic.
|
||||
// It is the only supported language by this package.
|
||||
English Language = iota + 1
|
||||
// Japanese is currently not supported.
|
||||
Japanese
|
||||
// Korean is currently not supported.
|
||||
Korean
|
||||
// Spanish is currently not supported.
|
||||
Spanish
|
||||
// ChineseSimplified is currently not supported.
|
||||
ChineseSimplified
|
||||
// ChineseTraditional is currently not supported.
|
||||
ChineseTraditional
|
||||
// French is currently not supported.
|
||||
French
|
||||
// Italian is currently not supported.
|
||||
Italian
|
||||
addressSuffix = "address"
|
||||
infoSuffix = "info"
|
||||
)
|
||||
|
||||
const (
|
||||
// used for deriving seed from mnemonic
|
||||
DefaultBIP39Passphrase = ""
|
||||
|
||||
// bits of entropy to draw when creating a mnemonic
|
||||
defaultEntropySize = 256
|
||||
)
|
||||
|
||||
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")
|
||||
|
||||
// ErrUnsupportedLanguage is raised when the caller tries to use a
|
||||
// different language than english for creating a mnemonic sentence.
|
||||
ErrUnsupportedLanguage = errors.New("unsupported language: only english is supported")
|
||||
)
|
||||
|
||||
// dbKeybase combines encryption and storage implementation to provide
|
||||
// a full-featured key manager
|
||||
type dbKeybase struct {
|
||||
db dbm.DB
|
||||
}
|
||||
|
||||
// newDbKeybase creates a new keybase instance using the passed DB for reading and writing keys.
|
||||
func newDbKeybase(db dbm.DB) cosmosKeys.Keybase {
|
||||
return dbKeybase{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
// NewInMemory creates a transient keybase on top of in-memory storage
|
||||
// instance useful for testing purposes and on-the-fly key generation.
|
||||
func NewInMemory() cosmosKeys.Keybase { return dbKeybase{dbm.NewMemDB()} }
|
||||
|
||||
// CreateMnemonic generates a new key 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.
|
||||
func (kb dbKeybase) CreateMnemonic(name string, language cosmosKeys.Language, passwd string, algo cosmosKeys.SigningAlgo) (info cosmosKeys.Info, mnemonic string, err error) {
|
||||
if language != cosmosKeys.English {
|
||||
return nil, "", ErrUnsupportedLanguage
|
||||
}
|
||||
if algo != Secp256k1 {
|
||||
err = ErrUnsupportedSigningAlgo
|
||||
return
|
||||
}
|
||||
|
||||
// default number of words (24):
|
||||
// this generates a mnemonic directly from the number of words by reading system entropy.
|
||||
entropy, err := bip39.NewEntropy(defaultEntropySize)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
mnemonic, err = bip39.NewMnemonic(entropy)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
seed := bip39.NewSeed(mnemonic, DefaultBIP39Passphrase)
|
||||
fullFundraiserPath := types.GetConfig().GetFullFundraiserPath()
|
||||
info, err = kb.persistDerivedKey(seed, passwd, name, fullFundraiserPath)
|
||||
return
|
||||
}
|
||||
|
||||
// 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) (cosmosKeys.Info, error) {
|
||||
coinType := types.GetConfig().GetCoinType()
|
||||
hdPath := hd.NewFundraiserParams(account, coinType, index)
|
||||
return kb.Derive(name, mnemonic, bip39Passwd, encryptPasswd, *hdPath)
|
||||
}
|
||||
|
||||
func (kb dbKeybase) Derive(name, mnemonic, bip39Passphrase, encryptPasswd string, params hd.BIP44Params) (info cosmosKeys.Info, err error) {
|
||||
seed, err := bip39.NewSeedWithErrorChecking(mnemonic, bip39Passphrase)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
info, err = kb.persistDerivedKey(seed, encryptPasswd, name, params.String())
|
||||
return info, err
|
||||
}
|
||||
|
||||
// CreateLedger creates a new locally-stored reference to a Ledger keypair
|
||||
// It returns the created key info and an error if the Ledger could not be queried
|
||||
func (kb dbKeybase) CreateLedger(name string, algo cosmosKeys.SigningAlgo, hrp string, account, index uint32) (cosmosKeys.Info, error) {
|
||||
if algo != Secp256k1 {
|
||||
return nil, ErrUnsupportedSigningAlgo
|
||||
}
|
||||
|
||||
coinType := types.GetConfig().GetCoinType()
|
||||
hdPath := hd.NewFundraiserParams(account, coinType, index)
|
||||
priv, _, err := crypto.NewPrivKeyLedgerSecp256k1(*hdPath, hrp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pub := priv.PubKey()
|
||||
|
||||
// Note: Once Cosmos App v1.3.1 is compulsory, it could be possible to check that pubkey and addr match
|
||||
return kb.writeLedgerKey(name, pub, *hdPath), nil
|
||||
}
|
||||
|
||||
// CreateOffline creates a new reference to an offline keypair. It returns the
|
||||
// created key info.
|
||||
func (kb dbKeybase) CreateOffline(name string, pub tmcrypto.PubKey) (cosmosKeys.Info, error) {
|
||||
return kb.writeOfflineKey(name, pub), nil
|
||||
}
|
||||
|
||||
// CreateMulti creates a new reference to a multisig (offline) keypair. It
|
||||
// returns the created key info.
|
||||
func (kb dbKeybase) CreateMulti(name string, pub tmcrypto.PubKey) (cosmosKeys.Info, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (kb *dbKeybase) persistDerivedKey(seed []byte, passwd, name, fullHdPath string) (info cosmosKeys.Info, err error) {
|
||||
// create master key and derive first key:
|
||||
masterPriv, ch := hd.ComputeMastersFromSeed(seed)
|
||||
derivedPriv, err := hd.DerivePrivateKeyForPath(masterPriv, ch, fullHdPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// if we have a password, use it to encrypt the private key and store it
|
||||
// else store the public key only
|
||||
if passwd != "" {
|
||||
info = kb.writeLocalKey(name, emintCrypto.PrivKeySecp256k1(derivedPriv[:]), passwd)
|
||||
} else {
|
||||
pubk := emintCrypto.PrivKeySecp256k1(derivedPriv[:]).PubKey()
|
||||
info = kb.writeOfflineKey(name, pubk)
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
// List returns the keys from storage in alphabetical order.
|
||||
func (kb dbKeybase) List() ([]cosmosKeys.Info, error) {
|
||||
var res []cosmosKeys.Info
|
||||
iter := kb.db.Iterator(nil, nil)
|
||||
defer iter.Close()
|
||||
for ; iter.Valid(); iter.Next() {
|
||||
key := string(iter.Key())
|
||||
|
||||
// need to include only keys in storage that have an info suffix
|
||||
if strings.HasSuffix(key, infoSuffix) {
|
||||
info, err := readInfo(iter.Value())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = append(res, info)
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Get returns the public information about one key.
|
||||
func (kb dbKeybase) Get(name string) (cosmosKeys.Info, error) {
|
||||
bs := kb.db.Get(infoKey(name))
|
||||
if len(bs) == 0 {
|
||||
return nil, keyerror.NewErrKeyNotFound(name)
|
||||
}
|
||||
return readInfo(bs)
|
||||
}
|
||||
|
||||
func (kb dbKeybase) GetByAddress(address types.AccAddress) (cosmosKeys.Info, error) {
|
||||
ik := kb.db.Get(addrKey(address))
|
||||
if len(ik) == 0 {
|
||||
return nil, fmt.Errorf("key with address %s not found", address)
|
||||
}
|
||||
bs := kb.db.Get(ik)
|
||||
return readInfo(bs)
|
||||
}
|
||||
|
||||
// Sign signs the msg with the named key.
|
||||
// It returns an error if the key doesn't exist or the decryption fails.
|
||||
func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, pub tmcrypto.PubKey, err error) {
|
||||
info, err := kb.Get(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var priv tmcrypto.PrivKey
|
||||
|
||||
switch info := info.(type) {
|
||||
case localInfo:
|
||||
if info.PrivKeyArmor == "" {
|
||||
err = fmt.Errorf("private key not available")
|
||||
return
|
||||
}
|
||||
|
||||
priv, err = mintkey.UnarmorDecryptPrivKey(info.PrivKeyArmor, passphrase)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
case ledgerInfo:
|
||||
priv, err = crypto.NewPrivKeyLedgerSecp256k1Unsafe(info.Path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// case offlineInfo, multiInfo:
|
||||
case offlineInfo:
|
||||
_, err := fmt.Fprintf(os.Stderr, "Message to sign:\n\n%s\n", msg)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
buf := bufio.NewReader(os.Stdin)
|
||||
_, err = fmt.Fprintf(os.Stderr, "\nEnter Amino-encoded signature:\n")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Will block until user inputs the signature
|
||||
signed, err := buf.ReadString('\n')
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if err := cdc.UnmarshalBinaryLengthPrefixed([]byte(signed), sig); err != nil {
|
||||
return nil, nil, errors.Wrap(err, "failed to decode signature")
|
||||
}
|
||||
|
||||
return sig, info.GetPubKey(), nil
|
||||
}
|
||||
|
||||
sig, err = priv.Sign(msg)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
pub = priv.PubKey()
|
||||
return sig, pub, nil
|
||||
}
|
||||
|
||||
func (kb dbKeybase) ExportPrivateKeyObject(name string, passphrase string) (tmcrypto.PrivKey, error) {
|
||||
info, err := kb.Get(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var priv tmcrypto.PrivKey
|
||||
|
||||
switch info := info.(type) {
|
||||
case localInfo:
|
||||
if info.PrivKeyArmor == "" {
|
||||
err = fmt.Errorf("private key not available")
|
||||
return nil, err
|
||||
}
|
||||
priv, err = mintkey.UnarmorDecryptPrivKey(info.PrivKeyArmor, passphrase)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// case ledgerInfo, offlineInfo, multiInfo:
|
||||
case ledgerInfo, offlineInfo:
|
||||
return nil, errors.New("only works on local private keys")
|
||||
}
|
||||
|
||||
return priv, nil
|
||||
}
|
||||
|
||||
func (kb dbKeybase) Export(name string) (armor string, err error) {
|
||||
bz := kb.db.Get(infoKey(name))
|
||||
if bz == nil {
|
||||
return "", fmt.Errorf("no key to export with name %s", name)
|
||||
}
|
||||
return mintkey.ArmorInfoBytes(bz), nil
|
||||
}
|
||||
|
||||
// ExportPubKey returns public keys in ASCII armored format.
|
||||
// Retrieve a Info object by its name and return the public key in
|
||||
// a portable format.
|
||||
func (kb dbKeybase) ExportPubKey(name string) (armor string, err error) {
|
||||
bz := kb.db.Get(infoKey(name))
|
||||
if bz == nil {
|
||||
return "", fmt.Errorf("no key to export with name %s", name)
|
||||
}
|
||||
info, err := readInfo(bz)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes()), nil
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (kb dbKeybase) ExportPrivKey(name string, decryptPassphrase string,
|
||||
encryptPassphrase string) (armor string, err error) {
|
||||
priv, err := kb.ExportPrivateKeyObject(name, decryptPassphrase)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return mintkey.EncryptArmorPrivKey(priv, encryptPassphrase), nil
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (kb dbKeybase) ImportPrivKey(name string, armor string, passphrase string) error {
|
||||
if _, err := kb.Get(name); err == nil {
|
||||
return errors.New("Cannot overwrite key " + name)
|
||||
}
|
||||
|
||||
privKey, err := mintkey.UnarmorDecryptPrivKey(armor, passphrase)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "couldn't import private key")
|
||||
}
|
||||
|
||||
kb.writeLocalKey(name, privKey, passphrase)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (kb dbKeybase) Import(name string, armor string) (err error) {
|
||||
bz := kb.db.Get(infoKey(name))
|
||||
if len(bz) > 0 {
|
||||
return errors.New("Cannot overwrite data for name " + name)
|
||||
}
|
||||
infoBytes, err := mintkey.UnarmorInfoBytes(armor)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
kb.db.Set(infoKey(name), infoBytes)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (kb dbKeybase) ImportPubKey(name string, armor string) (err error) {
|
||||
bz := kb.db.Get(infoKey(name))
|
||||
if len(bz) > 0 {
|
||||
return errors.New("Cannot overwrite data for name " + name)
|
||||
}
|
||||
pubBytes, err := mintkey.UnarmorPubKeyBytes(armor)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
pubKey, err := cryptoAmino.PubKeyFromBytes(pubBytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
kb.writeOfflineKey(name, pubKey)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete removes key forever, but we must present the
|
||||
// proper passphrase before deleting it (for security).
|
||||
// It returns an error if the key doesn't exist or
|
||||
// passphrases don't match.
|
||||
// Passphrase is ignored when deleting references to
|
||||
// offline and Ledger / HW wallet keys.
|
||||
func (kb dbKeybase) Delete(name, passphrase string, skipPass bool) error {
|
||||
// verify we have the proper password before deleting
|
||||
info, err := kb.Get(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if linfo, ok := info.(localInfo); ok && !skipPass {
|
||||
if _, err = mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
kb.db.DeleteSync(addrKey(info.GetAddress()))
|
||||
kb.db.DeleteSync(infoKey(name))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update changes the passphrase with which an already stored key is
|
||||
// encrypted.
|
||||
//
|
||||
// oldpass must be the current passphrase used for encryption,
|
||||
// getNewpass is a function to get the passphrase to permanently replace
|
||||
// the current passphrase
|
||||
func (kb dbKeybase) Update(name, oldpass string, getNewpass func() (string, error)) error {
|
||||
info, err := kb.Get(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch info := info.(type) {
|
||||
case localInfo:
|
||||
key, err := mintkey.UnarmorDecryptPrivKey(info.PrivKeyArmor, oldpass)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newpass, err := getNewpass()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kb.writeLocalKey(name, key, newpass)
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("locally stored key required. Received: %v", reflect.TypeOf(info).String())
|
||||
}
|
||||
}
|
||||
|
||||
// CloseDB releases the lock and closes the storage backend.
|
||||
func (kb dbKeybase) CloseDB() {
|
||||
kb.db.Close()
|
||||
}
|
||||
|
||||
func (kb dbKeybase) writeLocalKey(name string, priv tmcrypto.PrivKey, passphrase string) cosmosKeys.Info {
|
||||
privkey, ok := priv.(emintCrypto.PrivKeySecp256k1)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("invalid private key type: %T", priv))
|
||||
}
|
||||
// encrypt private key using passphrase
|
||||
privArmor := mintkey.EncryptArmorPrivKey(privkey, passphrase)
|
||||
// make Info
|
||||
pub := privkey.PubKey()
|
||||
pubkey, ok := pub.(emintCrypto.PubKeySecp256k1)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("invalid public key type: %T", pub))
|
||||
}
|
||||
info := newLocalInfo(name, pubkey, privArmor)
|
||||
kb.writeInfo(name, info)
|
||||
return info
|
||||
}
|
||||
|
||||
func (kb dbKeybase) writeLedgerKey(name string, pub tmcrypto.PubKey, path hd.BIP44Params) cosmosKeys.Info {
|
||||
pubkey, ok := pub.(emintCrypto.PubKeySecp256k1)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("invalid public key type: %T", pub))
|
||||
}
|
||||
info := newLedgerInfo(name, pubkey, path)
|
||||
kb.writeInfo(name, info)
|
||||
return info
|
||||
}
|
||||
|
||||
func (kb dbKeybase) writeOfflineKey(name string, pub tmcrypto.PubKey) cosmosKeys.Info {
|
||||
pubkey, ok := pub.(emintCrypto.PubKeySecp256k1)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("invalid public key type: %T", pub))
|
||||
}
|
||||
info := newOfflineInfo(name, pubkey)
|
||||
kb.writeInfo(name, info)
|
||||
return info
|
||||
}
|
||||
|
||||
func (kb dbKeybase) writeInfo(name string, info cosmosKeys.Info) {
|
||||
// write the info by key
|
||||
key := infoKey(name)
|
||||
serializedInfo := writeInfo(info)
|
||||
kb.db.SetSync(key, serializedInfo)
|
||||
// store a pointer to the infokey by address for fast lookup
|
||||
kb.db.SetSync(addrKey(info.GetAddress()), key)
|
||||
}
|
||||
|
||||
func addrKey(address types.AccAddress) []byte {
|
||||
return []byte(fmt.Sprintf("%s.%s", address.String(), addressSuffix))
|
||||
}
|
||||
|
||||
func infoKey(name string) []byte {
|
||||
return []byte(fmt.Sprintf("%s.%s", name, infoSuffix))
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
cosmosKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
)
|
||||
|
||||
// SigningAlgo defines an algorithm to derive key-pairs which can be used for cryptographic signing.
|
||||
type SigningAlgo string
|
||||
|
||||
const (
|
||||
// Secp256k1 uses the Bitcoin secp256k1 ECDSA parameters.
|
||||
Secp256k1 = cosmosKeys.SigningAlgo("emintsecp256k1")
|
||||
)
|
||||
@@ -1,222 +0,0 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
|
||||
cosmosKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
var _ cosmosKeys.Keybase = lazyKeybase{}
|
||||
|
||||
type lazyKeybase struct {
|
||||
name string
|
||||
dir string
|
||||
}
|
||||
|
||||
// New creates a new instance of a lazy keybase.
|
||||
func New(name, dir string) cosmosKeys.Keybase {
|
||||
if err := cmn.EnsureDir(dir, 0700); err != nil {
|
||||
panic(fmt.Sprintf("failed to create Keybase directory: %s", err))
|
||||
}
|
||||
|
||||
return lazyKeybase{name: name, dir: dir}
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) List() ([]cosmosKeys.Info, error) {
|
||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
return newDbKeybase(db).List()
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) Get(name string) (cosmosKeys.Info, error) {
|
||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
return newDbKeybase(db).Get(name)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) GetByAddress(address sdk.AccAddress) (cosmosKeys.Info, error) {
|
||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
return newDbKeybase(db).GetByAddress(address)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) Delete(name, passphrase string, skipPass bool) error {
|
||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
return newDbKeybase(db).Delete(name, passphrase, skipPass)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) Sign(name, passphrase string, msg []byte) ([]byte, crypto.PubKey, error) {
|
||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
return newDbKeybase(db).Sign(name, passphrase, msg)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) CreateMnemonic(name string, language cosmosKeys.Language, passwd string, algo cosmosKeys.SigningAlgo) (info cosmosKeys.Info, seed string, err error) {
|
||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
return newDbKeybase(db).CreateMnemonic(name, language, passwd, algo)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (cosmosKeys.Info, error) {
|
||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
return newDbKeybase(db).CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, account, index)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) Derive(name, mnemonic, bip39Passwd, encryptPasswd string, params hd.BIP44Params) (cosmosKeys.Info, error) {
|
||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
return newDbKeybase(db).Derive(name, mnemonic, bip39Passwd, encryptPasswd, params)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) CreateLedger(name string, algo cosmosKeys.SigningAlgo, hrp string, account, index uint32) (info cosmosKeys.Info, err error) {
|
||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
return newDbKeybase(db).CreateLedger(name, algo, hrp, account, index)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) CreateOffline(name string, pubkey crypto.PubKey) (info cosmosKeys.Info, err error) {
|
||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
return newDbKeybase(db).CreateOffline(name, pubkey)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) CreateMulti(name string, pubkey crypto.PubKey) (info cosmosKeys.Info, err error) {
|
||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
return newDbKeybase(db).CreateMulti(name, pubkey)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) Update(name, oldpass string, getNewpass func() (string, error)) error {
|
||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
return newDbKeybase(db).Update(name, oldpass, getNewpass)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) Import(name string, armor string) (err error) {
|
||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
return newDbKeybase(db).Import(name, armor)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) ImportPrivKey(name string, armor string, passphrase string) error {
|
||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
return newDbKeybase(db).ImportPrivKey(name, armor, passphrase)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) ImportPubKey(name string, armor string) (err error) {
|
||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
return newDbKeybase(db).ImportPubKey(name, armor)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) Export(name string) (armor string, err error) {
|
||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
return newDbKeybase(db).Export(name)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) ExportPubKey(name string) (armor string, err error) {
|
||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
return newDbKeybase(db).ExportPubKey(name)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) ExportPrivateKeyObject(name string, passphrase string) (crypto.PrivKey, error) {
|
||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
return newDbKeybase(db).ExportPrivateKeyObject(name, passphrase)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) ExportPrivKey(name string, decryptPassphrase string,
|
||||
encryptPassphrase string) (armor string, err error) {
|
||||
|
||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
return newDbKeybase(db).ExportPrivKey(name, decryptPassphrase, encryptPassphrase)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) CloseDB() {}
|
||||
@@ -1,111 +0,0 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
cosmosKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
)
|
||||
|
||||
// KeyOutput defines a structure wrapping around an Info object used for output
|
||||
// functionality.
|
||||
type KeyOutput struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Address string `json:"address"`
|
||||
ETHAddress string `json:"ethaddress"`
|
||||
PubKey string `json:"pubkey"`
|
||||
ETHPubKey string `json:"ethpubkey"`
|
||||
Mnemonic string `json:"mnemonic,omitempty"`
|
||||
Threshold uint `json:"threshold,omitempty"`
|
||||
}
|
||||
|
||||
// NewKeyOutput creates a default KeyOutput instance without Mnemonic, Threshold and PubKeys
|
||||
func NewKeyOutput(name, keyType, address, ethaddress, pubkey, ethpubkey string) KeyOutput {
|
||||
return KeyOutput{
|
||||
Name: name,
|
||||
Type: keyType,
|
||||
Address: address,
|
||||
ETHAddress: ethaddress,
|
||||
PubKey: pubkey,
|
||||
ETHPubKey: ethpubkey,
|
||||
}
|
||||
}
|
||||
|
||||
// Bech32KeysOutput returns a slice of KeyOutput objects, each with the "acc"
|
||||
// Bech32 prefixes, given a slice of Info objects. It returns an error if any
|
||||
// call to Bech32KeyOutput fails.
|
||||
func Bech32KeysOutput(infos []cosmosKeys.Info) ([]KeyOutput, error) {
|
||||
kos := make([]KeyOutput, len(infos))
|
||||
for i, info := range infos {
|
||||
ko, err := Bech32KeyOutput(info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
kos[i] = ko
|
||||
}
|
||||
|
||||
return kos, nil
|
||||
}
|
||||
|
||||
// Bech32ConsKeyOutput create a KeyOutput in with "cons" Bech32 prefixes.
|
||||
func Bech32ConsKeyOutput(keyInfo cosmosKeys.Info) (KeyOutput, error) {
|
||||
address := keyInfo.GetPubKey().Address()
|
||||
|
||||
bechPubKey, err := sdk.Bech32ifyConsPub(keyInfo.GetPubKey())
|
||||
if err != nil {
|
||||
return KeyOutput{}, err
|
||||
}
|
||||
|
||||
return NewKeyOutput(
|
||||
keyInfo.GetName(),
|
||||
keyInfo.GetType().String(),
|
||||
sdk.ConsAddress(address.Bytes()).String(),
|
||||
getEthAddress(keyInfo),
|
||||
bechPubKey,
|
||||
hex.EncodeToString(keyInfo.GetPubKey().Bytes()),
|
||||
), nil
|
||||
}
|
||||
|
||||
// Bech32ValKeyOutput create a KeyOutput in with "val" Bech32 prefixes.
|
||||
func Bech32ValKeyOutput(keyInfo cosmosKeys.Info) (KeyOutput, error) {
|
||||
address := keyInfo.GetPubKey().Address()
|
||||
|
||||
bechPubKey, err := sdk.Bech32ifyValPub(keyInfo.GetPubKey())
|
||||
if err != nil {
|
||||
return KeyOutput{}, err
|
||||
}
|
||||
|
||||
return NewKeyOutput(
|
||||
keyInfo.GetName(),
|
||||
keyInfo.GetType().String(),
|
||||
sdk.ValAddress(address.Bytes()).String(),
|
||||
getEthAddress(keyInfo),
|
||||
bechPubKey,
|
||||
hex.EncodeToString(keyInfo.GetPubKey().Bytes()),
|
||||
), nil
|
||||
}
|
||||
|
||||
// Bech32KeyOutput create a KeyOutput in with "acc" Bech32 prefixes.
|
||||
func Bech32KeyOutput(keyInfo cosmosKeys.Info) (KeyOutput, error) {
|
||||
address := keyInfo.GetPubKey().Address()
|
||||
|
||||
bechPubKey, err := sdk.Bech32ifyAccPub(keyInfo.GetPubKey())
|
||||
if err != nil {
|
||||
return KeyOutput{}, err
|
||||
}
|
||||
|
||||
return NewKeyOutput(
|
||||
keyInfo.GetName(),
|
||||
keyInfo.GetType().String(),
|
||||
sdk.AccAddress(address.Bytes()).String(),
|
||||
getEthAddress(keyInfo),
|
||||
bechPubKey,
|
||||
hex.EncodeToString(keyInfo.GetPubKey().Bytes()),
|
||||
), nil
|
||||
}
|
||||
|
||||
func getEthAddress(info cosmosKeys.Info) string {
|
||||
return info.GetPubKey().Address().String()
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
cosmosKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
emintCrypto "github.com/cosmos/ethermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
|
||||
"github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// 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]
|
||||
}
|
||||
|
||||
var (
|
||||
_ cosmosKeys.Info = &localInfo{}
|
||||
_ cosmosKeys.Info = &ledgerInfo{}
|
||||
_ cosmosKeys.Info = &offlineInfo{}
|
||||
)
|
||||
|
||||
// localInfo is the public information about a locally stored key
|
||||
type localInfo struct {
|
||||
Name string `json:"name"`
|
||||
PubKey emintCrypto.PubKeySecp256k1 `json:"pubkey"`
|
||||
PrivKeyArmor string `json:"privkey.armor"`
|
||||
}
|
||||
|
||||
func newLocalInfo(name string, pub emintCrypto.PubKeySecp256k1, privArmor string) cosmosKeys.Info {
|
||||
return &localInfo{
|
||||
Name: name,
|
||||
PubKey: pub,
|
||||
PrivKeyArmor: privArmor,
|
||||
}
|
||||
}
|
||||
|
||||
func (i localInfo) GetType() cosmosKeys.KeyType {
|
||||
return cosmosKeys.TypeLocal
|
||||
}
|
||||
|
||||
func (i localInfo) GetName() string {
|
||||
return i.Name
|
||||
}
|
||||
|
||||
func (i localInfo) GetPubKey() crypto.PubKey {
|
||||
return i.PubKey
|
||||
}
|
||||
|
||||
func (i localInfo) GetAddress() types.AccAddress {
|
||||
return i.PubKey.Address().Bytes()
|
||||
}
|
||||
|
||||
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
|
||||
type ledgerInfo struct {
|
||||
Name string `json:"name"`
|
||||
PubKey emintCrypto.PubKeySecp256k1 `json:"pubkey"`
|
||||
Path hd.BIP44Params `json:"path"`
|
||||
}
|
||||
|
||||
func newLedgerInfo(name string, pub emintCrypto.PubKeySecp256k1, path hd.BIP44Params) cosmosKeys.Info {
|
||||
return &ledgerInfo{
|
||||
Name: name,
|
||||
PubKey: pub,
|
||||
Path: path,
|
||||
}
|
||||
}
|
||||
|
||||
func (i ledgerInfo) GetType() cosmosKeys.KeyType {
|
||||
return cosmosKeys.TypeLedger
|
||||
}
|
||||
|
||||
func (i ledgerInfo) GetName() string {
|
||||
return i.Name
|
||||
}
|
||||
|
||||
func (i ledgerInfo) GetPubKey() crypto.PubKey {
|
||||
return i.PubKey
|
||||
}
|
||||
|
||||
func (i ledgerInfo) GetAddress() types.AccAddress {
|
||||
return i.PubKey.Address().Bytes()
|
||||
}
|
||||
|
||||
func (i ledgerInfo) GetPath() (*hd.BIP44Params, error) {
|
||||
tmp := i.Path
|
||||
return &tmp, nil
|
||||
}
|
||||
|
||||
// offlineInfo is the public information about an offline key
|
||||
type offlineInfo struct {
|
||||
Name string `json:"name"`
|
||||
PubKey emintCrypto.PubKeySecp256k1 `json:"pubkey"`
|
||||
}
|
||||
|
||||
func newOfflineInfo(name string, pub emintCrypto.PubKeySecp256k1) cosmosKeys.Info {
|
||||
return &offlineInfo{
|
||||
Name: name,
|
||||
PubKey: pub,
|
||||
}
|
||||
}
|
||||
|
||||
func (i offlineInfo) GetType() cosmosKeys.KeyType {
|
||||
return cosmosKeys.TypeOffline
|
||||
}
|
||||
|
||||
func (i offlineInfo) GetName() string {
|
||||
return i.Name
|
||||
}
|
||||
|
||||
func (i offlineInfo) GetPubKey() crypto.PubKey {
|
||||
return i.PubKey
|
||||
}
|
||||
|
||||
func (i offlineInfo) GetAddress() types.AccAddress {
|
||||
return i.PubKey.Address().Bytes()
|
||||
}
|
||||
|
||||
func (i offlineInfo) GetPath() (*hd.BIP44Params, error) {
|
||||
return nil, fmt.Errorf("BIP44 Paths are not available for this type")
|
||||
}
|
||||
|
||||
// encoding info
|
||||
func writeInfo(i cosmosKeys.Info) []byte {
|
||||
return cdc.MustMarshalBinaryLengthPrefixed(i)
|
||||
}
|
||||
|
||||
// decoding info
|
||||
func readInfo(bz []byte) (info cosmosKeys.Info, err error) {
|
||||
err = cdc.UnmarshalBinaryLengthPrefixed(bz, &info)
|
||||
return
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
|
||||
"github.com/cosmos/ethermint/crypto"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestWriteReadInfo(t *testing.T) {
|
||||
tmpKey, err := crypto.GenerateKey()
|
||||
assert.NoError(t, err)
|
||||
pkey := tmpKey.PubKey()
|
||||
pubkey, ok := pkey.(crypto.PubKeySecp256k1)
|
||||
assert.True(t, ok)
|
||||
|
||||
info := newOfflineInfo("offline", pubkey)
|
||||
bytes := writeInfo(info)
|
||||
assert.NotNil(t, bytes)
|
||||
|
||||
regeneratedKey, err := readInfo(bytes)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, info.GetPubKey(), regeneratedKey.GetPubKey())
|
||||
assert.Equal(t, info.GetName(), regeneratedKey.GetName())
|
||||
|
||||
info = newLocalInfo("local", pubkey, "testarmor")
|
||||
bytes = writeInfo(info)
|
||||
assert.NotNil(t, bytes)
|
||||
|
||||
regeneratedKey, err = readInfo(bytes)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, info.GetPubKey(), regeneratedKey.GetPubKey())
|
||||
assert.Equal(t, info.GetName(), regeneratedKey.GetName())
|
||||
|
||||
info = newLedgerInfo("ledger", pubkey,
|
||||
hd.BIP44Params{Purpose: 1, CoinType: 1, Account: 1, Change: false, AddressIndex: 1})
|
||||
bytes = writeInfo(info)
|
||||
assert.NotNil(t, bytes)
|
||||
|
||||
regeneratedKey, err = readInfo(bytes)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, info.GetPubKey(), regeneratedKey.GetPubKey())
|
||||
assert.Equal(t, info.GetName(), regeneratedKey.GetName())
|
||||
|
||||
}
|
||||
@@ -7,9 +7,19 @@ import (
|
||||
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||
ethsecp256k1 "github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
|
||||
tmcrypto "github.com/tendermint/tendermint/crypto"
|
||||
tmamino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
||||
)
|
||||
|
||||
func init() {
|
||||
tmamino.RegisterKeyType(PubKeySecp256k1{}, PubKeyAminoName)
|
||||
tmamino.RegisterKeyType(PrivKeySecp256k1{}, PrivKeyAminoName)
|
||||
authtypes.RegisterAccountTypeCodec(PubKeySecp256k1{}, PubKeyAminoName)
|
||||
authtypes.RegisterAccountTypeCodec(PrivKeySecp256k1{}, PrivKeyAminoName)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// secp256k1 Private Key
|
||||
|
||||
|
||||
Reference in New Issue
Block a user