gabriel / muse public
patch task/derived-key-zeroing #1 / 1
AI Agent gabriel · 162 days ago · Apr 17, 2026 · Diff

security: zero DerivedKey private_bytes and chain_code after use

DerivedKey.private_bytes and chain_code were immutable bytes — raw Ed25519 key material lingered in the Python heap indefinitely after derivation.

Changes: - DerivedKey fields changed from bytes to bytearray (frozen=True removed) - DerivedKey.zero() added: overwrites both fields with null bytes - master_key and child_key wrap HMAC output in bytearray and zero I and data immediately after slicing into the new DerivedKey - derive_path zeroes each intermediate DerivedKey before moving to the next child (parent material no longer needed after child is derived) - generate_hd_keypair calls dk.zero() after Ed25519PrivateKey.from_private_bytes() so the OpenSSL key object holds the material and the Python heap copy is wiped

8 tests in test_derived_key_zeroing.py.

sha256:8c444a31f6273c8b6865481dd8c60519bd67d384b4b0a4a5078c476c69a6d612 sha
+26 ~5 symbols
sha256:aa5c4195c196ba2d460f8de9760cbd5ee0327c9f16ef0ca76a00545ebbc7451a snapshot
+26
symbols added
~5
symbols modified
0
dead code introduced
Semantic Changes 31 symbols
~ tests/test_derived_key_zeroing.py .py 25 symbols added
+ TestDerivedKeyFieldTypes class class TestDerivedKeyFieldTypes L69–82
+ test_I1_private_bytes_is_bytearray method method test_I1_private_bytes_is_bytearray L70–75
+ test_I2_chain_code_is_bytearray method method test_I2_chain_code_is_bytearray L77–82
+ TestDerivedKeyZero class class TestDerivedKeyZero L89–109
+ test_II1_zero_wipes_private_bytes method method test_II1_zero_wipes_private_bytes L90–95
+ test_II2_zero_wipes_chain_code method method test_II2_zero_wipes_chain_code L97–102
+ test_II3_zero_preserves_length method method test_II3_zero_preserves_length L104–109
+ TestDerivedKeyZeroingCorrectness class class TestDerivedKeyZeroingCorrectness L163–174
+ test_IV1_same_seed_same_fingerprint method method test_IV1_same_seed_same_fingerprint L164–174
+ TestGenerateHdKeypairZeroing class class TestGenerateHdKeypairZeroing L116–156
+ test_III1_private_bytes_zeroed_after_keygen method method test_III1_private_bytes_zeroed_after_keygen L117–136
+ test_III2_chain_code_zeroed_after_keygen method method test_III2_chain_code_zeroed_after_keygen L138–156
+ _MNEMONIC variable variable _MNEMONIC L47–50
+ _SEED variable variable _SEED L51–51
+ DerivedKey import import DerivedKey L44–44
+ _hdkeys import import _hdkeys L43–43
+ annotations import import annotations L34–34
+ id_module import import id_module L42–42
+ kp_module import import kp_module L41–41
+ master_key import import master_key L44–44
+ mnemonic_to_seed import import mnemonic_to_seed L45–45
+ patch import import patch L37–37
+ pathlib import import pathlib L36–36
+ pytest import import pytest L39–39
+ isolated function function isolated L55–62
~ muse/core/keypair.py .py 1 symbol modified
~ muse/core/slip010.py .py 1 symbol added, 4 symbols modified
+ zero method method zero L196–199
← Older Oldest on task/derived-key-zeroing
All commits
Newer → Latest on task/derived-key-zeroing

0 comments

No comments yet. Be the first to start the discussion.

To add a comment, use the Muse CLI: muse hub commit comment sha256:8c444a31f6273c8b6865481dd8c60519bd67d384b4b0a4a5078c476c69a6d612 --body "your comment"