Skip to content

Commit

Permalink
fix(crypto/keys): in dbKeybase.writeInfo, if replacing a name entry, …
Browse files Browse the repository at this point in the history
…remove the lookup by the old address (#2685)

This PR fixes the bug demonstrated in
#2684 :
* In `dbKeybase.writeInfo`, add an `error` return and propagate this to
all callers (`writeLocalKey`, etc.) . We need `writeInfo` to do some
database integrity checks, so it needs to be able to return an error.
* Update `dbKeybase.writeInfo` as suggested in
[#2684](#2684) . If an existing name
entry is being replaced with new `Info`, then remove the "lookup by
address" entry for the existing address.
* In `TestKeyManagement`, add a test similar to
[#2684](#2684) , except that after
using `CreateAccount` with the same name, expect `GetByAddress` to fail
for the obsolete address and its (non-existing) public key. (This test
passes.)

<details><summary>Contributors' checklist...</summary>

- [x] Added new tests, or not needed, or not feasible
- [x] Provided an example (e.g. screenshot) to aid review or the PR is
self-explanatory
- [x] Updated the official documentation or not needed
- [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message
was included in the description
- [x] Added references to related issues and PRs
- [x] Provided any useful hints for running manual tests
</details>

Signed-off-by: Jeff Thompson <[email protected]>
  • Loading branch information
jefft0 authored Oct 22, 2024
1 parent 47fb389 commit 4b68712
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 20 deletions.
58 changes: 38 additions & 20 deletions tm2/pkg/crypto/keys/keybase.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,33 +115,32 @@ func (kb dbKeybase) CreateLedger(name string, algo SigningAlgo, hrp string, acco
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
return kb.writeLedgerKey(name, pub, *hdPath)
}

// CreateOffline creates a new reference to an offline keypair. It returns the
// created key info.
func (kb dbKeybase) CreateOffline(name string, pub crypto.PubKey) (Info, error) {
return kb.writeOfflineKey(name, pub), nil
return kb.writeOfflineKey(name, pub)
}

// CreateMulti creates a new reference to a multisig (offline) keypair. It
// returns the created key info.
func (kb dbKeybase) CreateMulti(name string, pub crypto.PubKey) (Info, error) {
return kb.writeMultisigKey(name, pub), nil
return kb.writeMultisigKey(name, pub)
}

func (kb *dbKeybase) persistDerivedKey(seed []byte, passwd, name, fullHdPath string) (info Info, err error) {
func (kb *dbKeybase) persistDerivedKey(seed []byte, passwd, name, fullHdPath string) (Info, error) {
// create master key and derive first key:
masterPriv, ch := hd.ComputeMastersFromSeed(seed)
derivedPriv, err := hd.DerivePrivateKeyForPath(masterPriv, ch, fullHdPath)
if err != nil {
return
return nil, err
}

// use possibly blank password to encrypt the private
// key and store it. User must enforce good passwords.
info = kb.writeLocalKey(name, secp256k1.PrivKeySecp256k1(derivedPriv), passwd)
return
return kb.writeLocalKey(name, secp256k1.PrivKeySecp256k1(derivedPriv), passwd)
}

// List returns the keys from storage in alphabetical order.
Expand Down Expand Up @@ -475,41 +474,60 @@ func (kb dbKeybase) CloseDB() {
kb.db.Close()
}

func (kb dbKeybase) writeLocalKey(name string, priv crypto.PrivKey, passphrase string) Info {
func (kb dbKeybase) writeLocalKey(name string, priv crypto.PrivKey, passphrase string) (Info, error) {
// encrypt private key using passphrase
privArmor := armor.EncryptArmorPrivKey(priv, passphrase)
// make Info
pub := priv.PubKey()
info := newLocalInfo(name, pub, privArmor)
kb.writeInfo(name, info)
return info
if err := kb.writeInfo(name, info); err != nil {
return nil, err
}
return info, nil
}

func (kb dbKeybase) writeLedgerKey(name string, pub crypto.PubKey, path hd.BIP44Params) Info {
func (kb dbKeybase) writeLedgerKey(name string, pub crypto.PubKey, path hd.BIP44Params) (Info, error) {
info := newLedgerInfo(name, pub, path)
kb.writeInfo(name, info)
return info
if err := kb.writeInfo(name, info); err != nil {
return nil, err
}
return info, nil
}

func (kb dbKeybase) writeOfflineKey(name string, pub crypto.PubKey) Info {
func (kb dbKeybase) writeOfflineKey(name string, pub crypto.PubKey) (Info, error) {
info := newOfflineInfo(name, pub)
kb.writeInfo(name, info)
return info
if err := kb.writeInfo(name, info); err != nil {
return nil, err
}
return info, nil
}

func (kb dbKeybase) writeMultisigKey(name string, pub crypto.PubKey) Info {
func (kb dbKeybase) writeMultisigKey(name string, pub crypto.PubKey) (Info, error) {
info := NewMultiInfo(name, pub)
kb.writeInfo(name, info)
return info
if err := kb.writeInfo(name, info); err != nil {
return nil, err
}
return info, nil
}

func (kb dbKeybase) writeInfo(name string, info Info) {
func (kb dbKeybase) writeInfo(name string, info Info) error {
// write the info by key
key := infoKey(name)
oldInfob := kb.db.Get(key)
if len(oldInfob) > 0 {
// Enforce 1-to-1 name to address. Remove the lookup by the old address
oldInfo, err := readInfo(oldInfob)
if err != nil {
return err
}
kb.db.DeleteSync(addrKey(oldInfo.GetAddress()))
}

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)
return nil
}

func addrKey(address crypto.Address) []byte {
Expand Down
13 changes: 13 additions & 0 deletions tm2/pkg/crypto/keys/keybase_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,19 @@ func TestKeyManagement(t *testing.T) {
require.NoError(t, err)
require.Equal(t, 1, len(keyS))

// Lookup by original i2 address
infoByAddress, err := cstore.GetByAddress(i2.GetAddress())
require.NoError(t, err)
// GetByAddress should return Info with the corresponding public key
require.Equal(t, infoByAddress.GetPubKey(), i2.GetPubKey())
// Replace n2 with a new address
mn2New := `fancy assault crane note start invite ladder ordinary gold amateur check cousin text mercy speak chuckle wine raw chief isolate swallow cushion wrist piece`
_, err = cstore.CreateAccount(n2, mn2New, bip39Passphrase, p2, 0, 0)
require.NoError(t, err)
// Check that CreateAccount removes the entry for the original address (public key)
_, err = cstore.GetByAddress(i2.GetAddress())
require.NotNil(t, err)

// addr cache gets nuked - and test skip flag
err = cstore.Delete(n2, "", true)
require.NoError(t, err)
Expand Down

1 comment on commit 4b68712

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'Go Benchmarks'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.20.

Benchmark suite Current: 4b68712 Previous: 1154172 Ratio
BenchmarkBinary/EmptyStruct:encode 489.7 ns/op 96 B/op 2 allocs/op 289.4 ns/op 96 B/op 2 allocs/op 1.69
BenchmarkBinary/EmptyStruct:encode - ns/op 489.7 ns/op 289.4 ns/op 1.69
BenchmarkBinary/EmptyStruct:decode 256.8 ns/op 0 B/op 0 allocs/op 135.5 ns/op 0 B/op 0 allocs/op 1.90
BenchmarkBinary/EmptyStruct:decode - ns/op 256.8 ns/op 135.5 ns/op 1.90
BenchmarkBinary/PrimitivesStruct:encode 5020 ns/op 1724 B/op 60 allocs/op 4154 ns/op 1724 B/op 60 allocs/op 1.21
BenchmarkBinary/PrimitivesStruct:encode - ns/op 5020 ns/op 4154 ns/op 1.21
BenchmarkBinary/ShortArraysStruct:encode 769.3 ns/op 192 B/op 4 allocs/op 613.8 ns/op 192 B/op 4 allocs/op 1.25
BenchmarkBinary/ShortArraysStruct:encode - ns/op 769.3 ns/op 613.8 ns/op 1.25
BenchmarkBinary/ShortArraysStruct:decode 358.6 ns/op 0 B/op 0 allocs/op 217 ns/op 0 B/op 0 allocs/op 1.65
BenchmarkBinary/ShortArraysStruct:decode - ns/op 358.6 ns/op 217 ns/op 1.65
BenchmarkBcryptGenerateFromPassword/benchmark-security-param 63664259 ns/op 5130 B/op 9 allocs/op 31921433 ns/op 5125 B/op 9 allocs/op 1.99
BenchmarkBcryptGenerateFromPassword/benchmark-security-param - ns/op 63664259 ns/op 31921433 ns/op 1.99
BenchmarkBcryptGenerateFromPassword/benchmark-security-param 127280015 ns/op 5139 B/op 9 allocs/op 31921433 ns/op 5125 B/op 9 allocs/op 3.99
BenchmarkBcryptGenerateFromPassword/benchmark-security-param - ns/op 127280015 ns/op 31921433 ns/op 3.99
BenchmarkBcryptGenerateFromPassword/benchmark-security-param 254522411 ns/op 5158 B/op 9 allocs/op 31921433 ns/op 5125 B/op 9 allocs/op 7.97
BenchmarkBcryptGenerateFromPassword/benchmark-security-param - ns/op 254522411 ns/op 31921433 ns/op 7.97
BenchmarkBcryptGenerateFromPassword/benchmark-security-param 508903738 ns/op 5196 B/op 10 allocs/op 31921433 ns/op 5125 B/op 9 allocs/op 15.94
BenchmarkBcryptGenerateFromPassword/benchmark-security-param - ns/op 508903738 ns/op 31921433 ns/op 15.94
BenchmarkBcryptGenerateFromPassword/benchmark-security-param 1017736987 ns/op 5528 B/op 13 allocs/op 31921433 ns/op 5125 B/op 9 allocs/op 31.88
BenchmarkBcryptGenerateFromPassword/benchmark-security-param - ns/op 1017736987 ns/op 31921433 ns/op 31.88
BenchmarkBcryptGenerateFromPassword/benchmark-security-param - allocs/op 13 allocs/op 9 allocs/op 1.44
BenchmarkBcryptGenerateFromPassword/benchmark-security-param 2034850003 ns/op 5528 B/op 13 allocs/op 31921433 ns/op 5125 B/op 9 allocs/op 63.75
BenchmarkBcryptGenerateFromPassword/benchmark-security-param - ns/op 2034850003 ns/op 31921433 ns/op 63.75
BenchmarkBcryptGenerateFromPassword/benchmark-security-param - allocs/op 13 allocs/op 9 allocs/op 1.44
BenchmarkSigning 84353 ns/op 1856 B/op 36 allocs/op 25716 ns/op 64 B/op 1 allocs/op 3.28
BenchmarkSigning - ns/op 84353 ns/op 25716 ns/op 3.28
BenchmarkSigning - B/op 1856 B/op 64 B/op 29
BenchmarkSigning - allocs/op 36 allocs/op 1 allocs/op 36
BenchmarkSigning 83400 ns/op 1856 B/op 36 allocs/op 25716 ns/op 64 B/op 1 allocs/op 3.24
BenchmarkSigning - ns/op 83400 ns/op 25716 ns/op 3.24
BenchmarkSigning - B/op 1856 B/op 64 B/op 29
BenchmarkSigning - allocs/op 36 allocs/op 1 allocs/op 36
BenchmarkVerification 164516 ns/op 864 B/op 19 allocs/op 61409 ns/op 0 B/op 0 allocs/op 2.68
BenchmarkVerification - ns/op 164516 ns/op 61409 ns/op 2.68
BenchmarkVerification - B/op 864 B/op 0 B/op +∞
BenchmarkVerification - allocs/op 19 allocs/op 0 allocs/op +∞
BenchmarkVerification 166316 ns/op 864 B/op 19 allocs/op 61409 ns/op 0 B/op 0 allocs/op 2.71
BenchmarkVerification - ns/op 166316 ns/op 61409 ns/op 2.71
BenchmarkVerification - B/op 864 B/op 0 B/op +∞
BenchmarkVerification - allocs/op 19 allocs/op 0 allocs/op +∞
BenchmarkRandomBytes/random 68.9 ns/op 16 B/op 1 allocs/op 32.64 ns/op 4 B/op 1 allocs/op 2.11
BenchmarkRandomBytes/random - ns/op 68.9 ns/op 32.64 ns/op 2.11
BenchmarkRandomBytes/random - B/op 16 B/op 4 B/op 4
BenchmarkRandomBytes/random 104.9 ns/op 32 B/op 1 allocs/op 32.64 ns/op 4 B/op 1 allocs/op 3.21
BenchmarkRandomBytes/random - ns/op 104.9 ns/op 32.64 ns/op 3.21
BenchmarkRandomBytes/random - B/op 32 B/op 4 B/op 8
BenchmarkRandomBytes/random 267.6 ns/op 112 B/op 1 allocs/op 32.64 ns/op 4 B/op 1 allocs/op 8.20
BenchmarkRandomBytes/random - ns/op 267.6 ns/op 32.64 ns/op 8.20
BenchmarkRandomBytes/random - B/op 112 B/op 4 B/op 28
BenchmarkRandomBytes/random 2313 ns/op 1024 B/op 1 allocs/op 32.64 ns/op 4 B/op 1 allocs/op 70.86
BenchmarkRandomBytes/random - ns/op 2313 ns/op 32.64 ns/op 70.86
BenchmarkRandomBytes/random - B/op 1024 B/op 4 B/op 256
BenchmarkSmall/boltdb-1000-100-16-40/update 1560994 ns/op 46373 B/op 410 allocs/op 957304 ns/op 37614 B/op 371 allocs/op 1.63
BenchmarkSmall/boltdb-1000-100-16-40/update - ns/op 1560994 ns/op 957304 ns/op 1.63
BenchmarkSmall/boltdb-1000-100-16-40/update - B/op 46373 B/op 37614 B/op 1.23
BenchmarkSmall/memdb-1000-100-16-40/block 16019611 ns/op 9229206 B/op 168346 allocs/op 11804415 ns/op 6598770 B/op 117053 allocs/op 1.36
BenchmarkSmall/memdb-1000-100-16-40/block - ns/op 16019611 ns/op 11804415 ns/op 1.36
BenchmarkSmall/memdb-1000-100-16-40/block - B/op 9229206 B/op 6598770 B/op 1.40
BenchmarkSmall/memdb-1000-100-16-40/block - allocs/op 168346 allocs/op 117053 allocs/op 1.44
BenchmarkMedium/boltdb-100000-100-16-40/update 6822644 ns/op 129019 B/op 1005 allocs/op 5451720 ns/op 100993 B/op 855 allocs/op 1.25
BenchmarkMedium/boltdb-100000-100-16-40/update - ns/op 6822644 ns/op 5451720 ns/op 1.25
BenchmarkMedium/boltdb-100000-100-16-40/update - B/op 129019 B/op 100993 B/op 1.28
BenchmarkMedium/memdb-100000-100-16-40/update 1207100 ns/op 375006 B/op 7428 allocs/op 989722 ns/op 265386 B/op 5131 allocs/op 1.22
BenchmarkMedium/memdb-100000-100-16-40/update - ns/op 1207100 ns/op 989722 ns/op 1.22
BenchmarkMedium/memdb-100000-100-16-40/update - B/op 375006 B/op 265386 B/op 1.41
BenchmarkMedium/memdb-100000-100-16-40/update - allocs/op 7428 allocs/op 5131 allocs/op 1.45
BenchmarkLevelDBBatchSizes/goleveldb-100000-400-16-40/update - B/op 48967 B/op 38391 B/op 1.28
BenchmarkLevelDBBatchSizes/goleveldb-100000-400-16-40/update - allocs/op 590 allocs/op 448 allocs/op 1.32
BenchmarkLevelDBBatchSizes/goleveldb-100000-2000-16-40/update - allocs/op 440 allocs/op 343 allocs/op 1.28
BenchmarkLevelDBBatchSizes/goleveldb-100000-2000-16-40/block - B/op 109983514 B/op 79179637 B/op 1.39
BenchmarkLevelDBBatchSizes/goleveldb-100000-2000-16-40/block - allocs/op 1310480 allocs/op 985549 allocs/op 1.33
BenchmarkHash/ripemd160 2839 ns/op 25 B/op 1 allocs/op 701.2 ns/op 25 B/op 1 allocs/op 4.05
BenchmarkHash/ripemd160 - ns/op 2839 ns/op 701.2 ns/op 4.05
BenchmarkHash/sha2-256 521.5 ns/op 33 B/op 1 allocs/op 170.7 ns/op 33 B/op 1 allocs/op 3.06
BenchmarkHash/sha2-256 - ns/op 521.5 ns/op 170.7 ns/op 3.06
BenchmarkHash/sha3-256 1839 ns/op 33 B/op 1 allocs/op 715.1 ns/op 33 B/op 1 allocs/op 2.57
BenchmarkHash/sha3-256 - ns/op 1839 ns/op 715.1 ns/op 2.57
BenchmarkWriteSecretConnection 6597 ns/op 0 B/op 0 allocs/op 4102 ns/op 0 B/op 0 allocs/op 1.61
BenchmarkWriteSecretConnection - ns/op 6597 ns/op 4102 ns/op 1.61
BenchmarkReadSecretConnection 3938 ns/op 0 B/op 0 allocs/op 2353 ns/op 0 B/op 0 allocs/op 1.67
BenchmarkReadSecretConnection - ns/op 3938 ns/op 2353 ns/op 1.67

This comment was automatically generated by workflow using github-action-benchmark.

CC: @ajnavarro @thehowl @zivkovicmilos

Please sign in to comment.