github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/crypto/keys/lazy_keybase_test.go (about) 1 package keys 2 3 import ( 4 "testing" 5 6 "github.com/fibonacci-chain/fbc/libs/tendermint/crypto" 7 "github.com/fibonacci-chain/fbc/libs/tendermint/crypto/ed25519" 8 tmamino "github.com/fibonacci-chain/fbc/libs/tendermint/crypto/encoding/amino" 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 amino "github.com/tendermint/go-amino" 12 13 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec" 14 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/crypto/keys/hd" 15 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/tests" 16 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 17 ) 18 19 func TestNew(t *testing.T) { 20 dir, cleanup := tests.NewTestCaseDir(t) 21 defer cleanup() 22 kb := New("keybasename", dir) 23 lazykb, ok := kb.(lazyKeybase) 24 require.True(t, ok) 25 require.Equal(t, lazykb.name, "keybasename") 26 require.Equal(t, lazykb.dir, dir) 27 } 28 29 func TestLazyKeyManagement(t *testing.T) { 30 dir, cleanup := tests.NewTestCaseDir(t) 31 defer cleanup() 32 kb := New("keybasename", dir) 33 34 algo := Secp256k1 35 n1, n2, n3 := "personal", "business", "other" 36 p1, p2 := nums, "really-secure!@#$" 37 38 // Check empty state 39 l, err := kb.List() 40 require.Nil(t, err) 41 assert.Empty(t, l) 42 43 _, _, err = kb.CreateMnemonic(n1, English, p1, Ed25519, "") 44 require.Error(t, err, "ed25519 keys are currently not supported by keybase") 45 46 // create some keys 47 _, err = kb.Get(n1) 48 require.Error(t, err) 49 i, _, err := kb.CreateMnemonic(n1, English, p1, algo, "") 50 51 require.NoError(t, err) 52 require.Equal(t, n1, i.GetName()) 53 _, _, err = kb.CreateMnemonic(n2, English, p2, algo, "") 54 require.NoError(t, err) 55 56 // we can get these keys 57 i2, err := kb.Get(n2) 58 require.NoError(t, err) 59 _, err = kb.Get(n3) 60 require.NotNil(t, err) 61 _, err = kb.GetByAddress(accAddr(i2)) 62 require.NoError(t, err) 63 addr, err := sdk.AccAddressFromBech32("cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t") 64 require.NoError(t, err) 65 _, err = kb.GetByAddress(addr) 66 require.NotNil(t, err) 67 68 // list shows them in order 69 keyS, err := kb.List() 70 require.NoError(t, err) 71 require.Equal(t, 2, len(keyS)) 72 // note these are in alphabetical order 73 require.Equal(t, n2, keyS[0].GetName()) 74 require.Equal(t, n1, keyS[1].GetName()) 75 require.Equal(t, i2.GetPubKey(), keyS[0].GetPubKey()) 76 77 // deleting a key removes it 78 err = kb.Delete("bad name", "foo", false) 79 require.NotNil(t, err) 80 err = kb.Delete(n1, p1, false) 81 require.NoError(t, err) 82 keyS, err = kb.List() 83 require.NoError(t, err) 84 require.Equal(t, 1, len(keyS)) 85 _, err = kb.Get(n1) 86 require.Error(t, err) 87 88 // create an offline key 89 o1 := "offline" 90 priv1 := ed25519.GenPrivKey() 91 pub1 := priv1.PubKey() 92 i, err = kb.CreateOffline(o1, pub1, algo) 93 require.Nil(t, err) 94 require.Equal(t, pub1, i.GetPubKey()) 95 require.Equal(t, o1, i.GetName()) 96 keyS, err = kb.List() 97 require.NoError(t, err) 98 require.Equal(t, 2, len(keyS)) 99 100 // delete the offline key 101 err = kb.Delete(o1, "", false) 102 require.NoError(t, err) 103 keyS, err = kb.List() 104 require.NoError(t, err) 105 require.Equal(t, 1, len(keyS)) 106 107 // addr cache gets nuked - and test skip flag 108 err = kb.Delete(n2, "", true) 109 require.NoError(t, err) 110 } 111 112 func TestLazySignVerify(t *testing.T) { 113 dir, cleanup := tests.NewTestCaseDir(t) 114 defer cleanup() 115 kb := New("keybasename", dir) 116 algo := Secp256k1 117 118 n1, n2, n3 := "some dude", "a dudette", "dude-ish" 119 p1, p2, p3 := nums, foobar, foobar 120 121 // create two users and get their info 122 i1, _, err := kb.CreateMnemonic(n1, English, p1, algo, "") 123 require.Nil(t, err) 124 125 i2, _, err := kb.CreateMnemonic(n2, English, p2, algo, "") 126 require.Nil(t, err) 127 128 // Import a public key 129 armor, err := kb.ExportPubKey(n2) 130 require.Nil(t, err) 131 kb.ImportPubKey(n3, armor) 132 i3, err := kb.Get(n3) 133 require.NoError(t, err) 134 require.Equal(t, i3.GetName(), n3) 135 136 // let's try to sign some messages 137 d1 := []byte("my first message") 138 d2 := []byte("some other important info!") 139 d3 := []byte("feels like I forgot something...") 140 141 // try signing both data with both .. 142 s11, pub1, err := kb.Sign(n1, p1, d1) 143 require.Nil(t, err) 144 require.Equal(t, i1.GetPubKey(), pub1) 145 146 s12, pub1, err := kb.Sign(n1, p1, d2) 147 require.Nil(t, err) 148 require.Equal(t, i1.GetPubKey(), pub1) 149 150 s21, pub2, err := kb.Sign(n2, p2, d1) 151 require.Nil(t, err) 152 require.Equal(t, i2.GetPubKey(), pub2) 153 154 s22, pub2, err := kb.Sign(n2, p2, d2) 155 require.Nil(t, err) 156 require.Equal(t, i2.GetPubKey(), pub2) 157 158 // let's try to validate and make sure it only works when everything is proper 159 cases := []struct { 160 key crypto.PubKey 161 data []byte 162 sig []byte 163 valid bool 164 }{ 165 // proper matches 166 {i1.GetPubKey(), d1, s11, true}, 167 // change data, pubkey, or signature leads to fail 168 {i1.GetPubKey(), d2, s11, false}, 169 {i2.GetPubKey(), d1, s11, false}, 170 {i1.GetPubKey(), d1, s21, false}, 171 // make sure other successes 172 {i1.GetPubKey(), d2, s12, true}, 173 {i2.GetPubKey(), d1, s21, true}, 174 {i2.GetPubKey(), d2, s22, true}, 175 } 176 177 for i, tc := range cases { 178 valid := tc.key.VerifyBytes(tc.data, tc.sig) 179 require.Equal(t, tc.valid, valid, "%d", i) 180 } 181 182 // Now try to sign data with a secret-less key 183 _, _, err = kb.Sign(n3, p3, d3) 184 require.NotNil(t, err) 185 } 186 187 func TestLazyExportImport(t *testing.T) { 188 dir, cleanup := tests.NewTestCaseDir(t) 189 defer cleanup() 190 kb := New("keybasename", dir) 191 192 info, _, err := kb.CreateMnemonic("john", English, "secretcpw", Secp256k1, "") 193 require.NoError(t, err) 194 require.Equal(t, info.GetName(), "john") 195 196 john, err := kb.Get("john") 197 require.NoError(t, err) 198 require.Equal(t, info.GetName(), "john") 199 johnAddr := info.GetPubKey().Address() 200 201 armor, err := kb.Export("john") 202 require.NoError(t, err) 203 204 err = kb.Import("john2", armor) 205 require.NoError(t, err) 206 207 john2, err := kb.Get("john2") 208 require.NoError(t, err) 209 210 require.Equal(t, john.GetPubKey().Address(), johnAddr) 211 require.Equal(t, john.GetName(), "john") 212 require.Equal(t, john, john2) 213 } 214 215 func TestLazyExportImportPrivKey(t *testing.T) { 216 dir, cleanup := tests.NewTestCaseDir(t) 217 defer cleanup() 218 kb := New("keybasename", dir) 219 220 info, _, err := kb.CreateMnemonic("john", English, "secretcpw", Secp256k1, "") 221 require.NoError(t, err) 222 require.Equal(t, info.GetName(), "john") 223 priv1, err := kb.Get("john") 224 require.NoError(t, err) 225 226 // decrypt local private key, and produce encrypted ASCII armored output 227 armored, err := kb.ExportPrivKey("john", "secretcpw", "new_secretcpw") 228 require.NoError(t, err) 229 230 // delete exported key 231 require.NoError(t, kb.Delete("john", "", true)) 232 _, err = kb.Get("john") 233 require.Error(t, err) 234 235 // import armored key 236 require.NoError(t, kb.ImportPrivKey("john", armored, "new_secretcpw")) 237 238 // ensure old and new keys match 239 priv2, err := kb.Get("john") 240 require.NoError(t, err) 241 require.True(t, priv1.GetPubKey().Equals(priv2.GetPubKey())) 242 } 243 244 func TestLazyExportImportPubKey(t *testing.T) { 245 dir, cleanup := tests.NewTestCaseDir(t) 246 defer cleanup() 247 kb := New("keybasename", dir) 248 algo := Secp256k1 249 250 // CreateMnemonic a private-public key pair and ensure consistency 251 notPasswd := "n9y25ah7" 252 info, _, err := kb.CreateMnemonic("john", English, notPasswd, algo, "") 253 require.Nil(t, err) 254 require.NotEqual(t, info, "") 255 require.Equal(t, info.GetName(), "john") 256 addr := info.GetPubKey().Address() 257 john, err := kb.Get("john") 258 require.NoError(t, err) 259 require.Equal(t, john.GetName(), "john") 260 require.Equal(t, john.GetPubKey().Address(), addr) 261 262 // Export the public key only 263 armor, err := kb.ExportPubKey("john") 264 require.NoError(t, err) 265 // Import it under a different name 266 err = kb.ImportPubKey("john-pubkey-only", armor) 267 require.NoError(t, err) 268 // Ensure consistency 269 john2, err := kb.Get("john-pubkey-only") 270 require.NoError(t, err) 271 // Compare the public keys 272 require.True(t, john.GetPubKey().Equals(john2.GetPubKey())) 273 // Ensure the original key hasn't changed 274 john, err = kb.Get("john") 275 require.NoError(t, err) 276 require.Equal(t, john.GetPubKey().Address(), addr) 277 require.Equal(t, john.GetName(), "john") 278 279 // Ensure keys cannot be overwritten 280 err = kb.ImportPubKey("john-pubkey-only", armor) 281 require.NotNil(t, err) 282 } 283 284 func TestLazyExportPrivateKeyObject(t *testing.T) { 285 dir, cleanup := tests.NewTestCaseDir(t) 286 defer cleanup() 287 kb := New("keybasename", dir) 288 289 info, _, err := kb.CreateMnemonic("john", English, "secretcpw", Secp256k1, "") 290 require.NoError(t, err) 291 require.Equal(t, info.GetName(), "john") 292 293 // export private key object 294 _, err = kb.ExportPrivateKeyObject("john", "invalid") 295 require.NotNil(t, err, "%+v", err) 296 exported, err := kb.ExportPrivateKeyObject("john", "secretcpw") 297 require.Nil(t, err, "%+v", err) 298 require.True(t, exported.PubKey().Equals(info.GetPubKey())) 299 } 300 301 func TestLazyAdvancedKeyManagement(t *testing.T) { 302 dir, cleanup := tests.NewTestCaseDir(t) 303 defer cleanup() 304 kb := New("keybasename", dir) 305 306 algo := Secp256k1 307 n1, n2 := "old-name", "new name" 308 p1, p2 := nums, foobar 309 310 // make sure key works with initial password 311 _, _, err := kb.CreateMnemonic(n1, English, p1, algo, "") 312 require.Nil(t, err, "%+v", err) 313 assertPassword(t, kb, n1, p1, p2) 314 315 // update password requires the existing password 316 getNewpass := func() (string, error) { return p2, nil } 317 err = kb.Update(n1, "jkkgkg", getNewpass) 318 require.NotNil(t, err) 319 assertPassword(t, kb, n1, p1, p2) 320 321 // then it changes the password when correct 322 err = kb.Update(n1, p1, getNewpass) 323 require.NoError(t, err) 324 // p2 is now the proper one! 325 assertPassword(t, kb, n1, p2, p1) 326 327 // exporting requires the proper name and passphrase 328 _, err = kb.Export(n1 + ".notreal") 329 require.NotNil(t, err) 330 _, err = kb.Export(" " + n1) 331 require.NotNil(t, err) 332 _, err = kb.Export(n1 + " ") 333 require.NotNil(t, err) 334 _, err = kb.Export("") 335 require.NotNil(t, err) 336 exported, err := kb.Export(n1) 337 require.Nil(t, err, "%+v", err) 338 339 // import succeeds 340 err = kb.Import(n2, exported) 341 require.NoError(t, err) 342 343 // second import fails 344 err = kb.Import(n2, exported) 345 require.NotNil(t, err) 346 } 347 348 // TestSeedPhrase verifies restoring from a seed phrase 349 func TestLazySeedPhrase(t *testing.T) { 350 dir, cleanup := tests.NewTestCaseDir(t) 351 defer cleanup() 352 kb := New("keybasename", dir) 353 354 algo := Secp256k1 355 n1, n2 := "lost-key", "found-again" 356 p1, p2 := nums, foobar 357 358 // make sure key works with initial password 359 info, mnemonic, err := kb.CreateMnemonic(n1, English, p1, algo, "") 360 require.Nil(t, err, "%+v", err) 361 require.Equal(t, n1, info.GetName()) 362 assert.NotEmpty(t, mnemonic) 363 364 // now, let us delete this key 365 err = kb.Delete(n1, p1, false) 366 require.Nil(t, err, "%+v", err) 367 _, err = kb.Get(n1) 368 require.NotNil(t, err) 369 370 // let us re-create it from the mnemonic-phrase 371 params := *hd.NewFundraiserParams(0, sdk.CoinType, 0) 372 hdPath := params.String() 373 newInfo, err := kb.CreateAccount(n2, mnemonic, DefaultBIP39Passphrase, p2, hdPath, algo) 374 require.NoError(t, err) 375 require.Equal(t, n2, newInfo.GetName()) 376 require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address()) 377 require.Equal(t, info.GetPubKey(), newInfo.GetPubKey()) 378 } 379 380 var _ crypto.PrivKey = testPriv{} 381 var _ crypto.PubKey = testPub{} 382 var testCdc *amino.Codec 383 384 type testPriv []byte 385 386 func (privkey testPriv) PubKey() crypto.PubKey { return testPub{} } 387 func (privkey testPriv) Bytes() []byte { 388 return testCdc.MustMarshalBinaryBare(privkey) 389 } 390 func (privkey testPriv) Sign(msg []byte) ([]byte, error) { return []byte{}, nil } 391 func (privkey testPriv) Equals(other crypto.PrivKey) bool { return true } 392 393 type testPub []byte 394 395 func (key testPub) Address() crypto.Address { return crypto.Address{} } 396 func (key testPub) Bytes() []byte { 397 return testCdc.MustMarshalBinaryBare(key) 398 } 399 func (key testPub) VerifyBytes(msg []byte, sig []byte) bool { return true } 400 func (key testPub) Equals(other crypto.PubKey) bool { return true } 401 402 func TestKeygenOverride(t *testing.T) { 403 dir, cleanup := tests.NewTestCaseDir(t) 404 defer cleanup() 405 406 // Save existing codec and reset after test 407 cryptoCdc := CryptoCdc 408 defer func() { 409 CryptoCdc = cryptoCdc 410 }() 411 412 // Setup testCdc encoding and decoding new key type 413 testCdc = codec.New() 414 RegisterCodec(testCdc) 415 tmamino.RegisterAmino(testCdc) 416 417 // Set up codecs for using new key types 418 privName, pubName := "test/priv_name", "test/pub_name" 419 tmamino.RegisterKeyType(testPriv{}, privName) 420 tmamino.RegisterKeyType(testPub{}, pubName) 421 testCdc.RegisterConcrete(testPriv{}, privName, nil) 422 testCdc.RegisterConcrete(testPub{}, pubName, nil) 423 CryptoCdc = testCdc 424 425 overrideCalled := false 426 dummyFunc := func(bz []byte, algo SigningAlgo) (crypto.PrivKey, error) { 427 overrideCalled = true 428 return testPriv(bz), nil 429 } 430 431 kb := New("keybasename", dir, WithKeygenFunc(dummyFunc)) 432 433 testName, pw := "name", "testPassword" 434 435 // create new key which will generate with 436 info, _, err := kb.CreateMnemonic(testName, English, pw, Secp256k1, "") 437 require.NoError(t, err) 438 require.Equal(t, info.GetName(), testName) 439 440 // Assert overridden function was called 441 require.True(t, overrideCalled) 442 443 // export private key object 444 exported, err := kb.ExportPrivateKeyObject(testName, pw) 445 require.Nil(t, err, "%+v", err) 446 447 // require that the key type is the new key 448 _, ok := exported.(testPriv) 449 require.True(t, ok) 450 451 require.True(t, exported.PubKey().Equals(info.GetPubKey())) 452 }