Files
dragonx/doc/hd-transparent-keys.md
DanS 4caf2fc68f Add BIP39 seed phrases (SilentDragonXLite-compatible) and HD transparent keys
Derive transparent (t-addr) keys from the HD seed and add BIP39 mnemonic seed
phrases that are byte-for-byte compatible with SilentDragonXLite, so the same
24 words recover the same shielded and transparent addresses in either wallet.

HD transparent keys:
- Derive t-keys from the seed at m/44'/coin'/0'/0/i (were random CKeys).
- CHDChain gains a version-gated transparent counter; existing wallets load
  unchanged. GenerateNewKey routes through DeriveNewChildKey when enabled
  (-hdtransparent, default on).
- Restore from a seed hex via -hdseed with gap-limit pre-derivation; birthday
  pinned to genesis so the rescan is not clipped.

BIP39 seed phrases:
- Wire the vendored trezor BIP39 lib (src/crypto/bip39) into the build, fix its
  BIP39_WORDS guard, and disable the insecure mnemonic cache.
- Match SDXLite exactly: English wordlist, empty passphrase, PBKDF2 64-byte
  seed, coin type 141, ZIP-32 m/32'/141'/i' and BIP44 m/44'/141'/0'/0/i. Store
  the 32-byte entropy and expand to the 64-byte seed on demand.
- Restore via -mnemonic, create via -usemnemonic, reveal via z_exportmnemonic.

Verified by gtests including a known-answer BIP39 seed vector and z/t address
derivation checks (src/gtest/test_hdtransparent.cpp, test_mnemonic_compat.cpp).
Docs in doc/hd-transparent-keys.md and doc/seed-phrase.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 01:57:18 -05:00

3.8 KiB

HD transparent keys

DragonX derives transparent (t-address) keys deterministically from the wallet's HD seed, so they can be recovered from the seed alone — the same way Sapling (shielded) keys already are.

Derivation

Transparent keys are derived over secp256k1 using BIP32/BIP44:

m / 44' / coin_type' / 0' / 0 / i
  • coin_type is Params().BIP44CoinType()141 on mainnet, 1 on test/regtest.
  • Account is fixed at 0' and the chain at 0 (external). The internal/change chain (1) is not used: on this ac_private=1 chain a non-coinbase transparent output is consensus-invalid, so transparent change can never carry value.
  • i is CHDChain.transparentChildCounter, a monotonic index persisted in the wallet so the same addresses regenerate after a seed-only restore.

Each derived key records its hdKeypath and the seed fingerprint (seedFp) in its CKeyMetadata, matching the Sapling scheme.

Why this matters on a private chain

On DragonX (ac_private=1 from genesis) a normal user can never receive to a transparent address — inbound t-payments are rejected by consensus. The only thing that legitimately lands spendable value on a t-address is a mining coinbase (plus notary/burn special cases). There is no "coinbase must be shielded" rule, so mature coinbase is directly spendable.

So HD transparent keys exist to let a miner recover coinbase rewards that were paid to wallet-derived t-addresses, using only the seed.

Enabling / disabling

Controlled by -hdtransparent (default on). When on and the wallet has an HD seed, every newly generated transparent key (receive address, change, coinbase payout drawn from the keypool) is HD-derived.

-hdtransparent=0   # keep the legacy behaviour (random transparent keys)

Backing up and restoring

  • Back up the seed. z_exportwallet <file> writes the 32-byte HD seed as a # HDSeed=<hex> line. Guard this value like a private key.

  • Restore into a fresh/empty wallet by starting the node with:

    -hdseed=<64-hex-character seed>
    -hdtransparentgaplimit=<n>   # HD transparent keys to pre-derive (default 1000)
    

    On restore the node injects the seed, pre-derives n transparent keys with a genesis birthday, and the normal startup rescan finds any coinbase paid to them. Raise -hdtransparentgaplimit if the wallet minted more than n distinct coinbase addresses.

    Warning: passing -hdseed on the command line exposes the seed to your shell history and the process list. Prefer putting it in DRAGONX.conf with tight file permissions, and remove it after the restore completes.

Limitations (read before relying on recovery)

  • Legacy random keys are not recoverable. Any transparent key created before this feature (or with -hdtransparent=0) came from the CSPRNG, not the seed, and the phrase/seed will not regenerate it. Keep wallet.dat / dumpwallet backups for those. A wallet that predates the feature and then enables it becomes a mix of random (old) and HD (new) keys.
  • Gap limit. A rescan only discovers keys already present in the wallet. Restore pre-derives -hdtransparentgaplimit keys; coinbase paid to an index beyond that window is not found until you derive further and rescan again.
  • Scope. Recovers transparent coinbase value only, per the consensus rules above. Shielded funds are recovered separately via the Sapling HD keys.

On-disk compatibility

The transparent counter is stored in CHDChain under a new serialization version (VERSION_HD_TRANSPARENT = 2). Existing v1 wallet.dat records load unchanged (the counter defaults to 0); the record is rewritten as v2 the first time an HD transparent key is derived. Downgrading a v2 wallet to an older binary is not supported.