Repository navigation
Conversation
ecdsa
force-pushed
the
new_kdf
branch
3 times, most recently
from
October 16, 2026 08:26
506ef9a to
6e00672
Compare
- With the new KDF, we will need to store pw_key in WalletDB. Better store the password at the same location. - get_unlocked_password does not need to re-check the password. (re-check will get expensive once the KDF is stretched) - Daemon.load_wallet: replace 'force_check_password' with 'unlock' The QML gui is the only caller and it unlocks right after loading.
- 100k iterations of PBKDF2-HMAC512 with a random salt - there is a single salt per wallet file, stored in the db and shared by all the secrets of the wallet, so that the KDF only needs to be run once, however many secrets we touch - while the wallet is unlocked, the derived key is kept next to the password in WalletDB, so that the KDF does not run again Note that there is no security benefit for the moment, as we also need to apply the stronger KDF to the file storage. The only case where this increases security is if the file is NOT encrypted :-)
- if the file is encrypted, we already have the password when the file is opened, so the keystores can move to the latest pw hash version right then, instead of waiting for the next password change - wallets that only encrypt their keystore keep their old pw hash version until the next password change, as we have no password at opening time Note that this update is one-way: once a wallet has been migrated, older versions of Electrum will refuse to open it, and report "Unexpected password hash version: 3".
No change in behaviour, as has_lightning() returns bool(self.lnworker). This prepares for encrypting the lightning secrets (see #4909): lnworker will exist while the wallet is locked, and has_lightning() will keep meaning that the wallet has lightning, whether or not its secrets are loaded.
LNWallet is created from public data only: channels, onchain channel backups, swaps and payments. load_secrets() then derives the keys needed to run lightning (node, payment, backup, funding root and nostr keys), loads the channel keys and the imported channel backups, and registers the hold invoices of swaps. For now, it is called right after creation, so nothing changes. This prepares for encrypting the lightning secrets with the wallet password (see #4909): lnworker will exist while the wallet is locked, and load its secrets once we have the password. - lnwatcher registers its callbacks when it starts, as they may need the secrets. Channels are subscribed to it once the secrets are loaded.
- lightning_xprv, channel_seed, multisig_privkey, imported channel backups, preimages and SwapData privkeys are encrypted with a key derived from the wallet password - That key is kept in memory. The derivation is specific to lightning, so that it cannot decrypt the keystore - they are only encrypted if the keystore is: hw and watching-only wallets keep them in plaintext, even if the file is encrypted - do not propose to disable keystore for wallets that have lightning (this feature is only useful for multisig wallets) Lightning can only run once we have the password. If the wallet is not encrypted, the Qt and text GUIs ask for it at startup if the wallet has lightning. With the daemon, the wallet should be unlocked, because sweeping a force-closed anchor channel needs the password: use 'load_wallet --unlock' (or 'unlock'); load_wallet returns a warning otherwise. Until then, lnworker only gives access to public data: channels, swaps, balances, history, requests and invoices. Its keys, pw_key, the channel keys and the swap secrets raise LightningLocked. has_lightning() still means that the wallet has lightning; is_lightning_loaded() tells whether it can run. Lightning keys are encrypted at the same time as the new KDF migration.
update_password re-encrypts the lightning secrets and replaces lnworker.pw_key, while lnworker may be encrypting or decrypting secrets on another thread. A secret written with the old key after the re-encryption could never be decrypted again. - the re-encryption and the key swap are done under db.lock, and so is every read or write of a lightning secret - add_new_channel re-encrypts the secrets of a new channel when it is stored, as pw_key may have changed while the channel was being opened
ecdsa
marked this pull request as ready for review
October 16, 2026 15:29
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
see #4909.
Note that this is not a DB upgrade (it cannot be, because it requires password).
Also, be careful when visiting this branch: the gui will upgrade your wallet without user confirmation (unlike a DB upgrade)