Code cleanups, streamlined code in 'mmgen/addr.py'

This commit is contained in:
The MMGen Project 2014-08-03 16:16:09 +04:00
commit 7e079f1b7a
17 changed files with 220 additions and 450 deletions

View file

@ -31,12 +31,12 @@ from mmgen.util import *
from mmgen.addr import *
from mmgen.tx import make_addr_data_chksum
gen_what = "addresses" if sys.argv[0].split("-")[-1] == "addrgen" else "keys"
what = "keys" if sys.argv[0].split("-")[-1] == "keygen" else "addresses"
help_data = {
'prog_name': g.prog_name,
'desc': """Generate a list or range of {} from an {g.proj_name} wallet,
mnemonic, seed or password""".format(gen_what,g=g),
mnemonic, seed or password""".format(what,g=g),
'usage':"[opts] [infile] <address list>",
'options': """
-h, --help Print this help message{}
@ -73,9 +73,9 @@ help_data = {
"\n '{}-txsign'".format(g.proj_name.lower()),
"\n-x, --b16 Print secret keys in hexadecimal too"
)
if gen_what == "keys" else ("","","")),
if what == "keys" else ("","","")),
seed_lens=", ".join([str(i) for i in g.seed_lens]),
what=gen_what, g=g
what=what, g=g
),
'notes': """
@ -106,7 +106,7 @@ 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("\n\nBy default, both addresses and secret keys are generated."
if gen_what == "keys" else "")
if what == "keys" else "")
}
opts,cmd_args = parse_opts(sys.argv,help_data)
@ -117,8 +117,6 @@ 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
if g.debug: show_opts_and_cmd_args(opts,cmd_args)
if len(cmd_args) == 1 and (
@ -140,22 +138,26 @@ if not addr_idxs: sys.exit(2)
do_license_msg()
# Interact with user:
if gen_what == "keys" and not g.quiet:
if what == "keys" and not g.quiet:
confirm_or_exit(cmessages['unencrypted_secret_keys'], 'continue')
# Generate data:
if gen_what == "addresses":
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)
for l in (
('flat_list', 'no_addresses'),
('flat_list', 'b16'),
): check_incompatible_opts(opts,l)
opts['gen_what'] = \
("addrs") if what == "addresses" else (
("keys") if 'no_addresses' in opts else ("addrs","keys"))
addr_data = generate_addrs(seed, addr_idxs, opts)
addr_data_chksum = make_addr_data_chksum([(a['num'],a['addr'])
for a in addr_data]) if not 'no_addresses' in opts else ""
addr_data_chksum = make_addr_data_chksum([(a.num,a.addr)
for a in addr_data]) if 'addrs' in opts['gen_what'] else ""
addr_data_str = format_addr_data(
addr_data, addr_data_chksum, seed_id, addr_idxs, opts)
@ -163,20 +165,19 @@ outfile_base = "{}[{}]".format(seed_id, fmt_addr_idxs(addr_idxs))
# Output data:
if 'stdout' in opts:
confirm = True if (gen_what == "keys" and not g.quiet) else False
write_to_stdout(addr_data_str,gen_what,confirm)
confirm = True if (what == "keys" and not g.quiet) else False
write_to_stdout(addr_data_str,what,confirm)
elif not sys.stdout.isatty():
write_to_stdout(addr_data_str,gen_what,confirm=False)
write_to_stdout(addr_data_str,what,confirm=False)
else:
confirm = False if g.quiet else True
outfile = outfile_base + "." + (
g.addrfile_ext if 'print_addresses_only' in opts else (
g.keyfile_ext if 'no_addresses' in opts else (
g.keylist_ext if 'flat_list' in opts else "akeys"))
)
write_to_file(outfile,addr_data_str,opts,gen_what,confirm,True)
g.keylist_ext if 'flat_list' in opts else (
g.keyfile_ext if opts['gen_what'] == ("keys") else (
g.addrfile_ext if opts['gen_what'] == ("addrs") else "akeys")))
write_to_file(outfile,addr_data_str,opts,what,confirm,True)
if not 'no_addresses' in opts:
if 'addrs' in opts['gen_what']:
msg("Checksum for address data {}: {}".format(outfile_base,addr_data_chksum))
if 'save_checksum' in opts:
a = "address data checksum"

View file

@ -26,6 +26,7 @@ from mmgen.util import *
import mmgen.config as g
help_data = {
'prog_name': g.prog_name,
'desc': """Change the passphrase, hash preset or label of an {}
deterministic wallet""".format(g.proj_name),
'usage': "[opts] [filename]",

View file

@ -86,6 +86,8 @@ help_data = {
}
opts,cmd_args = parse_opts(sys.argv,help_data)
from mmgen.Opts import check_incompatible_opts
check_incompatible_opts(opts,('json','keys','addrs','keysforaddrs'))
if len(cmd_args) == 1:
from mmgen.util import check_infile

View file

@ -19,13 +19,10 @@
mmgen-tool: Perform various Bitcoin-related operations - part of the MMGen suite
"""
import sys, os
from hashlib import sha256
import sys
import mmgen.config as g
import mmgen.tool as tool
from mmgen.Opts import *
from mmgen.util import pretty_hexdump
help_data = {
'prog_name': g.prog_name,

View file

@ -89,6 +89,11 @@ Seed data supplied in files must have the following extensions:
opts,infiles = parse_opts(sys.argv,help_data)
for l in (
('tx_id', 'info'),
('keys_from_file','all_keys_from_file')
): check_incompatible_opts(opts,l)
if "quiet" in opts: g.quiet = True
if 'from_incog_hex' in opts or 'from_incog_hidden' in opts:
opts['from_incog'] = True

View file

@ -25,7 +25,6 @@ from hashlib import sha256
import mmgen.config as g
from mmgen.Opts import *
from mmgen.license import *
from mmgen.walletgen import *
from mmgen.util import *
help_data = {

View file

@ -16,112 +16,101 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys, getopt
import sys
import mmgen.config as g
import mmgen.opt.Opts
from mmgen.util import msg,check_infile,check_outfile,check_outdir
def usage(hd):
print "USAGE: %s %s" % (hd['prog_name'], hd['usage'])
sys.exit(2)
def usage(hd): mmgen.opt.Opts.usage(hd)
def print_version_info(): # MMGen only
def print_version_info():
print """
'{g.prog_name}' version {g.version}. Part of the {g.proj_name} suite.
Copyright (C) {g.Cdates} by {g.author} {g.email}.
""".format(g=g).strip()
def print_help(help_data):
pn = help_data['prog_name']
pn_len = str(len(pn)+2)
print (" %-"+pn_len+"s %s") % (pn.upper()+":", help_data['desc'].strip())
print (" %-"+pn_len+"s %s %s")%("USAGE:", pn, help_data['usage'].strip())
sep = "\n "
print " OPTIONS:"+sep+"%s" % sep.join(help_data['options'].strip().split("\n"))
if "notes" in help_data:
print " %s" % "\n ".join(help_data['notes'][1:-1].split("\n"))
def process_opts(argv,help_data,short_opts,long_opts):
if len(argv) == 2 and argv[1] == '--version': # MMGen only!
print_version_info(); sys.exit()
if g.debug:
print "Short opts: %s" % repr(short_opts)
print "Long opts: %s" % repr(long_opts)
long_opts = [i.replace("_","-") for i in long_opts]
try: cl_opts, args = getopt.getopt(argv[1:], short_opts, long_opts)
except getopt.GetoptError as err:
print str(err); sys.exit(2)
opts,short_opts_l = {},[]
for i in short_opts:
if i == ":": short_opts_l[-1] += i
else: short_opts_l += i
for opt, arg in cl_opts:
if opt in ("-h","--help"): print_help(help_data); sys.exit()
elif opt[:2] == "--" and opt[2:] in long_opts:
opts[opt[2:].replace("-","_")] = True
elif opt[:2] == "--" and opt[2:]+"=" in long_opts:
opts[opt[2:].replace("-","_")] = arg
elif opt[0] == "-" and opt[1] in short_opts_l:
opts[long_opts[short_opts_l.index(opt[1:])].replace("-","_")] = True
elif opt[0] == "-" and opt[1:]+":" in short_opts_l:
opts[long_opts[short_opts_l.index(opt[1:]+":")][:-1].replace("-","_")] = arg
else: assert False, "Invalid option"
if g.debug: print "User-selected options: %s" % repr(opts)
return opts,args
def check_incompatible_opts(opts,incompat_list):
bad = [k for k in opts.keys() if k in incompat_list]
if len(bad) > 1:
msg("Mutually exclusive options: %s" % " ".join(
["--"+b.replace("_","-") for b in bad]))
sys.exit(1)
def parse_opts(argv,help_data):
lines = help_data['options'].strip().split("\n")
import re
pat = r"^-([a-zA-Z0-9]), --([a-zA-Z0-9-]{1,64})(=| )(.+)"
rep = r"-{0}, --{1}{w}{3}"
opt_data = [list(m.groups()) for m in [re.match(pat,l) for l in lines] if m]
# for o in opt_data: print o
# sys.exit()
if len(argv) == 2 and argv[1] == '--version':
print_version_info(); sys.exit()
for d in opt_data:
if d[2] == " ": d[2] = ""
short_opts = "".join([d[0]+d[2].replace("=",":") for d in opt_data])
long_opts = [d[1].replace("-","_")+d[2] for d in opt_data]
help_data['options'] = "\n".join(
[rep.format(w=" ", *m.groups())
if m else k for m,k in [(re.match(pat,l),l) for l in lines]]
)
opts,infiles = process_opts(argv,help_data,short_opts,long_opts)
opts,args,short_opts,long_opts = mmgen.opt.Opts.parse_opts(argv,help_data)
if g.debug:
print "short opts: %s" % repr(short_opts)
print "long opts: %s" % repr(long_opts)
print "user-selected opts: %s" % repr(opts)
print "cmd args: %s" % repr(args)
for l in (
('outdir', 'export_incog_hidden'),
('from_incog_hidden','from_incog','from_seed','from_mnemonic','from_brain'),
('export_incog','export_incog_hex','export_incog_hidden','export_mnemonic',
'export_seed'),
('quiet','verbose')
): check_incompatible_opts(opts,l)
# check_opts() doesn't touch opts[]
if not check_opts(opts,long_opts): sys.exit(1)
# If unset, set these to the default values in mmgen.config:
# If unset, set these to default values in mmgen.config:
for v in g.cl_override_vars:
if v in opts: typeconvert_override_var(opts,v)
else: opts[v] = eval("g."+v)
if g.debug: print "processed opts: %s" % opts
if g.debug: print "opts after typeconvert: %s" % opts
return opts,infiles
return opts,args
def show_opts_and_cmd_args(opts,cmd_args):
print "Processed options: %s" % repr(opts)
print "Cmd args: %s" % repr(cmd_args)
# Everything below here is MMGen-specific:
from mmgen.util import msg,check_infile
def check_opts(opts,long_opts):
def opt_splits(val,sep,n,what):
sepword = "comma" if sep == "," else (
"colon" if sep == ":" else ("'"+sep+"'"))
try: l = val.split(sep)
except:
msg("'%s': invalid %s (not %s-separated list)" % (val,what,sepword))
return False
if len(l) == n: return True
else:
msg("'%s': invalid %s (%s %s-separated items required)" %
(val,what,n,sepword))
return False
def opt_compares(val,op,target,what):
if not eval("%s %s %s" % (val, op, target)):
msg("%s: invalid %s (not %s %s)" % (val,what,op,target))
return False
return True
def opt_is_int(val,what):
try: int(val)
except:
msg("'%s': invalid %s (not an integer)" % (val,what))
return False
return True
def opt_is_in_list(val,lst,what):
if val not in lst:
q,sep = ("'","','") if type(lst[0]) == str else ("",",")
msg("{q}{}{q}: invalid {}\nValid options: {q}{}{q}".format(
val,what,sep.join([str(i) for i in sorted(lst)]),q=q))
return False
return True
for opt,val in opts.items():
what = "parameter for '--%s' option" % opt.replace("_","-")
@ -133,121 +122,49 @@ def check_opts(opts,long_opts):
continue
if opt == 'outdir':
what = "output directory"
import os
if os.path.isdir(val):
if os.access(val, os.W_OK|os.X_OK):
opts[opt] = os.path.normpath(val)
else:
msg("Requested %s '%s' is unwritable by you" % (what,val))
return False
else:
msg("Requested %s '%s' does not exist" % (what,val))
return False
check_outdir(val) # exits on error
elif opt == 'label':
if len(val) > g.max_wallet_label_len:
msg("Label must be %s characters or less" %
g.max_wallet_label_len)
if not opt_compares(len(val),"<=",g.max_wallet_label_len,"label length"):
return False
try: val.decode("ascii")
except:
msg("ERROR: label contains a non-ASCII symbol")
return False
w = "character in label"
for ch in list(val):
chs = g.wallet_label_symbols
if ch not in chs:
msg("'%s': ERROR: label contains an illegal symbol" % val)
msg("The following symbols are permitted:\n%s" % "".join(chs))
return False
if not opt_is_in_list(ch,g.wallet_label_symbols,w): return False
elif opt == 'export_incog_hidden' or opt == 'from_incog_hidden':
try:
if opt == 'export_incog_hidden':
outfile,offset = val.split(",")
else:
outfile,offset,seed_len = val.split(",")
except:
msg("'%s': invalid %s" % (val,what))
return False
try:
o = int(offset)
except:
msg("'%s': invalid 'o' %s (not an integer)" % (offset,what))
return False
if o < 0:
msg("'%s': invalid 'o' %s (less than zero)" % (offset,what))
return False
if opt == 'from_incog_hidden':
try:
sl = int(seed_len)
except:
msg("'%s': invalid 'l' %s (not an integer)" % (sl,what))
return False
if sl not in g.seed_lens:
msg("'%s': invalid 'l' %s (valid choices: %s)" %
(sl,what," ".join(str(i) for i in g.seed_lens)))
return False
import os, stat
try: mode = os.stat(outfile).st_mode
except:
msg("Unable to stat requested %s '%s'" % (what,outfile))
return False
if not (stat.S_ISREG(mode) or stat.S_ISBLK(mode)):
msg("Requested %s '%s' is not a file or block device" %
(what,outfile))
return False
ac,m = (os.W_OK,"writ") \
if "export_incog_hidden" in opts else (os.R_OK,"read")
if not os.access(outfile, ac):
msg("Requested %s '%s' is un%sable by you" % (what,outfile,m))
return False
if not opt_splits(val,",",3,what): return False
infile,offset,seed_len = val.split(",")
check_infile(infile)
w = "seed length " + what
if not opt_is_int(seed_len,w): return False
if not opt_is_in_list(int(seed_len),g.seed_lens,w): return False
else:
if not opt_splits(val,",",2,what): return False
outfile,offset = val.split(",")
check_outfile(outfile)
w = "offset " + what
if not opt_is_int(offset,w): return False
if not opt_compares(offset,">=",0,what): return False
elif opt == 'from_brain':
try:
l,p = val.split(",")
except:
msg("'%s': invalid %s" % (val,what))
return False
try:
int(l)
except:
msg("'%s': invalid 'l' %s (not an integer)" % (l,what))
return False
if int(l) not in g.seed_lens:
msg("'%s': invalid 'l' %s. Options: %s" %
(l, what, ", ".join([str(i) for i in g.seed_lens])))
return False
if p not in g.hash_presets:
hps = ", ".join([i for i in sorted(g.hash_presets.keys())])
msg("'%s': invalid 'p' %s. Options: %s" % (p, what, hps))
return False
if not opt_splits(val,",",2,what): return False
l,p = val.split(",")
w = "seed length " + what
if not opt_is_int(l,w): return False
if not opt_is_in_list(int(l),g.seed_lens,w): return False
w = "hash preset " + what
if not opt_is_in_list(p,g.hash_presets.keys(),w): return False
elif opt == 'seed_len':
if val not in g.seed_lens:
msg("'%s': invalid %s. Options: %s"
% (val,what,", ".join([str(i) for i in g.seed_lens])))
return False
if not opt_is_int(val,what): return False
if not opt_is_in_list(int(val),g.seed_lens,what): return False
elif opt == 'hash_preset':
if val not in g.hash_presets:
msg("'%s': invalid %s. Options: %s"
% (val,what,", ".join(sorted(g.hash_presets.keys()))))
return False
if not opt_is_in_list(val,g.hash_presets.keys(),what): return False
elif opt == 'usr_randchars':
try: v = int(val)
except:
msg("'%s': invalid value for %s (not an integer)" % (val,what))
return False
if v != 0 and not (g.min_urandchars <= v <= g.max_urandchars):
msg("'%s': invalid %s (must be >= %s and <= %s (or zero))"
% (v,what,g.min_urandchars,g.max_urandchars))
return False
if not opt_is_int(val,what): return False
if not opt_compares(val,">=",g.min_urandchars,what): return False
if not opt_compares(val,"<=",g.max_urandchars,what): return False
else:
if g.debug: print "check_opts(): No test for opt '%s'" % opt

View file

@ -33,36 +33,33 @@ addrmsgs = {
# MMGen address file
#
# This file is editable.
# Everything following a hash symbol '#' is a comment and ignored by {}.
# Everything following a hash symbol '#' is a comment and ignored by {pnm}.
# A text label of {} characters or less may be added to the right of each
# address, and it will be appended to the bitcoind wallet label upon import.
# The label may contain any printable ASCII symbol.
""".strip().format(g.proj_name,g.max_addr_label_len)
""".strip().format(g.max_addr_label_len,pnm=g.proj_name),
'no_keyconv_msg': """
Executable '{kcexe}' unavailable. Falling back on (slow) internal ECDSA library.
Please install '{kcexe}' from the {vanityg} package on your system for much
faster address generation.
""".format(kcexe=g.keyconv_exec, vanityg="vanitygen")
}
def test_for_keyconv():
"""
Test for the presence of 'keyconv' utility on system
"""
from subprocess import Popen, PIPE
try:
p = Popen([g.keyconv_exec, '-h'], stdout=PIPE, stderr=PIPE)
except:
sys.stderr.write("""
Executable '%s' unavailable. Falling back on (slow) internal ECDSA library.
Please install '%s' from the %s package on your system for much
faster address generation.
""" % (g.keyconv_exec, g.keyconv_exec, "vanitygen"))
msg(addrmsgs['no_keyconv_msg'])
return False
else:
return True
return True
def generate_addrs(seed, addrnums, opts):
if not 'no_addresses' in opts:
if 'addrs' in opts['gen_what']:
if 'no_keyconv' in opts or test_for_keyconv() == False:
msg("Using (slow) internal ECDSA library for address generation")
from mmgen.bitcoin import privnum2addr
@ -71,73 +68,62 @@ def generate_addrs(seed, addrnums, opts):
from subprocess import Popen, PIPE
keyconv = "keyconv"
a,t_addrs,i,out = sorted(addrnums),len(addrnums),0,[]
fmt = "num addr" if opts['gen_what'] == ("addrs") else (
"num sec wif" if opts['gen_what'] == ("keys") else "num sec wif addr")
while a:
seed = sha512(seed).digest()
i += 1 # round /i/
from collections import namedtuple
addrinfo = namedtuple("addrinfo",fmt)
addrinfo_args = "%s" % ",".join(fmt.split())
if g.debug: print "Seed round %s: %s" % (i, hexlify(seed))
t_addrs,num,pos,out = len(addrnums),0,0,[]
addrnums.sort() # needed only if caller didn't sort
if i < a[0]: continue
try:
while pos != t_addrs:
seed = sha512(seed).digest()
num += 1 # round
a.pop(0)
if g.debug: print "Seed round %s: %s" % (num, hexlify(seed))
if num != addrnums[pos]: continue
qmsg_r("\rGenerating %s %s (%s of %s)" %
(opts['gen_what'], i, t_addrs-len(a), t_addrs))
pos += 1
# Secret key is double sha256 of seed hash round /i/
sec = sha256(sha256(seed).digest()).hexdigest()
wif = numtowif(int(sec,16))
qmsg_r("\rGenerating %s %s (%s of %s)" %
(opts['gen_what'][-1],num,pos,t_addrs))
if g.debug:
print "Privkey round %s:\n hex: %s\n wif: %s" % (i, sec, wif)
# Secret key is double sha256 of seed hash round /num/
sec = sha256(sha256(seed).digest()).hexdigest()
wif = numtowif(int(sec,16))
d = { 'num': i }
if 'addrs' in opts['gen_what']: addr = \
Popen([keyconv, wif], stdout=PIPE).stdout.readline().split()[1] \
if keyconv else privnum2addr(int(sec,16))
if not 'print_addresses_only' in opts:
d['sec'] = sec
d['wif'] = wif
out.append(eval("addrinfo("+addrinfo_args+")"))
if not 'no_addresses' in opts:
if keyconv:
p = Popen([keyconv, wif], stdout=PIPE)
addr = dict([j.split() for j in \
p.stdout.readlines()])['Address:']
else:
addr = privnum2addr(int(sec,16))
except KeyboardInterrupt:
msg("\nUser interrupt")
sys.exit(1)
d['addr'] = addr
out.append(d)
w = opts['gen_what']
if t_addrs == 1:
import re
w = re.sub('e*s$','',w)
w = 'key' if 'keys' in opts['gen_what'] else 'address'
if t_addrs != 1: w = w+"s" if w == 'key' else w+"es"
qmsg("\rGenerated %s %s%s"%(t_addrs, w, " "*15))
return out
def generate_keys(seed, addrnums):
o = {'no_addresses': True, 'gen_what': "keys"}
return generate_addrs(seed, addrnums, o)
def format_addr_data(addr_data, addr_data_chksum, seed_id, addr_idxs, opts):
if 'flat_list' in opts:
return "\n\n".join(["# %s:%s %s\n%s" % (seed_id,d['num'],d['addr'],d['wif'])
return "\n\n".join(["# {}:{d.num} {d.addr}\n{d.wif}".format(seed_id,d=d)
for d in addr_data])+"\n\n"
start = addr_data[0]['num']
end = addr_data[-1]['num']
fs = " %-{}s %s".format(len(str(end)))
out = []
fs = " {:<%s} {}" % len(str(addr_data[-1].num))
if not 'no_addresses' in opts:
if not 'stdout' in opts: out.append(addrmsgs['addrfile_header'] + "\n")
if 'addrs' not in opts['gen_what']: out = []
else:
out = [] if 'stdout' in opts else [addrmsgs['addrfile_header']+"\n"]
out.append("# Address data checksum for {}[{}]: {}".format(
seed_id, fmt_addr_idxs(addr_idxs), addr_data_chksum))
out.append("# Record this value to a secure location\n")
@ -145,14 +131,16 @@ def format_addr_data(addr_data, addr_data_chksum, seed_id, addr_idxs, opts):
out.append("%s {" % seed_id.upper())
for d in addr_data:
if 'no_addresses' in opts:
out.append(fs % (d['num'], "wif: " + d['wif']))
if 'addrs' in opts['gen_what']: # First line with number
out.append(fs.format(d.num, d.addr))
else:
out.append(fs % (d['num'], d['addr']))
if 'b16' in opts:
out.append(fs % ("", "hex: " + d['sec']))
if 'print_secret' in opts and not 'no_addresses' in opts:
out.append(fs % ("", "wif: " + d['wif']))
out.append(fs.format(d.num, "wif: "+d.wif))
if 'keys' in opts['gen_what']: # Subsequent lines
if 'b16' in opts:
out.append(fs.format("", "hex: "+d.sec))
if 'addrs' in opts['gen_what']:
out.append(fs.format("", "wif: "+d.wif))
out.append("}")

View file

@ -1,27 +0,0 @@
#!/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/>.
"""
addr.py: Test suite for mmgen.addr module
"""
from mmgen.addr import *
tests = "none",
if (len(sys.argv) == 1):
print "Available tests: %s" % " ".join(tests)

View file

@ -1,24 +0,0 @@
#!/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/>.
"""
mn_electrum.py: Test suite for mmgen.mn_electrum module
"""
from mmgen.mn_electrum import *
print electrum_words.strip()

View file

@ -1,24 +0,0 @@
#!/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/>.
"""
mn_tirosh.py: Test suite for mmgen.mn_tirosh module
"""
from mmgen.mn_tirosh import *
print tirosh_words.strip()

View file

@ -1,27 +0,0 @@
#!/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/>.
"""
util.py: Test suite for mmgen.util module
"""
from mmgen.util import *
tests = "none",
if (len(sys.argv) == 1):
print "Available tests: %s" % " ".join(tests)

View file

@ -1,27 +0,0 @@
#!/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/>.
"""
walletgen.py: Test suite for mmgen.walletgen module
"""
from mmgen.walletgen import *
tests = "none",
if (len(sys.argv) == 1):
print "Available tests: %s" % " ".join(tests)

View file

@ -424,8 +424,10 @@ def encrypt(infile,outfile="",hash_preset=''):
enc_d = encrypt_data(sha256(nonce+d).digest() + nonce + d, key,
int(ba.hexlify(iv),16))
if outfile == '-': sys.stdout.write(salt+iv+enc_d)
else: write_to_file((outfile or infile+"."+g.mmenc_ext),
salt+iv+enc_d,opts,"encrypted data",True,True)
else:
if not outfile:
outfile = os.path.basename(infile) + "." + g.mmenc_ext
write_to_file(outfile, salt+iv+enc_d, opts,"encrypted data",True,True)
def decrypt(infile,outfile="",hash_preset=''):
d = get_data_from_file(infile,"encrypted data")
@ -439,12 +441,15 @@ def decrypt(infile,outfile="",hash_preset=''):
from hashlib import sha256
if dec_d[:sha256_len] == sha256(dec_d[sha256_len:]).digest():
out = dec_d[sha256_len+nonce_len:]
if outfile == '-': sys.stdout.write(out)
if outfile == '-': sys.stdout.write(out)
else:
import re
of = re.sub(r'\.%s$'%g.mmenc_ext,r'',infile)
if of == infile: of = infile+".dec"
write_to_file((outfile or of),out,opts,"decrypted data",True,True)
if not outfile:
outfile = os.path.basename(infile)
if outfile[-len(g.mmenc_ext)-1:] == "."+g.mmenc_ext:
outfile = outfile[:-len(g.mmenc_ext)-1]
else:
outfile = outfile + ".dec"
write_to_file(outfile, out, opts,"decrypted data",True,True)
else:
msg("Incorrect passphrase or hash preset")

View file

@ -628,13 +628,13 @@ def get_keys_for_mmgen_addrs(mmgen_addrs,infiles,saved_seeds,opts,gen_pairs=Fals
seed = get_seed_for_seed_id(seed_id,infiles,saved_seeds,opts)
addr_ids = [int(i[9:]) for i in mmgen_addrs if i[:8] == seed_id]
from mmgen.addr import generate_keys,generate_addrs
from mmgen.addr import generate_addrs
if gen_pairs:
o = {"gen_what":"addresses"}
ret += [("%s:%s" % (seed_id,i['num']),i['addr'])
for i in generate_addrs(seed, addr_ids, o)]
ret += [("{}:{}".format(seed_id,i.num),i.addr)
for i in generate_addrs(seed, addr_ids, {'gen_what':("addrs")})]
else:
ret += [i['wif'] for i in generate_keys(seed, addr_ids)]
ret += [i.wif for i in generate_addrs(
seed,addr_ids,{'gen_what':("keys")})]
return ret

View file

@ -256,25 +256,36 @@ def make_iv_chksum(s):
return sha256(s).hexdigest()[:8].upper()
def check_infile(f):
def check_file_type_and_access(fname,ftype):
import os, stat
try: mode = os.stat(f).st_mode
typ2,tdesc2,access,action = (stat.S_ISLNK,"symbolic link",os.R_OK,"read")\
if ftype == "input file" else (stat.S_ISBLK,"block device",os.W_OK,"writ")
if ftype == "directory":
typ1,typ2,tdesc = stat.S_ISDIR,stat.S_ISDIR,"directory"
else:
typ1,tdesc = stat.S_ISREG,"regular file or "+tdesc2
try: mode = os.stat(fname).st_mode
except:
msg("Unable to stat requested input file '%s'" % f)
msg("Unable to stat requested %s '%s'" % (ftype,fname))
sys.exit(1)
if not stat.S_ISREG(mode) or stat.S_ISLNK(mode):
msg("Requested input file '%s' is not a file" % f)
if not (typ1(mode) or typ2(mode)):
msg("Requested %s '%s' is not a %s" % (ftype,fname,tdesc))
sys.exit(1)
if not os.access(f, os.R_OK):
msg("Requested input file '%s' is unreadable by you" % f)
if not os.access(fname, access):
msg("Requested %s '%s' is un%sable by you" % (ftype,fname,action))
sys.exit(1)
return True
def check_infile(f): return check_file_type_and_access(f,"input file")
def check_outfile(f): return check_file_type_and_access(f,"output file")
def check_outdir(f): return check_file_type_and_access(f,"directory")
def _validate_addr_num(n):

View file

@ -1,27 +0,0 @@
#!/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/>.
"""
walletgen.py: Routines used for seed generation and wallet creation
"""
import sys
import mmgen.config as g
from mmgen.util import msg, msg_r, qmsg, qmsg_r, get_char, prompt_and_get_char
from binascii import hexlify