refactor: Generalize derivation target calculation
What changed, and why it matters
This commit is a code cleanup (refactor) that changes how Bitcoin Core calculates how many password-stretching iterations to use when encrypting a wallet. It replaces a two-step manual timing-and-averaging process with a small loop that does the same thing more generally. There is no security bug visible in the change; it is purely a maintainability improvement.
No security action required. Treat as a normal refactor review.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch generalizes the derivation-target calculation in CWallet::EncryptMasterKey. Previously the code ran SetKeyFromPassphrase once to estimate iterations, then ran it again and averaged the result. The new code loops twice, computes target_iterations = nDeriveIterations * target_time / elapsed_time for each run, and updates a weighted average in place. The final minimum-iterations guard (DEFAULT_DERIVE_ITERATIONS) and the 100 ms target remain unchanged. No functional security weakness is introduced.
Changed components
src/wallet/wallet.cppCWallet::EncryptMasterKeyInspect captured patch +11 / −7
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 1e7ad3fc..782667cc 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -579,16 +579,20 @@ void CWallet::UpgradeDescriptorCache()
* derivation parameters (should take at least 100ms) and encrypt the master key. */
static bool EncryptMasterKey(const SecureString& wallet_passphrase, const CKeyingMaterial& plain_master_key, CMasterKey& master_key)
{
- constexpr MillisecondsDouble target{100};
- auto start{SteadyClock::now()};
+ constexpr MillisecondsDouble target_time{100};
CCrypter crypter;
- crypter.SetKeyFromPassphrase(wallet_passphrase, master_key.vchSalt, master_key.nDeriveIterations, master_key.nDerivationMethod);
- master_key.nDeriveIterations = static_cast<unsigned int>(master_key.nDeriveIterations * target / (SteadyClock::now() - start));
+ // Get the weighted average of iterations we can do in 100ms over 2 runs.
+ for (int i = 0; i < 2; i++){
+ auto start_time{SteadyClock::now()};
+ crypter.SetKeyFromPassphrase(wallet_passphrase, master_key.vchSalt, master_key.nDeriveIterations, master_key.nDerivationMethod);
+ auto elapsed_time{SteadyClock::now() - start_time};
- start = SteadyClock::now();
- crypter.SetKeyFromPassphrase(wallet_passphrase, master_key.vchSalt, master_key.nDeriveIterations, master_key.nDerivationMethod);
- master_key.nDeriveIterations = (master_key.nDeriveIterations + static_cast<unsigned int>(master_key.nDeriveIterations * target / (SteadyClock::now() - start))) / 2;
+ // target_iterations : elapsed_iterations :: target_time : elapsed_time
+ unsigned int target_iterations = master_key.nDeriveIterations * target_time / elapsed_time;
+ // Get the weighted average with previous runs.
+ master_key.nDeriveIterations = (i * master_key.nDeriveIterations + target_iterations) / (i + 1);
+ }
if (master_key.nDeriveIterations < CMasterKey::DEFAULT_DERIVE_ITERATIONS) {
master_key.nDeriveIterations = CMasterKey::DEFAULT_DERIVE_ITERATIONS;
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.