wallet: Make encryption derivation clock mockable
What changed, and why it matters
This is a small Bitcoin Core wallet change that makes the encryption key-stretching benchmark use a mockable clock during testing. If the measured time is zero (likely because a test fakes the clock), it falls back to a fixed default number of iterations instead of trying to divide by zero or produce unstable results. It is a test-stability improvement, not a fix for an active security vulnerability.
No urgent action. Treat as normal code-quality/testability patch. Review that DEFAULT_DERIVE_ITERATIONS remains strong enough for production use and that the mockable clock cannot be accidentally enabled in production builds.
Security signals we found
Division-by-zero guard added in key-derivation iteration calibration
Clock source changed from SteadyClock to mockable NodeClock
Behavior explicitly scoped to test/benchmark environment via comment
Evidence from the diff
The commit replaces SteadyClock with NodeClock in the wallet encryption derivation benchmark loop and adds a special case: if elapsed_time <= 0s, it sets master_key.nDeriveIterations to CMasterKey::DEFAULT_DERIVE_ITERATIONS and breaks. NodeClock is mockable in tests, so a mocked clock can return identical start/end times, yielding zero elapsed time. Without this guard, the subsequent division target_iterations = nDeriveIterations * target_time / elapsed_time would divide by zero. The change prevents undefined behavior / floating/integer division issues under mocked time and makes benchmarks deterministic.
Changed components
src/wallet/wallet.cppCMasterKey encryption derivation benchmarkNodeClock / SteadyClock time measurementInspect captured patch +8 / −2
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 782667cc..dae37e05 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -584,9 +584,15 @@ static bool EncryptMasterKey(const SecureString& wallet_passphrase, const CKeyin
// 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()};
+ auto start_time{NodeClock::now()};
crypter.SetKeyFromPassphrase(wallet_passphrase, master_key.vchSalt, master_key.nDeriveIterations, master_key.nDerivationMethod);
- auto elapsed_time{SteadyClock::now() - start_time};
+ auto elapsed_time{NodeClock::now() - start_time};
+
+ if (elapsed_time <= 0s) {
+ // We are probably in a test with a mocked clock.
+ master_key.nDeriveIterations = CMasterKey::DEFAULT_DERIVE_ITERATIONS;
+ break;
+ }
// target_iterations : elapsed_iterations :: target_time : elapsed_time
unsigned int target_iterations = master_key.nDeriveIterations * target_time / elapsed_time;
Why this scored 18/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.