2082 lines
56 KiB
Go
2082 lines
56 KiB
Go
package keyring
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/99designs/keyring"
|
|
cmtcrypto "github.com/cometbft/cometbft/crypto"
|
|
"github.com/stretchr/testify/require"
|
|
"golang.org/x/crypto/bcrypt"
|
|
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
|
"github.com/cosmos/cosmos-sdk/crypto"
|
|
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
|
|
"github.com/cosmos/cosmos-sdk/crypto/hd"
|
|
cosmosbcrypt "github.com/cosmos/cosmos-sdk/crypto/keys/bcrypt"
|
|
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
|
"github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
|
|
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
|
"github.com/cosmos/cosmos-sdk/crypto/types"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
|
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
|
)
|
|
|
|
const (
|
|
someKey = "theKey"
|
|
theID = "theID"
|
|
otherID = "otherID"
|
|
)
|
|
|
|
func init() {
|
|
crypto.BcryptSecurityParameter = 1
|
|
}
|
|
|
|
func getCodec() codec.Codec {
|
|
registry := codectypes.NewInterfaceRegistry()
|
|
cryptocodec.RegisterInterfaces(registry)
|
|
return codec.NewProtoCodec(registry)
|
|
}
|
|
|
|
func TestNewKeyring(t *testing.T) {
|
|
cdc := getCodec()
|
|
|
|
tests := []struct {
|
|
name string
|
|
appName string
|
|
backend string
|
|
dir string
|
|
userInput io.Reader
|
|
cdc codec.Codec
|
|
expectedErr error
|
|
}{
|
|
{
|
|
name: "file backend",
|
|
appName: "cosmos",
|
|
backend: BackendFile,
|
|
dir: t.TempDir(),
|
|
userInput: strings.NewReader(""),
|
|
cdc: cdc,
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "unknown backend",
|
|
appName: "cosmos",
|
|
backend: "unknown",
|
|
dir: t.TempDir(),
|
|
userInput: strings.NewReader(""),
|
|
cdc: cdc,
|
|
expectedErr: ErrUnknownBacked,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kr, err := New(tt.appName, tt.backend, tt.dir, tt.userInput, tt.cdc)
|
|
if tt.expectedErr == nil {
|
|
require.NoError(t, err)
|
|
} else {
|
|
require.Error(t, err)
|
|
require.Nil(t, kr)
|
|
require.True(t, errors.Is(err, tt.expectedErr))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewMnemonic(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
backend string
|
|
reader *strings.Reader
|
|
userInput string
|
|
path string
|
|
algo SignatureAlgo
|
|
uid string
|
|
language Language
|
|
expectedError error
|
|
}{
|
|
{
|
|
name: "create new mnemonic",
|
|
backend: BackendMemory,
|
|
reader: strings.NewReader(""),
|
|
userInput: "password\npassword\n",
|
|
path: sdk.FullFundraiserPath,
|
|
algo: hd.Secp256k1,
|
|
uid: "foo",
|
|
language: English,
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "not supported algo",
|
|
backend: BackendMemory,
|
|
reader: strings.NewReader(""),
|
|
userInput: "password\npassword\n",
|
|
path: sdk.FullFundraiserPath,
|
|
algo: notSupportedAlgo{},
|
|
uid: "foo",
|
|
language: English,
|
|
expectedError: ErrUnsupportedSigningAlgo,
|
|
},
|
|
{
|
|
name: "unsupported language",
|
|
backend: BackendMemory,
|
|
reader: strings.NewReader(""),
|
|
userInput: "password\npassword\n",
|
|
path: sdk.FullFundraiserPath,
|
|
algo: hd.Secp256k1,
|
|
uid: "foo",
|
|
language: Spanish,
|
|
expectedError: ErrUnsupportedLanguage,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kr, err := New("cosmos", tt.backend, t.TempDir(), tt.reader, cdc)
|
|
require.NoError(t, err)
|
|
tt.reader.Reset(tt.userInput)
|
|
k, _, err := kr.NewMnemonic(tt.uid, tt.language, tt.path, DefaultBIP39Passphrase, tt.algo)
|
|
if tt.expectedError == nil {
|
|
require.NoError(t, err)
|
|
require.Equal(t, tt.uid, k.Name)
|
|
} else {
|
|
require.Error(t, err)
|
|
require.True(t, errors.Is(err, tt.expectedError))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestKeyringDirectory(t *testing.T) {
|
|
dir := t.TempDir()
|
|
kb, err := New("keybasename", "test", dir, nil, getCodec())
|
|
require.NoError(t, err)
|
|
|
|
// create some random directory inside the keyring directory to check migrate ignores
|
|
// all files other than *.info
|
|
newPath := filepath.Join(dir, "random")
|
|
require.NoError(t, os.Mkdir(newPath, 0o755))
|
|
items, err := os.ReadDir(dir)
|
|
require.NoError(t, err)
|
|
require.GreaterOrEqual(t, len(items), 1)
|
|
keys, err := kb.List()
|
|
require.NoError(t, err)
|
|
require.Empty(t, keys)
|
|
|
|
_, _, err = kb.NewMnemonic("uid", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
|
|
items, err = os.ReadDir(dir)
|
|
require.NoError(t, err)
|
|
require.GreaterOrEqual(t, len(items), 2)
|
|
}
|
|
|
|
func TestNewKey(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
backend string
|
|
uid string
|
|
}{
|
|
{
|
|
name: "key creation",
|
|
backend: BackendTest,
|
|
uid: "newKey",
|
|
},
|
|
{
|
|
name: "in memory key creation",
|
|
backend: BackendMemory,
|
|
uid: "newKey",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kb, err := New("keybasename", tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
|
|
// Check empty state
|
|
l, err := kb.List()
|
|
require.NoError(t, err)
|
|
require.Empty(t, l)
|
|
|
|
_, err = kb.Key(tt.uid)
|
|
require.Error(t, err)
|
|
|
|
r, _, err := kb.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
require.Equal(t, tt.uid, r.Name)
|
|
|
|
k, err := kb.Key(tt.uid)
|
|
require.NoError(t, err)
|
|
|
|
addr, err := accAddr(k)
|
|
require.NoError(t, err)
|
|
_, err = kb.KeyByAddress(addr)
|
|
require.NoError(t, err)
|
|
|
|
addr, err = sdk.AccAddressFromBech32("cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t")
|
|
require.NoError(t, err)
|
|
_, err = kb.KeyByAddress(addr)
|
|
require.NotNil(t, err)
|
|
|
|
// list shows them in order
|
|
keyS, err := kb.List()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(keyS))
|
|
require.Equal(t, tt.uid, keyS[0].Name)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetPub(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
backend string
|
|
uid string
|
|
}{
|
|
{
|
|
name: "correct get",
|
|
backend: BackendTest,
|
|
uid: "getKey",
|
|
},
|
|
{
|
|
name: "in memory correct get",
|
|
backend: BackendMemory,
|
|
uid: "getMemoryKey",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kb, err := New("keybasename", tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
|
|
r, _, err := kb.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
require.Equal(t, tt.uid, r.Name)
|
|
|
|
k, err := kb.Key(tt.uid)
|
|
require.NoError(t, err)
|
|
_, err = k.GetPubKey()
|
|
require.NoError(t, err)
|
|
|
|
keyS, err := kb.List()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(keyS))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDeleteKey(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
backend string
|
|
uid string
|
|
}{
|
|
{
|
|
name: "delete",
|
|
backend: BackendTest,
|
|
uid: "key",
|
|
},
|
|
{
|
|
name: "in memory delete",
|
|
backend: BackendMemory,
|
|
uid: "key",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kb, err := New("keybasename", tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
|
|
r, _, err := kb.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
require.Equal(t, tt.uid, r.Name)
|
|
|
|
err = kb.Delete(tt.uid)
|
|
require.NoError(t, err)
|
|
list, err := kb.List()
|
|
require.NoError(t, err)
|
|
require.Empty(t, list)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestOfflineKey(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
backend string
|
|
uid string
|
|
}{
|
|
{
|
|
name: "offline creation",
|
|
backend: BackendTest,
|
|
uid: "offline",
|
|
},
|
|
{
|
|
name: "in memory offline creation",
|
|
backend: BackendMemory,
|
|
uid: "offline",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kb, err := New("keybasename", tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
|
|
priv := ed25519.GenPrivKey()
|
|
pub := priv.PubKey()
|
|
k, err := kb.SaveOfflineKey(tt.uid, pub)
|
|
require.NoError(t, err)
|
|
require.Equal(t, tt.uid, k.Name)
|
|
|
|
key, err := k.GetPubKey()
|
|
require.NoError(t, err)
|
|
require.Equal(t, pub, key)
|
|
|
|
require.NotNil(t, k.GetOffline())
|
|
keys, err := kb.List()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(keys))
|
|
|
|
err = kb.Delete(tt.uid)
|
|
require.NoError(t, err)
|
|
keys, err = kb.List()
|
|
require.NoError(t, err)
|
|
require.Empty(t, keys)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSignVerifyKeyRing(t *testing.T) {
|
|
dir := t.TempDir()
|
|
cdc := getCodec()
|
|
|
|
kb, err := New("keybasename", "test", dir, nil, cdc)
|
|
require.NoError(t, err)
|
|
algo := hd.Secp256k1
|
|
|
|
n1, n2, n3 := "some dude", "a dudette", "dude-ish"
|
|
|
|
// create two users and get their info
|
|
kr1, _, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo)
|
|
require.Nil(t, err)
|
|
|
|
kr2, _, err := kb.NewMnemonic(n2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo)
|
|
require.Nil(t, err)
|
|
|
|
// let's try to sign some messages
|
|
d1 := []byte("my first message")
|
|
d2 := []byte("some other important info!")
|
|
d3 := []byte("feels like I forgot something...")
|
|
|
|
// try signing both data with both ..
|
|
s11, pub1, err := kb.Sign(n1, d1, signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
|
|
require.NoError(t, err)
|
|
|
|
key1, err := kr1.GetPubKey()
|
|
require.NoError(t, err)
|
|
require.NotNil(t, key1)
|
|
require.Equal(t, key1, pub1)
|
|
|
|
s12, pub1, err := kb.Sign(n1, d2, signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
|
|
require.Nil(t, err)
|
|
require.Equal(t, key1, pub1)
|
|
|
|
s21, pub2, err := kb.Sign(n2, d1, signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
|
|
require.Nil(t, err)
|
|
|
|
key2, err := kr2.GetPubKey()
|
|
require.NoError(t, err)
|
|
require.NotNil(t, key2)
|
|
require.Equal(t, key2, pub2)
|
|
|
|
s22, pub2, err := kb.Sign(n2, d2, signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
|
|
require.Nil(t, err)
|
|
require.Equal(t, key2, pub2)
|
|
|
|
// let's try to validate and make sure it only works when everything is proper
|
|
cases := []struct {
|
|
key types.PubKey
|
|
data []byte
|
|
sig []byte
|
|
valid bool
|
|
}{
|
|
// proper matches
|
|
{key1, d1, s11, true},
|
|
// change data, pubkey, or signature leads to fail
|
|
{key1, d2, s11, false},
|
|
{key2, d1, s11, false},
|
|
{key1, d1, s21, false},
|
|
// make sure other successes
|
|
{key1, d2, s12, true},
|
|
{key2, d1, s21, true},
|
|
{key2, d2, s22, true},
|
|
}
|
|
|
|
for i, tc := range cases {
|
|
valid := tc.key.VerifySignature(tc.data, tc.sig)
|
|
require.Equal(t, tc.valid, valid, "%d", i)
|
|
}
|
|
|
|
// Now try to sign data with a secret-less key
|
|
// Import a public key
|
|
armor, err := kb.ExportPubKeyArmor(n2)
|
|
require.NoError(t, err)
|
|
require.NoError(t, kb.Delete(n2))
|
|
|
|
require.NoError(t, kb.ImportPubKey(n3, armor))
|
|
i3, err := kb.Key(n3)
|
|
require.NoError(t, err)
|
|
require.Equal(t, i3.Name, n3)
|
|
|
|
_, _, err = kb.Sign(n3, d3, signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
|
|
require.Error(t, err)
|
|
require.Equal(t, "cannot sign with offline keys", err.Error())
|
|
}
|
|
|
|
func TestExportPrivKey(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
uid string
|
|
backend string
|
|
encryptPassphrase string
|
|
createKey func(keystore2 Keyring) (*Record, string, error)
|
|
expectedErr error
|
|
}{
|
|
{
|
|
name: "correct export",
|
|
uid: "correctTest",
|
|
backend: BackendTest,
|
|
encryptPassphrase: "myPassphrase",
|
|
createKey: func(keystore Keyring) (*Record, string, error) {
|
|
return keystore.NewMnemonic("correctTest", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase,
|
|
hd.Secp256k1)
|
|
},
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "correct in memory export",
|
|
uid: "inMemory",
|
|
backend: BackendMemory,
|
|
encryptPassphrase: "myPassphrase",
|
|
createKey: func(keystore Keyring) (*Record, string, error) {
|
|
return keystore.NewMnemonic("inMemory", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase,
|
|
hd.Secp256k1)
|
|
},
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "key is not created",
|
|
uid: "noKeyTest",
|
|
backend: BackendTest,
|
|
encryptPassphrase: "myPassphrase",
|
|
createKey: func(keystore Keyring) (*Record, string, error) {
|
|
return nil, "", nil
|
|
},
|
|
expectedErr: sdkerrors.ErrKeyNotFound,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kb, err := New("testExport", tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
_, _, err = tt.createKey(kb)
|
|
require.NoError(t, err)
|
|
_, err = kb.ExportPrivKeyArmor(tt.uid, tt.encryptPassphrase)
|
|
if tt.expectedErr == nil {
|
|
require.NoError(t, err)
|
|
} else {
|
|
require.Error(t, err)
|
|
require.True(t, errors.Is(err, tt.expectedErr))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestImportPrivKey(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
uid string
|
|
backend string
|
|
encryptPassphrase string
|
|
armor string
|
|
expectedErr error
|
|
}{
|
|
{
|
|
name: "correct import",
|
|
uid: "testOne",
|
|
backend: BackendTest,
|
|
encryptPassphrase: "this passphrase has been used for all test vectors",
|
|
armor: "-----BEGIN TENDERMINT PRIVATE KEY-----\nkdf: bcrypt\nsalt: 6BC5D5187F9DF241E1A1243EECFF9C17\ntype: secp256k1\n\nGDPpPfrSVZloiwufbal19fmd75QeiqwToZ949SwmnxxM03qL75xXVf3tTD/BrF4l\nFs14HuhwntDBM2xgZvymTBk2edHlEI20Phv6oC0=\n=/zZh\n-----END TENDERMINT PRIVATE KEY-----",
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "correct import",
|
|
uid: "inMemory",
|
|
backend: BackendMemory,
|
|
encryptPassphrase: "this passphrase has been used for all test vectors",
|
|
armor: "-----BEGIN TENDERMINT PRIVATE KEY-----\nkdf: bcrypt\nsalt: 6BC5D5187F9DF241E1A1243EECFF9C17\ntype: secp256k1\n\nGDPpPfrSVZloiwufbal19fmd75QeiqwToZ949SwmnxxM03qL75xXVf3tTD/BrF4l\nFs14HuhwntDBM2xgZvymTBk2edHlEI20Phv6oC0=\n=/zZh\n-----END TENDERMINT PRIVATE KEY-----",
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "wrong armor",
|
|
uid: "testWrongArmor",
|
|
backend: BackendTest,
|
|
encryptPassphrase: "this passphrase has been used for all test vectors",
|
|
armor: "-----BEGIN TENDERMINT PRIVATE KEY-----\nkdf: bcrypt\nsalt: 7BC5D5187F9DF241E1A1243EECFF9C17\ntype: secp256k1\n\nGDPpPfrSVZloiwufbal19fmd75QeiqwToZ949SwmnxxM03qL75xXVf3tTD/BrF4l\nFs14HuhwntDBM2xgZvymTBk2edHlEI20Phv6oC0=\n=/zZh\n-----END TENDERMINT PRIVATE KEY-----",
|
|
expectedErr: sdkerrors.ErrWrongPassword,
|
|
},
|
|
{
|
|
name: "incorrect passphrase",
|
|
uid: "testIncorrectPassphrase",
|
|
backend: BackendTest,
|
|
encryptPassphrase: "wrong passphrase",
|
|
armor: "-----BEGIN TENDERMINT PRIVATE KEY-----\nkdf: bcrypt\nsalt: 6BC5D5187F9DF241E1A1243EECFF9C17\ntype: secp256k1\n\nGDPpPfrSVZloiwufbal19fmd75QeiqwToZ949SwmnxxM03qL75xXVf3tTD/BrF4l\nFs14HuhwntDBM2xgZvymTBk2edHlEI20Phv6oC0=\n=/zZh\n-----END TENDERMINT PRIVATE KEY-----",
|
|
expectedErr: sdkerrors.ErrWrongPassword,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kb, err := New("TestExport", tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
err = kb.ImportPrivKey(tt.uid, tt.armor, tt.encryptPassphrase)
|
|
if tt.expectedErr == nil {
|
|
require.NoError(t, err)
|
|
} else {
|
|
require.Error(t, err)
|
|
require.True(t, errors.Is(err, tt.expectedErr))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestImportPrivKeyHex(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
uid string
|
|
backend string
|
|
hexKey string
|
|
algo string
|
|
expectedErr error
|
|
}{
|
|
{
|
|
name: "correct import",
|
|
uid: "hexImport",
|
|
backend: BackendTest,
|
|
hexKey: "0xa3e57952e835ed30eea86a2993ac2a61c03e74f2085b3635bd94aa4d7ae0cfdf",
|
|
algo: "secp256k1",
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "correct import without prefix",
|
|
uid: "hexImport",
|
|
backend: BackendTest,
|
|
hexKey: "a3e57952e835ed30eea86a2993ac2a61c03e74f2085b3635bd94aa4d7ae0cfdf",
|
|
algo: "secp256k1",
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "wrong hex length",
|
|
uid: "hexImport",
|
|
backend: BackendTest,
|
|
hexKey: "0xae57952e835ed30eea86a2993ac2a61c03e74f2085b3635bd94aa4d7ae0cfdf",
|
|
algo: "secp256k1",
|
|
expectedErr: hex.ErrLength,
|
|
},
|
|
{
|
|
name: "unsupported algo",
|
|
uid: "hexImport",
|
|
backend: BackendTest,
|
|
hexKey: "0xa3e57952e835ed30eea86a2993ac2a61c03e74f2085b3635bd94aa4d7ae0cfdf",
|
|
algo: "notSupportedAlgo",
|
|
expectedErr: ErrUnsupportedSigningAlgo,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kb, err := New("TestExport", tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
err = kb.ImportPrivKeyHex(tt.uid, tt.hexKey, tt.algo)
|
|
if tt.expectedErr == nil {
|
|
require.NoError(t, err)
|
|
} else {
|
|
require.Error(t, err)
|
|
require.True(t, errors.Is(err, tt.expectedErr))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestExportImportPrivKeyArmor(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
uid string
|
|
backend string
|
|
userInput io.Reader
|
|
encryptPassphrase string
|
|
importUID string
|
|
importPassphrase string
|
|
}{
|
|
{
|
|
name: "export import",
|
|
uid: "testOne",
|
|
backend: BackendTest,
|
|
userInput: nil,
|
|
encryptPassphrase: "apassphrase",
|
|
importUID: "importedKey",
|
|
importPassphrase: "apassphrase",
|
|
},
|
|
{
|
|
name: "memory export import",
|
|
uid: "inMemory",
|
|
backend: BackendMemory,
|
|
userInput: nil,
|
|
encryptPassphrase: "apassphrase",
|
|
importUID: "importedKey",
|
|
importPassphrase: "apassphrase",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kb, err := New("TestExport", tt.backend, t.TempDir(), tt.userInput, cdc)
|
|
require.NoError(t, err)
|
|
k, _, err := kb.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, k)
|
|
require.Equal(t, k.Name, tt.uid)
|
|
|
|
record, err := kb.Key(tt.uid)
|
|
require.NoError(t, err)
|
|
require.Equal(t, record.Name, tt.uid)
|
|
key, err := k.GetPubKey()
|
|
require.NoError(t, err)
|
|
|
|
armor, err := kb.ExportPrivKeyArmor(tt.uid, tt.encryptPassphrase)
|
|
require.NoError(t, err)
|
|
|
|
// Import while key has not been deleted
|
|
err = kb.ImportPrivKey(tt.uid, armor, tt.importPassphrase)
|
|
require.Error(t, err)
|
|
require.True(t, errors.Is(err, ErrOverwriteKey))
|
|
|
|
err = kb.Delete(tt.uid)
|
|
require.NoError(t, err)
|
|
|
|
err = kb.ImportPrivKey(tt.importUID, armor, tt.importPassphrase)
|
|
require.NoError(t, err)
|
|
|
|
importedRecord, err := kb.Key(tt.importUID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, importedRecord.Name, tt.importUID)
|
|
importedKey, err := importedRecord.GetPubKey()
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, key.Address(), importedKey.Address())
|
|
|
|
addr, err := record.GetAddress()
|
|
require.NoError(t, err)
|
|
importedAddr, err := importedRecord.GetAddress()
|
|
require.NoError(t, err)
|
|
require.True(t, addr.Equals(importedAddr))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestImportExportPrivKeyByAddress(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
uid string
|
|
backend string
|
|
passphrase string
|
|
importPassphrase string
|
|
expectedErr error
|
|
}{
|
|
{
|
|
name: "correct import export",
|
|
uid: "okTest",
|
|
backend: BackendTest,
|
|
passphrase: "exportKey",
|
|
importPassphrase: "exportKey",
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "correct in memory import export",
|
|
uid: "inMemory",
|
|
backend: BackendMemory,
|
|
passphrase: "exportKey",
|
|
importPassphrase: "exportKey",
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "wrong passphrase import",
|
|
uid: "incorrectPass",
|
|
backend: BackendTest,
|
|
passphrase: "exportKey",
|
|
importPassphrase: "incorrectPassphrase",
|
|
expectedErr: sdkerrors.ErrWrongPassword,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kr, err := New(t.Name(), tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
|
|
mnemonic, _, err := kr.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
|
|
addr, err := mnemonic.GetAddress()
|
|
require.NoError(t, err)
|
|
armor, err := kr.ExportPrivKeyArmorByAddress(addr, tt.passphrase)
|
|
require.NoError(t, err)
|
|
|
|
// Should fail importing private key on existing key.
|
|
err = kr.ImportPrivKey(tt.uid, armor, tt.passphrase)
|
|
require.True(t, errors.Is(err, ErrOverwriteKey))
|
|
|
|
err = kr.Delete(tt.uid)
|
|
require.NoError(t, err)
|
|
|
|
err = kr.ImportPrivKey(tt.uid, armor, tt.importPassphrase)
|
|
if tt.expectedErr == nil {
|
|
require.NoError(t, err)
|
|
} else {
|
|
require.Error(t, err)
|
|
require.True(t, errors.Is(err, tt.expectedErr))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestExportPubkey(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
uid string
|
|
backend string
|
|
exportUID string
|
|
getPubkey func(r *Record) (types.PubKey, error)
|
|
codec codec.Codec
|
|
expectedErr error
|
|
}{
|
|
{
|
|
name: "correct export",
|
|
uid: "correctExport",
|
|
backend: BackendTest,
|
|
exportUID: "correctExport",
|
|
getPubkey: func(r *Record) (types.PubKey, error) {
|
|
return r.GetPubKey()
|
|
},
|
|
codec: cdc,
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "wrong uid at export",
|
|
uid: "wrongUID",
|
|
backend: BackendTest,
|
|
exportUID: "notAValidUID",
|
|
getPubkey: func(r *Record) (types.PubKey, error) {
|
|
return r.GetPubKey()
|
|
},
|
|
codec: cdc,
|
|
expectedErr: sdkerrors.ErrKeyNotFound,
|
|
},
|
|
{
|
|
name: "previous space on export uid",
|
|
uid: "prefixSpace",
|
|
backend: BackendTest,
|
|
exportUID: " prefixSpace",
|
|
getPubkey: func(r *Record) (types.PubKey, error) {
|
|
return r.GetPubKey()
|
|
},
|
|
codec: cdc,
|
|
expectedErr: sdkerrors.ErrKeyNotFound,
|
|
},
|
|
{
|
|
name: "export uid with suffix space",
|
|
uid: "suffixSpace",
|
|
backend: BackendTest,
|
|
exportUID: "suffixSpace ",
|
|
getPubkey: func(r *Record) (types.PubKey, error) {
|
|
return r.GetPubKey()
|
|
},
|
|
codec: cdc,
|
|
expectedErr: sdkerrors.ErrKeyNotFound,
|
|
},
|
|
{
|
|
name: "correct in memory export",
|
|
uid: "inMemory",
|
|
backend: BackendMemory,
|
|
exportUID: "inMemory",
|
|
getPubkey: func(r *Record) (types.PubKey, error) {
|
|
return r.GetPubKey()
|
|
},
|
|
codec: cdc,
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "in memory wrong uid at export",
|
|
uid: "wrongUid",
|
|
backend: BackendMemory,
|
|
exportUID: "notAValidUid",
|
|
getPubkey: func(r *Record) (types.PubKey, error) {
|
|
return r.GetPubKey()
|
|
},
|
|
codec: cdc,
|
|
expectedErr: sdkerrors.ErrKeyNotFound,
|
|
},
|
|
{
|
|
name: "in memory previous space on export uid",
|
|
uid: "prefixSpace",
|
|
backend: BackendMemory,
|
|
exportUID: " prefixSpace",
|
|
getPubkey: func(r *Record) (types.PubKey, error) {
|
|
return r.GetPubKey()
|
|
},
|
|
codec: cdc,
|
|
expectedErr: sdkerrors.ErrKeyNotFound,
|
|
},
|
|
{
|
|
name: "in memory export uid with suffix space",
|
|
uid: "suffixSpace",
|
|
backend: BackendMemory,
|
|
exportUID: "suffixSpace ",
|
|
getPubkey: func(r *Record) (types.PubKey, error) {
|
|
return r.GetPubKey()
|
|
},
|
|
codec: cdc,
|
|
expectedErr: sdkerrors.ErrKeyNotFound,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kb, err := New("keybase", tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
k, _, err := kb.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, k)
|
|
_, err = tt.getPubkey(k)
|
|
require.NoError(t, err)
|
|
_, err = kb.ExportPubKeyArmor(tt.exportUID)
|
|
if tt.expectedErr == nil {
|
|
require.NoError(t, err)
|
|
} else {
|
|
require.Error(t, err)
|
|
require.True(t, errors.Is(err, tt.expectedErr))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestImportPubKey(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
uid string
|
|
backend string
|
|
armor string
|
|
expectedErr string
|
|
}{
|
|
{
|
|
name: "correct import",
|
|
uid: "correctTest",
|
|
backend: BackendTest,
|
|
armor: "-----BEGIN TENDERMINT PUBLIC KEY-----\nversion: 0.0.1\ntype: secp256k1\n\nCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQOlcgxiZM4cR0LA\nwum483+L6zRnXC6zEKtQ4FEa6z0VrA==\n=CqBG\n-----END TENDERMINT PUBLIC KEY-----",
|
|
expectedErr: "",
|
|
},
|
|
{
|
|
name: "modified armor",
|
|
uid: "modified",
|
|
backend: BackendTest,
|
|
armor: "-----BEGIN TENDERMINT PUBLIC KEY-----\nversion: 0.0.1\ntype: secp256k1\n\nCh8vY29zbW8zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQOlcgxiZM4cR0LA\nwum483+L6zRnXC6zEKtQ4FEa6z0VrA==\n=CqBG\n-----END TENDERMINT PUBLIC KEY-----",
|
|
expectedErr: "couldn't unarmor bytes: openpgp: invalid data: armor invalid",
|
|
},
|
|
{
|
|
name: "empty armor",
|
|
uid: "empty",
|
|
backend: BackendTest,
|
|
armor: "",
|
|
expectedErr: "couldn't unarmor bytes: EOF",
|
|
},
|
|
{
|
|
name: "correct in memory import",
|
|
uid: "inMemory",
|
|
backend: BackendMemory,
|
|
armor: "-----BEGIN TENDERMINT PUBLIC KEY-----\nversion: 0.0.1\ntype: secp256k1\n\nCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQOlcgxiZM4cR0LA\nwum483+L6zRnXC6zEKtQ4FEa6z0VrA==\n=CqBG\n-----END TENDERMINT PUBLIC KEY-----",
|
|
expectedErr: "",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kb, err := New("keybasename", tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
err = kb.ImportPubKey(tt.uid, tt.armor)
|
|
if tt.expectedErr == "" {
|
|
require.NoError(t, err)
|
|
} else {
|
|
require.ErrorContains(t, err, tt.expectedErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestExportImportPubKeyKey(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
uid string
|
|
backend string
|
|
importUID string
|
|
}{
|
|
{
|
|
name: "complete export import",
|
|
uid: "testOne",
|
|
backend: BackendTest,
|
|
importUID: "importedKey",
|
|
},
|
|
{
|
|
name: "in memory export import",
|
|
uid: "inMemory",
|
|
backend: BackendMemory,
|
|
importUID: "importedKey",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kb, err := New("keybasename", tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
|
|
k, _, err := kb.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
|
require.Nil(t, err)
|
|
require.NotNil(t, k)
|
|
require.Equal(t, k.Name, tt.uid)
|
|
|
|
key, err := k.GetPubKey()
|
|
require.NoError(t, err)
|
|
|
|
record, err := kb.Key(tt.uid)
|
|
require.NoError(t, err)
|
|
require.Equal(t, record.Name, tt.uid)
|
|
|
|
pk, err := record.GetPubKey()
|
|
require.NoError(t, err)
|
|
require.Equal(t, key.Address(), pk.Address())
|
|
|
|
// Export the public key only
|
|
armor, err := kb.ExportPubKeyArmor(tt.uid)
|
|
require.NoError(t, err)
|
|
err = kb.Delete(tt.uid)
|
|
require.NoError(t, err)
|
|
|
|
// Import it under a different name
|
|
err = kb.ImportPubKey(tt.importUID, armor)
|
|
require.NoError(t, err)
|
|
|
|
// Ensure consistency
|
|
record2, err := kb.Key(tt.importUID)
|
|
require.NoError(t, err)
|
|
key2, err := record2.GetPubKey()
|
|
require.NoError(t, err)
|
|
|
|
// Compare the public keys
|
|
require.True(t, key.Equals(key2))
|
|
|
|
// Ensure keys cannot be overwritten
|
|
err = kb.ImportPubKey(tt.importUID, armor)
|
|
require.NotNil(t, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestImportExportPubKeyByAddress(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
backend string
|
|
uid string
|
|
}{
|
|
{
|
|
name: "import export",
|
|
backend: BackendTest,
|
|
uid: "okTest",
|
|
},
|
|
{
|
|
name: "in memory import export",
|
|
backend: BackendMemory,
|
|
uid: "okTest",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kr, err := New(t.Name(), tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
|
|
mnemonic, _, err := kr.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
|
|
addr, err := mnemonic.GetAddress()
|
|
require.NoError(t, err)
|
|
armor, err := kr.ExportPubKeyArmorByAddress(addr)
|
|
require.NoError(t, err)
|
|
|
|
// Should fail importing private key on existing key.
|
|
err = kr.ImportPubKey(tt.uid, armor)
|
|
require.True(t, errors.Is(err, ErrOverwriteKey))
|
|
|
|
err = kr.Delete(tt.uid)
|
|
require.NoError(t, err)
|
|
|
|
err = kr.ImportPubKey(tt.uid, armor)
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAltKeyring_UnsafeExportPrivKeyHex(t *testing.T) {
|
|
cdc := getCodec()
|
|
kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
|
|
uid := theID
|
|
|
|
_, _, err = kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
|
|
privKey, err := kr.(keystore).ExportPrivateKeyObject(uid)
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, 64, len(hex.EncodeToString(privKey.Bytes())))
|
|
|
|
// test error on non existing key
|
|
_, err = kr.(keystore).ExportPrivateKeyObject("non-existing")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestNewAccount(t *testing.T) {
|
|
cdc := getCodec()
|
|
|
|
tests := []struct {
|
|
name string
|
|
backend string
|
|
uid string
|
|
bip39Passphrease string
|
|
hdpath string
|
|
algo SignatureAlgo
|
|
mnemonic string
|
|
expectedErr error
|
|
}{
|
|
{
|
|
name: "correct mnemonic",
|
|
uid: "correctTest",
|
|
backend: BackendTest,
|
|
hdpath: sdk.FullFundraiserPath,
|
|
bip39Passphrease: "",
|
|
algo: hd.Secp256k1,
|
|
mnemonic: "aunt imitate maximum student guard unhappy guard rotate marine panel negative merit record priority zoo voice mixture boost describe fruit often occur expect teach",
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "correct in memory mnemonic",
|
|
uid: "inMemory",
|
|
backend: BackendMemory,
|
|
hdpath: sdk.FullFundraiserPath,
|
|
bip39Passphrease: "",
|
|
algo: hd.Secp256k1,
|
|
mnemonic: "aunt imitate maximum student guard unhappy guard rotate marine panel negative merit record priority zoo voice mixture boost describe fruit often occur expect teach",
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "unsupported Algo",
|
|
uid: "correctTest",
|
|
backend: BackendTest,
|
|
hdpath: sdk.FullFundraiserPath,
|
|
bip39Passphrease: "",
|
|
algo: notSupportedAlgo{},
|
|
mnemonic: "aunt imitate maximum student guard unhappy guard rotate marine panel negative merit record priority zoo voice mixture boost describe fruit often occur expect teach",
|
|
expectedErr: ErrUnsupportedSigningAlgo,
|
|
},
|
|
{
|
|
name: "wrong mnemonic",
|
|
uid: "wrongMnemonic",
|
|
backend: BackendTest,
|
|
hdpath: sdk.FullFundraiserPath,
|
|
bip39Passphrease: "",
|
|
algo: hd.Secp256k1,
|
|
mnemonic: "fresh enact fresh ski large bicycle marine abandon motor end pact mixture annual elite bind fan write warrior adapt common manual cool happy dutch",
|
|
expectedErr: errors.New("invalid byte at position"),
|
|
},
|
|
{
|
|
name: "in memory invalid mnemonic",
|
|
uid: "memoryInvalid",
|
|
backend: BackendMemory,
|
|
hdpath: sdk.FullFundraiserPath,
|
|
bip39Passphrease: "",
|
|
algo: hd.Secp256k1,
|
|
mnemonic: "malarkey pair crucial catch public canyon evil outer stage ten gym tornado",
|
|
expectedErr: errors.New("invalid mnemonic"),
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kb, err := New("keybasename", tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
k1, err := kb.NewAccount(tt.uid, tt.mnemonic, DefaultBIP39Passphrase, tt.hdpath, tt.algo)
|
|
if tt.expectedErr == nil {
|
|
require.NoError(t, err)
|
|
require.Equal(t, tt.uid, k1.Name)
|
|
} else {
|
|
require.Error(t, err)
|
|
require.ErrorContains(t, err, err.Error())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestInMemoryWithKeyring(t *testing.T) {
|
|
priv := types.PrivKey(secp256k1.GenPrivKey())
|
|
pub := priv.PubKey()
|
|
|
|
cdc := getCodec()
|
|
_, err := NewLocalRecord("test record", priv, pub)
|
|
require.NoError(t, err)
|
|
|
|
multi := multisig.NewLegacyAminoPubKey(
|
|
1, []types.PubKey{
|
|
pub,
|
|
},
|
|
)
|
|
|
|
appName := "test-app"
|
|
|
|
legacyMultiInfo, err := NewLegacyMultiInfo(appName, multi)
|
|
require.NoError(t, err)
|
|
serializedLegacyMultiInfo := MarshalInfo(legacyMultiInfo)
|
|
|
|
kb := NewInMemoryWithKeyring(keyring.NewArrayKeyring([]keyring.Item{
|
|
{
|
|
Key: appName + ".info",
|
|
Data: serializedLegacyMultiInfo,
|
|
Description: "test description",
|
|
},
|
|
}), cdc)
|
|
|
|
t.Run("key exists", func(t *testing.T) {
|
|
_, err := kb.Key(appName)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("key deleted", func(t *testing.T) {
|
|
err := kb.Delete(appName)
|
|
require.NoError(t, err)
|
|
|
|
t.Run("key is gone", func(t *testing.T) {
|
|
_, err := kb.Key(appName)
|
|
require.Error(t, err)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestInMemoryCreateMultisig(t *testing.T) {
|
|
cdc := getCodec()
|
|
kb, err := New("keybasename", "memory", "", nil, cdc)
|
|
require.NoError(t, err)
|
|
multi := multisig.NewLegacyAminoPubKey(
|
|
1, []types.PubKey{
|
|
secp256k1.GenPrivKey().PubKey(),
|
|
},
|
|
)
|
|
_, err = kb.SaveMultisig("multi", multi)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// TestInMemorySignVerify does some detailed checks on how we sign and validate
|
|
// signatures
|
|
func TestInMemorySignVerify(t *testing.T) {
|
|
cdc := getCodec()
|
|
cstore := NewInMemory(cdc)
|
|
algo := hd.Secp256k1
|
|
|
|
n1, n2, n3 := "some dude", "a dudette", "dude-ish"
|
|
|
|
// create two users and get their info
|
|
kr1, _, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo)
|
|
require.Nil(t, err)
|
|
|
|
kr2, _, err := cstore.NewMnemonic(n2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo)
|
|
require.Nil(t, err)
|
|
|
|
// let's try to sign some messages
|
|
d1 := []byte("my first message")
|
|
d2 := []byte("some other important info!")
|
|
d3 := []byte("feels like I forgot something...")
|
|
|
|
// try signing both data with both ..
|
|
s11, pub1, err := cstore.Sign(n1, d1, signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
|
|
require.Nil(t, err)
|
|
key1, err := kr1.GetPubKey()
|
|
require.NoError(t, err)
|
|
require.Equal(t, key1, pub1)
|
|
|
|
s12, pub1, err := cstore.Sign(n1, d2, signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
|
|
require.Nil(t, err)
|
|
require.Equal(t, key1, pub1)
|
|
|
|
s21, pub2, err := cstore.Sign(n2, d1, signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
|
|
require.Nil(t, err)
|
|
key2, err := kr2.GetPubKey()
|
|
require.NoError(t, err)
|
|
require.Equal(t, key2, pub2)
|
|
|
|
s22, pub2, err := cstore.Sign(n2, d2, signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
|
|
require.Nil(t, err)
|
|
require.Equal(t, key2, pub2)
|
|
|
|
// let's try to validate and make sure it only works when everything is proper
|
|
cases := []struct {
|
|
key types.PubKey
|
|
data []byte
|
|
sig []byte
|
|
valid bool
|
|
}{
|
|
// proper matches
|
|
{key1, d1, s11, true},
|
|
// change data, pubkey, or signature leads to fail
|
|
{key1, d2, s11, false},
|
|
{key2, d1, s11, false},
|
|
{key1, d1, s21, false},
|
|
// make sure other successes
|
|
{key1, d2, s12, true},
|
|
{key2, d1, s21, true},
|
|
{key2, d2, s22, true},
|
|
}
|
|
|
|
for i, tc := range cases {
|
|
valid := tc.key.VerifySignature(tc.data, tc.sig)
|
|
require.Equal(t, tc.valid, valid, "%d", i)
|
|
}
|
|
|
|
// Import a public key
|
|
armor, err := cstore.ExportPubKeyArmor(n2)
|
|
require.Nil(t, err)
|
|
err = cstore.Delete(n2)
|
|
require.NoError(t, err)
|
|
err = cstore.ImportPubKey(n3, armor)
|
|
require.NoError(t, err)
|
|
i3, err := cstore.Key(n3)
|
|
require.NoError(t, err)
|
|
require.Equal(t, i3.Name, n3)
|
|
|
|
// Now try to sign data with a secret-less key
|
|
_, _, err = cstore.Sign(n3, d3, signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
|
|
require.Error(t, err)
|
|
require.Equal(t, "cannot sign with offline keys", err.Error())
|
|
}
|
|
|
|
// TestInMemorySeedPhrase verifies restoring from a seed phrase
|
|
func TestInMemorySeedPhrase(t *testing.T) {
|
|
// make the storage with reasonable defaults
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
uid string
|
|
importUID string
|
|
}{
|
|
{
|
|
name: "correct in memory seed",
|
|
uid: "okTest",
|
|
importUID: "imported",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
cstore := NewInMemory(cdc)
|
|
|
|
// make sure key works with initial password
|
|
k, mnemonic, err := cstore.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
|
require.Nil(t, err, "%+v", err)
|
|
require.Equal(t, tt.uid, k.Name)
|
|
require.NotEmpty(t, mnemonic)
|
|
|
|
// now, let us delete this key
|
|
err = cstore.Delete(tt.uid)
|
|
require.Nil(t, err, "%+v", err)
|
|
_, err = cstore.Key(tt.uid)
|
|
require.NotNil(t, err)
|
|
|
|
// let us re-create it from the mnemonic-phrase
|
|
hdPath := hd.NewFundraiserParams(0, sdk.CoinType, 0).String()
|
|
k1, err := cstore.NewAccount(tt.importUID, mnemonic, DefaultBIP39Passphrase, hdPath, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
require.Equal(t, tt.importUID, k1.Name)
|
|
key, err := k.GetPubKey()
|
|
require.NoError(t, err)
|
|
key1, err := k1.GetPubKey()
|
|
require.NoError(t, err)
|
|
require.Equal(t, key.Address(), key1.Address())
|
|
require.Equal(t, key, key1)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestKeyChain_ShouldFailWhenAddingSameGeneratedAccount(t *testing.T) {
|
|
cdc := getCodec()
|
|
kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
|
|
// Given we create a mnemonic
|
|
_, seed, err := kr.NewMnemonic("test", English, "", DefaultBIP39Passphrase, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, kr.Delete("test"))
|
|
|
|
path := hd.CreateHDPath(118, 0, 0).String()
|
|
_, err = kr.NewAccount("test1", seed, "", path, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
|
|
// Creating another account with different uid but same seed should fail due to have same pub address
|
|
_, err = kr.NewAccount("test2", seed, "", path, hd.Secp256k1)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func ExampleNew() {
|
|
// Select the encryption and storage for your cryptostore
|
|
cdc := getCodec()
|
|
cstore := NewInMemory(cdc)
|
|
|
|
sec := hd.Secp256k1
|
|
|
|
// Add keys and see they return in alphabetical order
|
|
bob, _, err := cstore.NewMnemonic("Bob", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, sec)
|
|
if err != nil {
|
|
// this should never happen
|
|
fmt.Println(err)
|
|
} else {
|
|
// return info here just like in List
|
|
fmt.Println(bob.Name)
|
|
}
|
|
_, _, _ = cstore.NewMnemonic("Alice", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, sec)
|
|
_, _, _ = cstore.NewMnemonic("Carl", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, sec)
|
|
records, _ := cstore.List()
|
|
for _, k := range records {
|
|
fmt.Println(k.Name)
|
|
}
|
|
|
|
// We need to use passphrase to generate a signature
|
|
tx := []byte("deadbeef")
|
|
sig, pub, err := cstore.Sign("Bob", tx, signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
|
|
if err != nil {
|
|
fmt.Println("don't accept real passphrase")
|
|
}
|
|
|
|
// and we can validate the signature with publicly available info
|
|
bRecord, _ := cstore.Key("Bob")
|
|
key, _ := bRecord.GetPubKey()
|
|
bobKey, _ := bob.GetPubKey()
|
|
if !key.Equals(bobKey) {
|
|
fmt.Println("Get and Create return different keys")
|
|
}
|
|
|
|
if pub.Equals(key) {
|
|
fmt.Println("signed by Bob")
|
|
}
|
|
if !pub.VerifySignature(tx, sig) {
|
|
fmt.Println("invalid signature")
|
|
}
|
|
|
|
// Output:
|
|
// Bob
|
|
// Alice
|
|
// Bob
|
|
// Carl
|
|
// signed by Bob
|
|
}
|
|
|
|
func TestAltKeyring_List(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
backend string
|
|
uids []string
|
|
}{
|
|
{
|
|
name: "correct list",
|
|
backend: BackendTest,
|
|
uids: []string{"Bkey", "Rkey", "Zkey"},
|
|
},
|
|
{
|
|
name: "empty list",
|
|
backend: BackendTest,
|
|
uids: nil,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kr, err := New("listKeys", tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
|
|
list, err := kr.List()
|
|
require.NoError(t, err)
|
|
require.Empty(t, list)
|
|
|
|
for _, uid := range tt.uids {
|
|
_, _, err = kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
}
|
|
list, err = kr.List()
|
|
require.NoError(t, err)
|
|
require.Len(t, list, len(tt.uids))
|
|
|
|
for i := range tt.uids {
|
|
require.Equal(t, tt.uids[i], list[i].Name)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAltKeyring_Get(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
backend string
|
|
uid string
|
|
uidToFind string
|
|
expectedErr error
|
|
}{
|
|
{
|
|
name: "correct get",
|
|
backend: BackendTest,
|
|
uid: "okTest",
|
|
uidToFind: "okTest",
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "not found key",
|
|
backend: BackendTest,
|
|
uid: "notFoundUid",
|
|
uidToFind: "notFound",
|
|
expectedErr: sdkerrors.ErrKeyNotFound,
|
|
},
|
|
{
|
|
name: "in memory correct get",
|
|
backend: BackendMemory,
|
|
uid: "okTest",
|
|
uidToFind: "okTest",
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "in memory not found key",
|
|
backend: BackendMemory,
|
|
uid: "notFoundUid",
|
|
uidToFind: "notFound",
|
|
expectedErr: sdkerrors.ErrKeyNotFound,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kr, err := New(tt.name, tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
|
|
mnemonic, _, err := kr.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
|
|
key, err := kr.Key(tt.uidToFind)
|
|
if tt.expectedErr == nil {
|
|
require.NoError(t, err)
|
|
requireEqualRenamedKey(t, mnemonic, key, true)
|
|
} else {
|
|
require.Error(t, err)
|
|
require.True(t, errors.Is(err, tt.expectedErr))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAltKeyring_KeyByAddress(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
backend string
|
|
uid string
|
|
getAddres func(*Record) (sdk.AccAddress, error)
|
|
expectedErr error
|
|
}{
|
|
{
|
|
name: "correct get",
|
|
backend: BackendTest,
|
|
uid: "okTest",
|
|
getAddres: func(k *Record) (sdk.AccAddress, error) {
|
|
return k.GetAddress()
|
|
},
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "not found key",
|
|
backend: BackendTest,
|
|
uid: "notFoundUid",
|
|
getAddres: func(k *Record) (sdk.AccAddress, error) {
|
|
return nil, nil
|
|
},
|
|
expectedErr: sdkerrors.ErrKeyNotFound,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kr, err := New(tt.name, tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
|
|
mnemonic, _, err := kr.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
addr, err := tt.getAddres(mnemonic)
|
|
require.NoError(t, err)
|
|
|
|
key, err := kr.KeyByAddress(addr)
|
|
if tt.expectedErr == nil {
|
|
require.NoError(t, err)
|
|
requireEqualRenamedKey(t, mnemonic, key, true)
|
|
} else {
|
|
require.Error(t, err)
|
|
require.True(t, errors.Is(err, tt.expectedErr))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAltKeyring_Delete(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
backend string
|
|
uid string
|
|
uidToDelete string
|
|
expectedErr error
|
|
}{
|
|
{
|
|
name: "correct delete",
|
|
backend: BackendTest,
|
|
uid: "deleteKey",
|
|
uidToDelete: "deleteKey",
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "not found delete",
|
|
backend: BackendTest,
|
|
uid: "deleteKey",
|
|
uidToDelete: "notFound",
|
|
expectedErr: sdkerrors.ErrKeyNotFound,
|
|
},
|
|
{
|
|
name: "in memory correct delete",
|
|
backend: BackendMemory,
|
|
uid: "inMemoryDeleteKey",
|
|
uidToDelete: "inMemoryDeleteKey",
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "in memory not found delete",
|
|
backend: BackendMemory,
|
|
uid: "inMemoryDeleteKey",
|
|
uidToDelete: "notFound",
|
|
expectedErr: sdkerrors.ErrKeyNotFound,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kr, err := New(t.Name(), tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
|
|
_, _, err = kr.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
|
|
list, err := kr.List()
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 1)
|
|
|
|
err = kr.Delete(tt.uidToDelete)
|
|
list, listErr := kr.List()
|
|
require.NoError(t, listErr)
|
|
if tt.expectedErr == nil {
|
|
require.NoError(t, err)
|
|
require.Empty(t, list)
|
|
} else {
|
|
require.Error(t, err)
|
|
require.True(t, errors.Is(err, tt.expectedErr))
|
|
require.Len(t, list, 1)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAltKeyring_DeleteByAddress(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
backend string
|
|
uid string
|
|
getAddres func(*Record) (sdk.AccAddress, error)
|
|
expectedErr error
|
|
}{
|
|
{
|
|
name: "correct delete",
|
|
backend: BackendTest,
|
|
uid: "okTest",
|
|
getAddres: func(k *Record) (sdk.AccAddress, error) {
|
|
return k.GetAddress()
|
|
},
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "not found",
|
|
backend: BackendTest,
|
|
uid: "notFoundUid",
|
|
getAddres: func(k *Record) (sdk.AccAddress, error) {
|
|
return nil, nil
|
|
},
|
|
expectedErr: sdkerrors.ErrKeyNotFound,
|
|
},
|
|
{
|
|
name: "in memory correct delete",
|
|
backend: BackendMemory,
|
|
uid: "inMemory",
|
|
getAddres: func(k *Record) (sdk.AccAddress, error) {
|
|
return k.GetAddress()
|
|
},
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "in memory not found",
|
|
backend: BackendMemory,
|
|
uid: "inMemoryNotFoundUid",
|
|
getAddres: func(k *Record) (sdk.AccAddress, error) {
|
|
return nil, nil
|
|
},
|
|
expectedErr: sdkerrors.ErrKeyNotFound,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kr, err := New(tt.name, tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
|
|
mnemonic, _, err := kr.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
addr, err := tt.getAddres(mnemonic)
|
|
require.NoError(t, err)
|
|
|
|
err = kr.DeleteByAddress(addr)
|
|
list, listErr := kr.List()
|
|
require.NoError(t, listErr)
|
|
if tt.expectedErr == nil {
|
|
require.NoError(t, err)
|
|
require.Empty(t, list)
|
|
} else {
|
|
require.Error(t, err)
|
|
require.True(t, errors.Is(err, tt.expectedErr))
|
|
require.Len(t, list, 1)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TODO: review
|
|
func TestAltKeyring_SaveOfflineKey(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
backend string
|
|
uid string
|
|
pubKey string
|
|
}{
|
|
{
|
|
name: "correct save",
|
|
backend: BackendTest,
|
|
uid: "okSave",
|
|
pubKey: "cfd96f5e00069b64ddb8bfa433941400ab674db42436ae08bc9c74f3b5ade896",
|
|
},
|
|
{
|
|
name: "in memory correct save",
|
|
backend: BackendMemory,
|
|
uid: "memorySave",
|
|
pubKey: "cfd96f5e00069b64ddb8bfa433941400ab674db42436ae08bc9c74f3b5ade896",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kr, err := New(tt.name, tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
priv := ed25519.GenPrivKey()
|
|
pub := priv.PubKey()
|
|
pub.Bytes()
|
|
k, err := kr.SaveOfflineKey(tt.uid, pub)
|
|
require.NoError(t, err)
|
|
pubKey, err := k.GetPubKey()
|
|
require.NoError(t, err)
|
|
require.Equal(t, pub, pubKey)
|
|
require.Equal(t, tt.uid, k.Name)
|
|
|
|
list, err := kr.List()
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 1)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNonConsistentKeyring_SavePubKey(t *testing.T) {
|
|
cdc := getCodec()
|
|
kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
|
|
list, err := kr.List()
|
|
require.NoError(t, err)
|
|
require.Empty(t, list)
|
|
|
|
key := someKey
|
|
priv := ed25519.GenPrivKey()
|
|
pub := priv.PubKey()
|
|
|
|
_, err = kr.SaveOfflineKey(key, pub)
|
|
require.NoError(t, err)
|
|
|
|
// broken keyring state test
|
|
unsafeKr, ok := kr.(keystore)
|
|
require.True(t, ok)
|
|
// we lost public key for some reason, but still have an address record
|
|
require.NoError(t, unsafeKr.db.Remove(infoKey(key)))
|
|
list, err = kr.List()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0, len(list))
|
|
|
|
k, err := kr.SaveOfflineKey(key, pub)
|
|
require.Nil(t, err)
|
|
pubKey, err := k.GetPubKey()
|
|
require.NoError(t, err)
|
|
require.Equal(t, pub, pubKey)
|
|
require.Equal(t, key, k.Name)
|
|
|
|
list, err = kr.List()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(list))
|
|
}
|
|
|
|
func TestAltKeyring_SaveMultisig(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
uid string
|
|
backend string
|
|
mnemonics []string
|
|
}{
|
|
{
|
|
name: "correct multisig",
|
|
uid: "multi",
|
|
backend: BackendTest,
|
|
mnemonics: []string{
|
|
"faint misery damage shoot wedding chat dress joy page stand gun business dance amount amused pond smart rate inner ill loud agree two evil",
|
|
"window surprise chief blame huge umbrella pool home draw staff water brief modify depth whisper hawk floor come fury property pond cluster ethics super",
|
|
},
|
|
},
|
|
{
|
|
name: "correct in memory multisig",
|
|
uid: "multiInMemory",
|
|
backend: BackendMemory,
|
|
mnemonics: []string{
|
|
"faint misery damage shoot wedding chat dress joy page stand gun business dance amount amused pond smart rate inner ill loud agree two evil",
|
|
"window surprise chief blame huge umbrella pool home draw staff water brief modify depth whisper hawk floor come fury property pond cluster ethics super",
|
|
},
|
|
},
|
|
{
|
|
name: "one key multisig",
|
|
uid: "multi",
|
|
backend: BackendTest,
|
|
mnemonics: []string{"faint misery damage shoot wedding chat dress joy page stand gun business dance amount amused pond smart rate inner ill loud agree two evil"},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kr, err := New(t.Name(), tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
pubKeys := make([]types.PubKey, len(tt.mnemonics))
|
|
for i, mnemonic := range tt.mnemonics {
|
|
r, err := kr.NewAccount(strconv.FormatInt(int64(i), 10), mnemonic, DefaultBIP39Passphrase, sdk.FullFundraiserPath, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
key, err := r.GetPubKey()
|
|
require.NoError(t, err)
|
|
pubKeys[i] = key
|
|
}
|
|
pub := multisig.NewLegacyAminoPubKey(len(tt.mnemonics), pubKeys)
|
|
k, err := kr.SaveMultisig(tt.uid, pub)
|
|
require.Nil(t, err)
|
|
infoKey, err := k.GetPubKey()
|
|
require.NoError(t, err)
|
|
require.Equal(t, pub, infoKey)
|
|
require.Equal(t, tt.uid, k.Name)
|
|
|
|
list, err := kr.List()
|
|
require.NoError(t, err)
|
|
require.Len(t, list, len(tt.mnemonics)+1)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TODO: add more tests
|
|
func TestAltKeyring_Sign(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
backend string
|
|
uid string
|
|
msg []byte
|
|
mode signing.SignMode
|
|
}{
|
|
{
|
|
name: "correct sign",
|
|
backend: BackendTest,
|
|
uid: "signKey",
|
|
msg: []byte("some message"),
|
|
mode: signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kr, err := New(t.Name(), tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
|
|
_, _, err = kr.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
|
|
sign, key, err := kr.Sign(tt.uid, tt.msg, tt.mode)
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, key.VerifySignature(tt.msg, sign))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAltKeyring_SignByAddress(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
backend string
|
|
uid string
|
|
msg []byte
|
|
mode signing.SignMode
|
|
}{
|
|
{
|
|
name: "correct sign by address",
|
|
backend: BackendTest,
|
|
uid: "signKey",
|
|
msg: []byte("some message"),
|
|
mode: signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kr, err := New(t.Name(), tt.backend, t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
|
|
mnemonic, _, err := kr.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
|
|
addr, err := mnemonic.GetAddress()
|
|
require.NoError(t, err)
|
|
sign, key, err := kr.SignByAddress(addr, tt.msg, tt.mode)
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, key.VerifySignature(tt.msg, sign))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAltKeyring_ConstructorSupportedAlgos(t *testing.T) {
|
|
cdc := getCodec()
|
|
tests := []struct {
|
|
name string
|
|
algoOptions func(options *Options)
|
|
expectedErr error
|
|
}{
|
|
{
|
|
name: "add new algo",
|
|
algoOptions: func(options *Options) {
|
|
options.SupportedAlgos = SigningAlgoList{
|
|
notSupportedAlgo{},
|
|
}
|
|
},
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "not supported algo",
|
|
algoOptions: func(options *Options) {},
|
|
expectedErr: ErrUnsupportedSigningAlgo,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc, tt.algoOptions)
|
|
require.NoError(t, err)
|
|
_, _, err = kr.NewMnemonic("test", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{})
|
|
if tt.expectedErr == nil {
|
|
require.NoError(t, err)
|
|
} else {
|
|
require.Error(t, err)
|
|
require.True(t, errors.Is(err, tt.expectedErr))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TODO: review it
|
|
func TestBackendConfigConstructors(t *testing.T) {
|
|
backend := newKWalletBackendKeyringConfig("test", "", nil)
|
|
require.Equal(t, []keyring.BackendType{keyring.KWalletBackend}, backend.AllowedBackends)
|
|
require.Equal(t, "kdewallet", backend.ServiceName)
|
|
require.Equal(t, "test", backend.KWalletAppID)
|
|
|
|
backend = newPassBackendKeyringConfig("test", "directory", nil)
|
|
require.Equal(t, []keyring.BackendType{keyring.PassBackend}, backend.AllowedBackends)
|
|
require.Equal(t, "test", backend.ServiceName)
|
|
require.Equal(t, "keyring-test", backend.PassPrefix)
|
|
}
|
|
|
|
func TestRenameKey(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
run func(Keyring)
|
|
}{
|
|
{
|
|
name: "rename a key",
|
|
run: func(kr Keyring) {
|
|
oldKeyUID, newKeyUID := "old", "new"
|
|
oldKeyRecord := newKeyRecord(t, kr, oldKeyUID)
|
|
err := kr.Rename(oldKeyUID, newKeyUID) // rename from "old" to "new"
|
|
require.NoError(t, err)
|
|
newRecord, err := kr.Key(newKeyUID) // new key should be in keyring
|
|
require.NoError(t, err)
|
|
requireEqualRenamedKey(t, newRecord, oldKeyRecord, false) // oldKeyRecord and newRecord should be the same except name
|
|
_, err = kr.Key(oldKeyUID) // old key should be gone from keyring
|
|
require.Error(t, err)
|
|
},
|
|
},
|
|
{
|
|
name: "can't rename a key that doesn't exist",
|
|
run: func(kr Keyring) {
|
|
err := kr.Rename("bogus", "bogus2")
|
|
require.Error(t, err)
|
|
},
|
|
},
|
|
{
|
|
name: "can't rename a key to an already existing key name",
|
|
run: func(kr Keyring) {
|
|
key1, key2 := "existingKey", "existingKey2" // create 2 keys
|
|
newKeyRecord(t, kr, key1)
|
|
newKeyRecord(t, kr, key2)
|
|
err := kr.Rename(key2, key1)
|
|
require.True(t, errors.Is(err, ErrKeyAlreadyExists))
|
|
assertKeysExist(t, kr, key1, key2) // keys should still exist after failed rename
|
|
},
|
|
},
|
|
{
|
|
name: "can't rename key to itself",
|
|
run: func(kr Keyring) {
|
|
keyName := "keyName"
|
|
newKeyRecord(t, kr, keyName)
|
|
err := kr.Rename(keyName, keyName)
|
|
require.True(t, errors.Is(err, ErrKeyAlreadyExists))
|
|
assertKeysExist(t, kr, keyName)
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
tc := tc
|
|
kr := newKeyring(t, "testKeyring")
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
tc.run(kr)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestChangeBcrypt tests the compatibility from upstream Bcrypt and our own
|
|
func TestChangeBcrypt(t *testing.T) {
|
|
pw := []byte("somepasswword!")
|
|
|
|
saltBytes := cmtcrypto.CRandBytes(16)
|
|
cosmosHash, err := cosmosbcrypt.GenerateFromPassword(saltBytes, pw, 2)
|
|
require.NoError(t, err)
|
|
|
|
bcryptHash, err := bcrypt.GenerateFromPassword(pw, 2)
|
|
require.NoError(t, err)
|
|
|
|
// Check the new hash with the old bcrypt, vice-versa and with the same
|
|
// bcrypt version just because.
|
|
err = cosmosbcrypt.CompareHashAndPassword(bcryptHash, pw)
|
|
require.NoError(t, err)
|
|
|
|
err = cosmosbcrypt.CompareHashAndPassword(cosmosHash, pw)
|
|
require.NoError(t, err)
|
|
|
|
err = bcrypt.CompareHashAndPassword(cosmosHash, pw)
|
|
require.NoError(t, err)
|
|
|
|
err = bcrypt.CompareHashAndPassword(bcryptHash, pw)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func requireEqualRenamedKey(t *testing.T, key, mnemonic *Record, nameMatch bool) {
|
|
t.Helper()
|
|
if nameMatch {
|
|
require.Equal(t, key.Name, mnemonic.Name)
|
|
}
|
|
keyAddr, err := key.GetAddress()
|
|
require.NoError(t, err)
|
|
mnemonicAddr, err := mnemonic.GetAddress()
|
|
require.NoError(t, err)
|
|
require.Equal(t, keyAddr, mnemonicAddr)
|
|
|
|
key1, err := key.GetPubKey()
|
|
require.NoError(t, err)
|
|
key2, err := mnemonic.GetPubKey()
|
|
require.NoError(t, err)
|
|
require.Equal(t, key1, key2)
|
|
require.Equal(t, key.GetType(), mnemonic.GetType())
|
|
}
|
|
|
|
func newKeyring(t *testing.T, name string) Keyring {
|
|
t.Helper()
|
|
cdc := getCodec()
|
|
kr, err := New(name, "test", t.TempDir(), nil, cdc)
|
|
require.NoError(t, err)
|
|
return kr
|
|
}
|
|
|
|
func newKeyRecord(t *testing.T, kr Keyring, name string) *Record {
|
|
t.Helper()
|
|
k, _, err := kr.NewMnemonic(name, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
|
require.NoError(t, err)
|
|
return k
|
|
}
|
|
|
|
func assertKeysExist(t *testing.T, kr Keyring, names ...string) {
|
|
t.Helper()
|
|
for _, n := range names {
|
|
_, err := kr.Key(n)
|
|
require.NoError(t, err)
|
|
}
|
|
}
|
|
|
|
func accAddr(k *Record) (sdk.AccAddress, error) { return k.GetAddress() }
|