mmgen-wallet/mmgen-addrgen
philemon 0894985bfa Added 'mmgen-tool' utility with following commands:
General operations:
  hexdump      - encode binary data in formatted hexadecimal form
  unhexdump    - decode formatted hexadecimal data

  Bitcoin operations:
  strtob58     - convert a string to base 58
  hextob58     - convert a hexadecimal number to base 58
  b58tohex     - convert a base 58 number to hexadecimal
  b58randenc   - generate a random 32-byte number and convert it to base 58
  randwif      - generate a random private key in WIF format
  randpair     - generate a random private key/address pair
  wif2addr     - generate a Bitcoin address from a key in WIF format

  Mnemonic operations (choose "electrum" (default), "tirosh" or "all" wordlists):
  mn_rand128   - generate random 128-bit mnemonic
  mn_rand192   - generate random 192-bit mnemonic
  mn_rand256   - generate random 256-bit mnemonic
  mn_stats     - show stats for mnemonic wordlist
  mn_printlist - print mnemonic wordlist
2014-07-17 21:50:52 +04:00

186 lines
6.5 KiB
Python
Executable file

#!/usr/bin/env python
#
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
mmgen-addrgen: Generate a list or range of addresses from a mmgen
deterministic wallet.
Call as 'btc-keygen' to allow key generation as well.
"""
import sys
import mmgen.config as g
from mmgen.Opts import *
from mmgen.license import *
from mmgen.util import *
from mmgen.addr import *
invoked_as = sys.argv[0].split("-")[-1]
gen_what = "addresses" if invoked_as == "addrgen" else "keys"
if invoked_as == "keygen":
extra_help_data = (
"\n-A, --no-addresses Print only secret keys, no addresses",
"\n-x, --b16 Print secret keys in hexadecimal too",
"\nBy default, both addresses and secret keys are generated."
)
else: extra_help_data = ("","","")
help_data = {
'prog_name': sys.argv[0].split("/")[-1],
'desc': """Generate a list or range of {} from a {} wallet,
mnemonic, seed or password""".format(gen_what,g.proj_name),
'usage':"[opts] [infile] <address list>",
'options': """
-h, --help Print this help message{}
-d, --outdir d Specify an alternate directory 'd' for output
-e, --echo-passphrase Echo passphrase or mnemonic to screen upon entry
-H, --show-hash-presets Show information on available hash presets
-K, --no-keyconv Use internal libraries for address generation
instead of 'keyconv'
-l, --seed-len N Length of seed. Options: {}
(default: {})
-p, --hash-preset p Use scrypt.hash() parameters from preset 'p'
when hashing password (default: '{}')
-P, --passwd-file f Get passphrase from file 'f'
-q, --quiet Suppress warnings; overwrite files without
prompting
-S, --stdout Print {W} to stdout
-v, --verbose Produce more verbose output{}
-b, --from-brain l,p Generate {W} from a user-created password,
i.e. a "brainwallet", using seed length 'l' and
hash preset 'p' (comma-separated)
-g, --from-incog Generate {W} from an incognito wallet
-X, --from-incog-hex Generate {W} from an incognito hexadecimal wallet
-G, --from-incog-hidden f,o,l Generate {W} from incognito data in file
'f' at offset 'o', with seed length of 'l'
-m, --from-mnemonic Generate {W} from an electrum-like mnemonic
-s, --from-seed Generate {W} from a seed in .{S} format
Addresses are given in a comma-separated list. Hyphen-separated
ranges are also allowed.{}
If available, the external 'keyconv' program will be used for address
generation.
Data for the --from-<what> options will be taken from <infile> if <infile>
is specified. Otherwise, the user will be prompted to enter the data.
For passphrases all combinations of whitespace are equal, and leading and
trailing space are ignored. This permits reading passphrase data from a
multi-line file with free spacing and indentation. This is particularly
convenient for long brainwallet passphrases, for example.
BRAINWALLET NOTE:
As brainwallets require especially strong hashing to thwart dictionary
attacks, the brainwallet hash preset must be specified by the user, using
the 'p' parameter of the '--from-brain' option
The '--from-brain' option also requires the user to specify a seed length
(the 'l' parameter)
For a brainwallet passphrase to always generate the same keys and
addresses, the same 'l' and 'p' parameters to '--from-brain' must be used
in all future invocations with that passphrase
""".format(
extra_help_data[0],
", ".join([str(i) for i in g.seed_lens]),
g.seed_len,
g.hash_preset,
extra_help_data[1],
extra_help_data[2],
W=gen_what,
S=g.seed_ext
)
}
short_opts = ["h","A","d:","e",
"H","K","l:","p:",
"P:","q","S","v","x","b:",
"g","X","G:","m","s"]
long_opts = ["help","no_addresses","outdir=","echo_passphrase",
"show_hash_presets","no_keyconv","seed_len=","hash_preset=",
"passwd_file=","quiet","stdout","verbose","b16","from_brain=",
"from_incog","from_incog_hex","from_incog_hidden=",
"from_mnemonic","from_seed"]
if invoked_as == "addrgen":
for i in "A","x": short_opts.remove(i)
for i in "no_addresses","b16": long_opts.remove(i)
opts,cmd_args = process_opts(sys.argv,help_data,"".join(short_opts),long_opts)
if 'show_hash_presets' in opts: show_hash_presets()
if 'verbose' in opts: g.verbose = True
if 'quiet' in opts: g.quiet = True
if 'from_incog_hex' in opts or 'from_incog_hidden' in opts:
opts['from_incog'] = True
opts['gen_what'] = gen_what
check_opts(opts,long_opts)
if g.debug: show_opts_and_cmd_args(opts,cmd_args)
if len(cmd_args) == 1 and (
'from_mnemonic' in opts
or 'from_brain' in opts
or 'from_seed' in opts
or 'from_incog_hidden' in opts
):
infile,addr_list_arg = "",cmd_args[0]
elif len(cmd_args) == 2:
infile,addr_list_arg = cmd_args
check_infile(infile)
else: usage(help_data)
addr_list = parse_address_list(addr_list_arg)
if not addr_list: sys.exit(2)
do_license_msg()
# Interact with user:
if invoked_as == "keygen" and not g.quiet:
confirm_or_exit(cmessages['unencrypted_secret_keys'], 'continue')
# Generate data:
if invoked_as == "addrgen":
opts['print_addresses_only'] = True
else:
if not 'no_addresses' in opts: opts['print_secret'] = True
seed = get_seed_retry(infile,opts)
seed_id = make_chksum_8(seed)
addr_data = generate_addrs(seed, addr_list, opts)
addr_data_str = format_addr_data(addr_data, seed_id, opts)
# Output data:
if 'stdout' in opts:
if invoked_as == "keygen" and not g.quiet:
confirm = True
else: confirm = False
write_to_stdout(addr_data_str,"secret keys",confirm)
elif not sys.stdout.isatty():
write_to_stdout(addr_data_str,"secret keys",confirm=False)
else:
write_addr_data_to_file(seed, addr_data_str, addr_list, opts)