What changed, and why it matters
This commit fixes how a recovery-plan checksum is calculated in Electrum's timelock recovery plugin. Previously, non-English characters were being converted to ASCII escape sequences before hashing, which could produce a different checksum than expected by the BIP-128 standard. The fix makes hashing consistent with the standard and shortens the displayed checksum to 8 hex characters. Plans that used only ordinary ASCII characters are unaffected.
Treat as a compatibility/standards-compliance fix. Review whether any previously created recovery plans with non-ASCII characters need re-checksumming, and confirm that 8 hex characters provides sufficient collision resistance for the intended threat model. No immediate emergency response is indicated by the diff alone.
Security signals we found
checksum algorithm mismatch with published standard (BIP-128)
non-ASCII data silently hashed differently than users/standard expect
truncated digest reduces checksum collision resistance
no input validation or signature added in patch
Evidence from the diff
The patch changes two lines in electrum/plugins/timelock_recovery/qt.py. It sets json.dumps(…, ensure_ascii=False) so that Unicode characters are serialized as UTF-8 rather than \uXXXX escapes before SHA-256 hashing, matching BIP-128’s reference behavior. It also truncates the resulting hex digest to the first 8 characters. The change is correctness-oriented and narrows the checksum output; it does not add input validation, authentication, or cryptographic binding to the recovery plan.
Changed components
electrum/plugins/timelock_recovery/qt.pyTimelockRecovery plugin checksum generationInspect captured patch +2 / −2
diff --git a/electrum/plugins/timelock_recovery/qt.py b/electrum/plugins/timelock_recovery/qt.py
index faeec3c..7b96a9a 100644
--- a/electrum/plugins/timelock_recovery/qt.py
+++ b/electrum/plugins/timelock_recovery/qt.py
@@ -687,10 +687,10 @@ class Plugin(TimelockRecoveryPlugin):
# object whose fields can be ordered in multiple ways).
return hashlib.sha256(json.dumps(
sorted(json_data.items()),
- skipkeys=False, ensure_ascii=True, check_circular=True,
+ skipkeys=False, ensure_ascii=False, check_circular=True,
allow_nan=True, cls=None, indent=None, separators=(',', ':'),
default=None, sort_keys=False,
- ).encode()).hexdigest()
+ ).encode()).hexdigest()[:8]
def _save_recovery_plan_json(self, context: TimelockRecoveryContext, download_dialog: WindowModalDialog):
try:
Why this scored 33/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.