mmgen-addrgen 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. #!/usr/bin/env python
  2. #
  3. # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
  4. # Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. """
  19. mmgen-addrgen: Generate a list or range of addresses from a mmgen
  20. deterministic wallet.
  21. Call as 'btc-keygen' to allow key generation as well.
  22. """
  23. import sys
  24. import mmgen.config as g
  25. from mmgen.Opts import *
  26. from mmgen.license import *
  27. from mmgen.util import *
  28. from mmgen.addr import *
  29. invoked_as = sys.argv[0].split("-")[-1]
  30. gen_what = "addresses" if invoked_as == "addrgen" else "keys"
  31. if invoked_as == "keygen":
  32. extra_help_data = (
  33. "\n-A, --no-addresses Print only secret keys, no addresses",
  34. "\n-x, --b16 Print secret keys in hexadecimal too",
  35. "\nBy default, both addresses and secret keys are generated."
  36. )
  37. else: extra_help_data = ("","","")
  38. help_data = {
  39. 'prog_name': sys.argv[0].split("/")[-1],
  40. 'desc': """Generate a list or range of {} from a {} wallet,
  41. mnemonic, seed or password""".format(gen_what,g.proj_name),
  42. 'usage':"[opts] [infile] <address list>",
  43. 'options': """
  44. -h, --help Print this help message{}
  45. -d, --outdir d Specify an alternate directory 'd' for output
  46. -e, --echo-passphrase Echo passphrase or mnemonic to screen upon entry
  47. -H, --show-hash-presets Show information on available hash presets
  48. -K, --no-keyconv Use internal libraries for address generation
  49. instead of 'keyconv'
  50. -l, --seed-len N Length of seed. Options: {}
  51. (default: {})
  52. -p, --hash-preset p Use scrypt.hash() parameters from preset 'p'
  53. when hashing password (default: '{}')
  54. -P, --passwd-file f Get passphrase from file 'f'
  55. -q, --quiet Suppress warnings; overwrite files without
  56. prompting
  57. -S, --stdout Print {W} to stdout
  58. -v, --verbose Produce more verbose output{}
  59. -b, --from-brain l,p Generate {W} from a user-created password,
  60. i.e. a "brainwallet", using seed length 'l' and
  61. hash preset 'p' (comma-separated)
  62. -g, --from-incog Generate {W} from an incognito wallet
  63. -X, --from-incog-hex Generate {W} from an incognito hexadecimal wallet
  64. -G, --from-incog-hidden f,o,l Generate {W} from incognito data in file
  65. 'f' at offset 'o', with seed length of 'l'
  66. -m, --from-mnemonic Generate {W} from an electrum-like mnemonic
  67. -s, --from-seed Generate {W} from a seed in .{S} format
  68. Addresses are given in a comma-separated list. Hyphen-separated
  69. ranges are also allowed.{}
  70. If available, the external 'keyconv' program will be used for address
  71. generation.
  72. Data for the --from-<what> options will be taken from <infile> if <infile>
  73. is specified. Otherwise, the user will be prompted to enter the data.
  74. For passphrases all combinations of whitespace are equal, and leading and
  75. trailing space are ignored. This permits reading passphrase data from a
  76. multi-line file with free spacing and indentation. This is particularly
  77. convenient for long brainwallet passphrases, for example.
  78. BRAINWALLET NOTE:
  79. As brainwallets require especially strong hashing to thwart dictionary
  80. attacks, the brainwallet hash preset must be specified by the user, using
  81. the 'p' parameter of the '--from-brain' option
  82. The '--from-brain' option also requires the user to specify a seed length
  83. (the 'l' parameter)
  84. For a brainwallet passphrase to always generate the same keys and
  85. addresses, the same 'l' and 'p' parameters to '--from-brain' must be used
  86. in all future invocations with that passphrase
  87. """.format(
  88. extra_help_data[0],
  89. ", ".join([str(i) for i in g.seed_lens]),
  90. g.seed_len,
  91. g.hash_preset,
  92. extra_help_data[1],
  93. extra_help_data[2],
  94. W=gen_what,
  95. S=g.seed_ext
  96. )
  97. }
  98. short_opts = ["h","A","d:","e",
  99. "H","K","l:","p:",
  100. "P:","q","S","v","x","b:",
  101. "g","X","G:","m","s"]
  102. long_opts = ["help","no_addresses","outdir=","echo_passphrase",
  103. "show_hash_presets","no_keyconv","seed_len=","hash_preset=",
  104. "passwd_file=","quiet","stdout","verbose","b16","from_brain=",
  105. "from_incog","from_incog_hex","from_incog_hidden=",
  106. "from_mnemonic","from_seed"]
  107. if invoked_as == "addrgen":
  108. for i in "A","x": short_opts.remove(i)
  109. for i in "no_addresses","b16": long_opts.remove(i)
  110. opts,cmd_args = process_opts(sys.argv,help_data,"".join(short_opts),long_opts)
  111. if 'show_hash_presets' in opts: show_hash_presets()
  112. if 'verbose' in opts: g.verbose = True
  113. if 'quiet' in opts: g.quiet = True
  114. if 'from_incog_hex' in opts or 'from_incog_hidden' in opts:
  115. opts['from_incog'] = True
  116. opts['gen_what'] = gen_what
  117. check_opts(opts,long_opts)
  118. if g.debug: show_opts_and_cmd_args(opts,cmd_args)
  119. if len(cmd_args) == 1 and (
  120. 'from_mnemonic' in opts
  121. or 'from_brain' in opts
  122. or 'from_seed' in opts
  123. or 'from_incog_hidden' in opts
  124. ):
  125. infile,addr_list_arg = "",cmd_args[0]
  126. elif len(cmd_args) == 2:
  127. infile,addr_list_arg = cmd_args
  128. check_infile(infile)
  129. else: usage(help_data)
  130. addr_list = parse_address_list(addr_list_arg)
  131. if not addr_list: sys.exit(2)
  132. do_license_msg()
  133. # Interact with user:
  134. if invoked_as == "keygen" and not g.quiet:
  135. confirm_or_exit(cmessages['unencrypted_secret_keys'], 'continue')
  136. # Generate data:
  137. if invoked_as == "addrgen":
  138. opts['print_addresses_only'] = True
  139. else:
  140. if not 'no_addresses' in opts: opts['print_secret'] = True
  141. seed = get_seed_retry(infile,opts)
  142. seed_id = make_chksum_8(seed)
  143. addr_data = generate_addrs(seed, addr_list, opts)
  144. addr_data_str = format_addr_data(addr_data, seed_id, opts)
  145. # Output data:
  146. if 'stdout' in opts:
  147. if invoked_as == "keygen" and not g.quiet:
  148. confirm = True
  149. else: confirm = False
  150. write_to_stdout(addr_data_str,"secret keys",confirm)
  151. elif not sys.stdout.isatty():
  152. write_to_stdout(addr_data_str,"secret keys",confirm=False)
  153. else:
  154. write_addr_data_to_file(seed, addr_data_str, addr_list, opts)