mmgen-keygen 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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-keygen: Generate addresses/secret keys from a mmgen deterministic
  20. wallet for a range of addresses.
  21. Call as 'btc-addrgen' for safe, reduced functionality
  22. with no output of secret keys.
  23. """
  24. import sys
  25. from mmgen.Opts import *
  26. from mmgen.config import *
  27. from mmgen.license import *
  28. from mmgen.utils import *
  29. from mmgen.addr import *
  30. invoked_as = sys.argv[0].split("-")[-1]
  31. gen_what = "addresses" if invoked_as == "addrgen" else "keys"
  32. if invoked_as == "keygen":
  33. extra_help_data = (
  34. "\n-A, --no-addresses Print only secret keys, no addresses",
  35. "\n-x, --b16 Print secret keys in hexadecimal too",
  36. ".\nBy default, both addresses and secret keys are generated"
  37. )
  38. else: extra_help_data = ("","","")
  39. help_data = {
  40. 'prog_name': sys.argv[0].split("/")[-1],
  41. 'desc': """Generate a range of {} from a {} wallet, mnemonic,
  42. seed or password""".format(gen_what,proj_name),
  43. 'usage':"[opts] [infile] <address range>",
  44. 'options': """
  45. -h, --help Print this help message{}
  46. -d, --outdir d Specify an alternate directory 'd' for output
  47. -e, --echo-passphrase Display passphrase or mnemonic on screen upon entry
  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, --show-hash-presets Show information on available hash presets
  55. -q, --quiet Suppress warnings; overwrite files without asking
  56. -S, --stdout Print {W} to stdout
  57. -v, --verbose Produce more verbose output{}
  58. -b, --from-brain l,p Generate {W} from a user-created password,
  59. i.e. a "brainwallet", using seed length 'l' and
  60. hash preset 'p' (comma-separated)
  61. -m, --from-mnemonic Generate {W} from an electrum-like mnemonic
  62. -s, --from-seed Generate {W} from a seed in .{S} format
  63. Address range may be a single number or a range in the form XXX-YYY{}
  64. If available, external 'keyconv' program will be used for address generation
  65. Data for the --from-<what> options will be taken from <infile> if <infile>
  66. is specified. Otherwise, the user will be prompted to enter the data. Note
  67. that passphrase data in a file may be arranged in free-form fashion, using
  68. any combination of spaces, tabs or newlines to separate words
  69. BRAINWALLET NOTE:
  70. As brainwallets require especially strong hashing to thwart dictionary
  71. attacks, the brainwallet hash preset must be specified by the user, using
  72. the 'p' parameter of the '--from-brain' option
  73. The '--from-brain' option also requires the user to specify a seed length
  74. (the 'l' parameter)
  75. For a brainwallet passphrase to always generate the same keys and addresses,
  76. the same 'l' and 'p' parameters to '--from-brain' must be used in all future
  77. invocations with that passphrase
  78. """.format(
  79. extra_help_data[0],
  80. ", ".join([str(i) for i in seed_lens]),
  81. seed_len,
  82. hash_preset,
  83. extra_help_data[1],
  84. extra_help_data[2],
  85. W=gen_what,
  86. S=seed_ext
  87. )
  88. }
  89. so = "h","A","d:","e","K","l:","p:","P","q","S","v","x","b:","m","s"
  90. lo = "help","no_addresses","outdir=","echo_passphrase","no_keyconv",\
  91. "seed_len=","hash_preset=","show_hash_presets","quiet","stdout",\
  92. "verbose","b16","from_brain=","from_mnemonic","from_seed"
  93. if invoked_as == "addrgen":
  94. short_opts = so[0:1] + so[2:10] + so[11:]
  95. long_opts = lo[0:1] + lo[2:10] + lo[11:]
  96. else:
  97. short_opts,long_opts = so,lo
  98. opts,cmd_args = process_opts(sys.argv,help_data,"".join(short_opts),long_opts)
  99. if 'show_hash_presets' in opts: show_hash_presets()
  100. # Sanity checking and processing of command-line arguments:
  101. opts['gen_what'] = gen_what
  102. set_if_unset_and_typeconvert(opts,(
  103. ('hash_preset',hash_preset,'str'),
  104. ('seed_len',seed_len,'int')
  105. ))
  106. # Exits on invalid input
  107. check_opts(opts,('hash_preset','seed_len','outdir','from_brain'))
  108. if debug:
  109. print "Processed options: %s" % repr(opts)
  110. print "Cmd args: %s" % repr(cmd_args)
  111. if len(cmd_args) == 1 and (
  112. 'from_mnemonic' in opts or
  113. 'from_brain' in opts or
  114. 'from_seed' in opts
  115. ): infile,addr_range = "",cmd_args[0]
  116. elif len(cmd_args) == 2:
  117. infile,addr_range = cmd_args
  118. check_infile(infile)
  119. else: usage(help_data)
  120. start,end = parse_address_range(addr_range)
  121. if not 'quiet' in opts: do_license_msg()
  122. # Interact with user:
  123. if invoked_as == "keygen" and not 'quiet' in opts:
  124. confirm_or_exit(cmessages['unencrypted_secret_keys'], 'continue')
  125. # Generate data:
  126. if invoked_as == "addrgen":
  127. opts['print_addresses_only'] = True
  128. else:
  129. if not 'no_addresses' in opts: opts['print_secret'] = True
  130. seed = get_seed(infile,opts)
  131. seed_id = make_chksum_8(seed)
  132. addr_data = generate_addrs(seed, start, end, opts)
  133. addr_data_str = format_addr_data(addr_data, seed_id, opts)
  134. # Output data:
  135. if 'stdout' in opts:
  136. if invoked_as == "keygen" and not 'quiet' in opts:
  137. confirm = True
  138. else: confirm = False
  139. write_to_stdout(addr_data_str,"secret keys",confirm)
  140. elif not sys.stdout.isatty():
  141. write_to_stdout(addr_data_str,"secret keys",confirm=False)
  142. else:
  143. write_addr_data_to_file(seed, addr_data_str, start, end, opts)