Skip to content

Remove internal hardened BIP32 derivation via Bitcoin Core HD-key RPCs #6

Description

@BenWestgate

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

  1. Keep only stdlib BIP32 root validation and root xprv/tprv serialization in Python.
  2. Where a private target wallet is already part of the operation, evaluate replacing Python hardened derivation with the Core 31.1 importdescriptorsgethdkeyscreatewalletdescriptor flow, restricted to account 0.
  3. 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.
  4. When the minimum supported Bitcoin Core release includes derivehdkey, use it for explicit hardened paths and consume Core's returned origin + xpub/tpub.
  5. Remove _hardened_child and non-root child-xprv serialization from codex32 once all public descriptor and multisig-account derivation paths use Core.
  6. 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.
  7. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions