bip_hd.py 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. #!/usr/bin/env python3
  2. #
  3. # MMGen Wallet, a terminal-based cryptocurrency wallet
  4. # Copyright (C)2013-2024 The MMGen Project <mmgen@tuta.io>
  5. # Licensed under the GNU General Public License, Version 3:
  6. # https://www.gnu.org/licenses
  7. # Public project repositories:
  8. # https://github.com/mmgen/mmgen-wallet
  9. # https://gitlab.com/mmgen/mmgen-wallet
  10. """
  11. examples/bip_hd.py: Usage examples for the MMGen BIP-32/-44 hierarchical/deterministic library
  12. """
  13. from mmgen.cfg import Config
  14. from mmgen.util import fmt
  15. from mmgen.bip39 import bip39
  16. from mmgen.bip_hd import MasterNode, BipHDNode
  17. cfg = Config()
  18. bip39_mnemonic = 'cat swing flag economy stadium alone churn speed unique patch report train'
  19. seed = bip39().generate_seed(bip39_mnemonic.split())
  20. m = MasterNode(cfg, seed)
  21. # Derive sample path:
  22. # to_chain() derives default chain for coin/addr_type pair:
  23. dfl_pub_chain = m.to_chain(idx=0, coin='ltc', addr_type='bech32')
  24. dfl_chg_chain = m.to_chain(idx=1, coin='ltc', addr_type='bech32')
  25. print('Default path (LTC, bech32):\n')
  26. print(f' public chain xpub:\n {dfl_pub_chain.xpub}\n')
  27. print(f' internal chain xpub:\n {dfl_chg_chain.xpub}\n')
  28. print(f' public chain addr 0:\n {dfl_pub_chain.derive_public(0).address}\n')
  29. print(f' public chain addr 1:\n {dfl_pub_chain.derive_public(1).address}\n')
  30. # Derive sample path using path string:
  31. dfl_pub_chain_from_path = BipHDNode.from_path(
  32. base_cfg = cfg,
  33. seed = seed,
  34. # purpose=84 (bech32 [BIP-84]), coin_type=2 (LTC mainnet [SLIP-44]), account=0, chain=0 (public)
  35. # as per BIP-44, ‘purpose’, ‘coin_type’ and ‘account’ are hardened, while ‘chain’ is not
  36. path_str = "m/84'/2'/0'/0",
  37. coin = 'ltc',
  38. addr_type = 'bech32')
  39. assert dfl_pub_chain_from_path.xpub == dfl_pub_chain.xpub
  40. # Derive sample path step-by-step:
  41. # Configure master node with coin/addr_type pair:
  42. master = m.init_cfg(coin='ltc', addr_type='bech32')
  43. # ‘idx’ and ‘hardened’ args may be omitted at depths where defaults exist:
  44. purpose = master.derive_private() # ‘idx’ is auto-computed from addr_type (BIP-44/49/84)
  45. coin_type = purpose.derive_private() # ‘idx’ is auto-computed from coin/network (SLIP-44)
  46. account = coin_type.derive_private(idx=0)
  47. pub_chain = account.derive_public(idx=0)
  48. assert pub_chain.xpub == dfl_pub_chain.xpub
  49. # Initialize node from xpub:
  50. pub_chain_from_xpub = BipHDNode.from_extended_key(cfg, 'ltc', pub_chain.xpub)
  51. assert pub_chain_from_xpub.xpub == pub_chain.xpub
  52. # To derive arbitrary BIP-32 paths, ignoring BIP-44, specify ‘no_path_checks’
  53. nonstd_path = BipHDNode.from_path(
  54. base_cfg = cfg,
  55. seed = seed,
  56. path_str = "m/111'/222/333/444",
  57. coin = 'eth',
  58. addr_type = 'E',
  59. no_path_checks = True)
  60. print('Non-standard path (ETH):\n')
  61. print(f' xpub:\n {nonstd_path.xpub}\n')
  62. print(f' WIF key:\n {nonstd_path.privkey.wif}\n')
  63. print(f' address:\n {nonstd_path.address}\n')
  64. # Display parsed xpub:
  65. parsed_xpub = nonstd_path.key_extended(public=True)
  66. print('Default path parsed xpub:\n')
  67. print(fmt(str(parsed_xpub), indent=' '))