Follow-up to #3.
Goal
Remove the temporary Python implementation of hardened BIP32 child derivation from the Bitcoin Core integration. Python should stop at validating/serializing the BIP32 root xprv/tprv; Bitcoin Core should perform hardened derivation and public-key work.
Verified Core 31.1 behavior
Bitcoin Core v31.1.0 has createwalletdescriptor and gethdkeys, but does not expose addhdkey, derivehdkey, or sethdseed RPCs.
A root key can nevertheless be made known to a descriptor wallet by importing one inactive descriptor containing the root xprv/tprv. gethdkeys then returns the corresponding xpub/tpub, and createwalletdescriptor successfully derives the standard account-0 descriptors with origin metadata.
Using the public synthetic BIP93 test seed, this was verified on both networks:
- mainnet:
44h/0h/0h, 49h/0h/0h, 84h/0h/0h, 86h/0h/0h
- regtest:
44h/1h/0h, 49h/1h/0h, 84h/1h/0h, 86h/1h/0h
So createwalletdescriptor works on non-mainnet as well as mainnet. Its fixed account 0h is acceptable for the current codex32 integration.
Remaining problem
createwalletdescriptor is wallet-stateful: the wallet must already know the private HD key, and the RPC adds descriptors to that wallet. That is usable for private-wallet initialization, but it is not a clean stateless replacement for public_descriptors() / watch-only export. Using a scratch wallet would persist secret material and introduces cleanup/lifecycle concerns.
The newer derivehdkey design would be the clean primitive once it exists in a Bitcoin Core release that codex32 supports, because it can return the derived xpub plus key origin without requiring Python to implement hardened child derivation.
Implementation plan
- Keep only stdlib BIP32 root validation and root xprv/tprv serialization in Python.
- Where a private target wallet is already part of the operation, evaluate replacing Python hardened derivation with the Core 31.1
importdescriptors → gethdkeys → createwalletdescriptor flow, restricted to account 0.
- Do not introduce a persistent scratch wallet merely to support watch-only/public export without an explicit security review of secret-on-disk lifecycle and cleanup.
- When the minimum supported Bitcoin Core release includes
derivehdkey, use it for explicit hardened paths and consume Core's returned origin + xpub/tpub.
- Remove
_hardened_child and non-root child-xprv serialization from codex32 once all public descriptor and multisig-account derivation paths use Core.
- Add real-Core integration coverage on mainnet-style and non-mainnet extended-key versions, including BIP44/49/84/86 account-0 origins and BIP48 multisig derivation.
- Keep tests asserting that backup/recovery remains free of third-party/native secp256k1 dependencies.
Acceptance criteria
- Python implements no general or hardened BIP32 child derivation for wallet interoperability.
- Root seed → root xprv/tprv remains stdlib-only.
- Hardened account derivation and public-key conversion occur in Bitcoin Core.
- Mainnet and non-mainnet descriptor origins are verified against real Core.
- No new persistent scratch wallet containing the root secret is introduced without an explicit security decision.
Follow-up to #3.
Goal
Remove the temporary Python implementation of hardened BIP32 child derivation from the Bitcoin Core integration. Python should stop at validating/serializing the BIP32 root xprv/tprv; Bitcoin Core should perform hardened derivation and public-key work.
Verified Core 31.1 behavior
Bitcoin Core v31.1.0 has
createwalletdescriptorandgethdkeys, but does not exposeaddhdkey,derivehdkey, orsethdseedRPCs.A root key can nevertheless be made known to a descriptor wallet by importing one inactive descriptor containing the root xprv/tprv.
gethdkeysthen returns the corresponding xpub/tpub, andcreatewalletdescriptorsuccessfully derives the standard account-0 descriptors with origin metadata.Using the public synthetic BIP93 test seed, this was verified on both networks:
44h/0h/0h,49h/0h/0h,84h/0h/0h,86h/0h/0h44h/1h/0h,49h/1h/0h,84h/1h/0h,86h/1h/0hSo
createwalletdescriptorworks on non-mainnet as well as mainnet. Its fixed account0his acceptable for the current codex32 integration.Remaining problem
createwalletdescriptoris wallet-stateful: the wallet must already know the private HD key, and the RPC adds descriptors to that wallet. That is usable for private-wallet initialization, but it is not a clean stateless replacement forpublic_descriptors()/ watch-only export. Using a scratch wallet would persist secret material and introduces cleanup/lifecycle concerns.The newer
derivehdkeydesign would be the clean primitive once it exists in a Bitcoin Core release that codex32 supports, because it can return the derived xpub plus key origin without requiring Python to implement hardened child derivation.Implementation plan
importdescriptors→gethdkeys→createwalletdescriptorflow, restricted to account 0.derivehdkey, use it for explicit hardened paths and consume Core's returned origin + xpub/tpub._hardened_childand non-root child-xprv serialization from codex32 once all public descriptor and multisig-account derivation paths use Core.Acceptance criteria