new file: MANIFEST new file: mmgen-addrgen new file: mmgen-keygen new file: mmgen-passchg new file: mmgen-walletchk new file: mmgen-walletgen new file: mmgen/Opts.py new file: mmgen/__init__.py new file: mmgen/addr.py new file: mmgen/bitcoin.py new file: mmgen/config.py new file: mmgen/license.py new file: mmgen/mn_electrum.py new file: mmgen/mn_tirosh.py new file: mmgen/mnemonic.py new file: mmgen/utils.py new file: mmgen/walletgen.py new file: setup.py new file: tests/addr.py new file: tests/bitcoin.py new file: tests/mn_electrum.py new file: tests/mn_tirosh.py new file: tests/mnemonic.py new file: tests/test.py new file: tests/utils.py new file: tests/walletgen.py new file: wordlists/mn_wordlist.c new file: wordlists/mn_wordlist.py new file: wordlists/mn_wordlist.sort.py new file: wordlists/mnemonic.py new file: wordlists/mnemonic.sort.py
175 lines
6 KiB
Python
Executable file
175 lines
6 KiB
Python
Executable file
#!/usr/bin/env python
|
|
#
|
|
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
|
|
# Copyright (C) 2013 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-keygen: Generate addresses/secret keys from a mmgen deterministic
|
|
wallet for a range of addresses.
|
|
Call as 'btc-addrgen' for safe, reduced functionality
|
|
with no output of secret keys.
|
|
"""
|
|
|
|
import sys
|
|
|
|
from mmgen.Opts import *
|
|
from mmgen.config import *
|
|
from mmgen.license import *
|
|
from mmgen.utils 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 range of {} from a {} wallet, mnemonic,
|
|
seed or password""".format(gen_what,proj_name),
|
|
'usage':"[opts] [infile] <address range>",
|
|
'options': """
|
|
-h, --help Print this help message{}
|
|
-d, --outdir d Specify an alternate directory 'd' for output
|
|
-e, --echo-passphrase Display passphrase or mnemonic on screen upon entry
|
|
-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, --show-hash-presets Show information on available hash presets
|
|
-q, --quiet Suppress warnings; overwrite files without asking
|
|
-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)
|
|
-m, --from-mnemonic Generate {W} from an electrum-like mnemonic
|
|
-s, --from-seed Generate {W} from a seed in .{S} format
|
|
|
|
Address range may be a single number or a range in the form XXX-YYY{}
|
|
|
|
If available, 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. Note
|
|
that passphrase data in a file may be arranged in free-form fashion, using
|
|
any combination of spaces, tabs or newlines to separate words
|
|
|
|
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 seed_lens]),
|
|
seed_len,
|
|
hash_preset,
|
|
extra_help_data[1],
|
|
extra_help_data[2],
|
|
W=gen_what,
|
|
S=seed_ext
|
|
)
|
|
}
|
|
|
|
so = "h","A","d:","e","K","l:","p:","P","q","S","v","x","b:","m","s"
|
|
lo = "help","no_addresses","outdir=","echo_passphrase","no_keyconv",\
|
|
"seed_len=","hash_preset=","show_hash_presets","quiet","stdout",\
|
|
"verbose","b16","from_brain=","from_mnemonic","from_seed"
|
|
|
|
if invoked_as == "addrgen":
|
|
short_opts = so[0:1] + so[2:10] + so[11:]
|
|
long_opts = lo[0:1] + lo[2:10] + lo[11:]
|
|
else:
|
|
short_opts,long_opts = so,lo
|
|
|
|
opts,cmd_args = process_opts(sys.argv,help_data,"".join(short_opts),long_opts)
|
|
|
|
if 'show_hash_presets' in opts: show_hash_presets()
|
|
|
|
# Sanity checking and processing of command-line arguments:
|
|
|
|
opts['gen_what'] = gen_what
|
|
|
|
set_if_unset_and_typeconvert(opts,(
|
|
('hash_preset',hash_preset,'str'),
|
|
('seed_len',seed_len,'int')
|
|
))
|
|
|
|
# Exits on invalid input
|
|
check_opts(opts,('hash_preset','seed_len','outdir','from_brain'))
|
|
|
|
if debug:
|
|
print "Processed options: %s" % repr(opts)
|
|
print "Cmd args: %s" % repr(cmd_args)
|
|
|
|
if len(cmd_args) == 1 and (
|
|
'from_mnemonic' in opts or
|
|
'from_brain' in opts or
|
|
'from_seed' in opts
|
|
): infile,addr_range = "",cmd_args[0]
|
|
elif len(cmd_args) == 2:
|
|
infile,addr_range = cmd_args
|
|
check_infile(infile)
|
|
else: usage(help_data)
|
|
|
|
start,end = parse_address_range(addr_range)
|
|
|
|
if not 'quiet' in opts: do_license_msg(); msg("\n")
|
|
|
|
# Interact with user:
|
|
|
|
if invoked_as == "keygen" and not 'quiet' in opts:
|
|
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(infile,opts)
|
|
seed_id = make_chksum_8(seed)
|
|
addr_data = generate_addrs(seed, start, end, opts)
|
|
addr_data_str = format_addr_data(addr_data, seed_id, opts)
|
|
|
|
# Output data:
|
|
if 'stdout' in opts:
|
|
if invoked_as == "keygen" and not 'quiet' in opts:
|
|
confirm = True
|
|
else: confirm = False
|
|
write_to_stdout(addr_data_str,confirm)
|
|
elif not sys.stdout.isatty():
|
|
write_to_stdout(addr_data_str,confirm=False)
|
|
else:
|
|
write_addr_data_to_file(seed, addr_data_str, start, end, opts)
|