mmgen-addrgen 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. #!/usr/bin/env python
  2. #
  3. # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
  4. # Copyright (C) 2013 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 range of addresses from a mmgen deterministic
  20. wallet.
  21. Call as 'btc-keygen' to allow key generation as well.
  22. """
  23. import sys
  24. from mmgen.Opts import *
  25. from mmgen.config import *
  26. from mmgen.license import *
  27. from mmgen.utils 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 range of {} from a {} wallet, mnemonic,
  41. seed or password""".format(gen_what,proj_name),
  42. 'usage':"[opts] [infile] <address range>",
  43. 'options': """
  44. -h, --help Print this help message{}
  45. -d, --outdir d Specify an alternate directory 'd' for output
  46. -e, --echo-passphrase Display passphrase or mnemonic on screen upon entry
  47. -K, --no-keyconv Use internal libraries for address generation
  48. instead of 'keyconv'
  49. -l, --seed-len N Length of seed. Options: {}
  50. (default: {})
  51. -p, --hash-preset p Use scrypt.hash() parameters from preset 'p'
  52. when hashing password (default: '{}')
  53. -P, --show-hash-presets Show information on available hash presets
  54. -q, --quiet Suppress warnings; overwrite files without asking
  55. -S, --stdout Print {W} to stdout
  56. -v, --verbose Produce more verbose output{}
  57. -b, --from-brain l,p Generate {W} from a user-created password,
  58. i.e. a "brainwallet", using seed length 'l' and
  59. hash preset 'p' (comma-separated)
  60. -m, --from-mnemonic Generate {W} from an electrum-like mnemonic
  61. -s, --from-seed Generate {W} from a seed in .{S} format
  62. Address range may be a single number or a range in the form XXX-YYY{}
  63. If available, external 'keyconv' program will be used for address generation
  64. Data for the --from-<what> options will be taken from <infile> if <infile>
  65. is specified. Otherwise, the user will be prompted to enter the data.
  66. For passphrases all combinations of whitespace are equal, and leading and
  67. trailing space are ignored. This permits reading passphrase data from a
  68. multi-line file with free spacing and indentation. This is particularly
  69. convenient for long brainwallet passphrases, for example.
  70. BRAINWALLET NOTE:
  71. As brainwallets require especially strong hashing to thwart dictionary
  72. attacks, the brainwallet hash preset must be specified by the user, using
  73. the 'p' parameter of the '--from-brain' option
  74. The '--from-brain' option also requires the user to specify a seed length
  75. (the 'l' parameter)
  76. For a brainwallet passphrase to always generate the same keys and addresses,
  77. the same 'l' and 'p' parameters to '--from-brain' must be used in all future
  78. invocations with that passphrase
  79. """.format(
  80. extra_help_data[0],
  81. ", ".join([str(i) for i in seed_lens]),
  82. seed_len,
  83. hash_preset,
  84. extra_help_data[1],
  85. extra_help_data[2],
  86. W=gen_what,
  87. S=seed_ext
  88. )
  89. }
  90. so = "h","A","d:","e","K","l:","p:","P","q","S","v","x","b:","m","s"
  91. lo = "help","no_addresses","outdir=","echo_passphrase","no_keyconv",\
  92. "seed_len=","hash_preset=","show_hash_presets","quiet","stdout",\
  93. "verbose","b16","from_brain=","from_mnemonic","from_seed"
  94. if invoked_as == "addrgen":
  95. short_opts = so[0:1] + so[2:10] + so[11:]
  96. long_opts = lo[0:1] + lo[2:10] + lo[11:]
  97. else:
  98. short_opts,long_opts = so,lo
  99. opts,cmd_args = process_opts(sys.argv,help_data,"".join(short_opts),long_opts)
  100. if 'show_hash_presets' in opts: show_hash_presets()
  101. # Sanity checking and processing of command-line arguments:
  102. opts['gen_what'] = gen_what
  103. set_if_unset_and_typeconvert(opts,(
  104. ('hash_preset',hash_preset,'str'),
  105. ('seed_len',seed_len,'int')
  106. ))
  107. # Exits on invalid input
  108. check_opts(opts,('hash_preset','seed_len','outdir','from_brain'))
  109. if debug:
  110. print "Processed options: %s" % repr(opts)
  111. print "Cmd args: %s" % repr(cmd_args)
  112. if len(cmd_args) == 1 and (
  113. 'from_mnemonic' in opts or
  114. 'from_brain' in opts or
  115. 'from_seed' in opts
  116. ): infile,addr_range = "",cmd_args[0]
  117. elif len(cmd_args) == 2:
  118. infile,addr_range = cmd_args
  119. check_infile(infile)
  120. else: usage(help_data)
  121. start,end = parse_address_range(addr_range)
  122. if not 'quiet' in opts: do_license_msg()
  123. # Interact with user:
  124. if invoked_as == "keygen" and not 'quiet' in opts:
  125. confirm_or_exit(cmessages['unencrypted_secret_keys'], 'continue')
  126. # Generate data:
  127. if invoked_as == "addrgen":
  128. opts['print_addresses_only'] = True
  129. else:
  130. if not 'no_addresses' in opts: opts['print_secret'] = True
  131. seed = get_seed(infile,opts)
  132. seed_id = make_chksum_8(seed)
  133. addr_data = generate_addrs(seed, range(start, end+1), opts)
  134. addr_data_str = format_addr_data(addr_data, seed_id, opts)
  135. # Output data:
  136. if 'stdout' in opts:
  137. if invoked_as == "keygen" and not 'quiet' in opts:
  138. confirm = True
  139. else: confirm = False
  140. write_to_stdout(addr_data_str,"secret keys",confirm)
  141. elif not sys.stdout.isatty():
  142. write_to_stdout(addr_data_str,"secret keys",confirm=False)
  143. else:
  144. write_addr_data_to_file(seed, addr_data_str, start, end, opts)