Browse Source

Bugfixes, new commands for 'mmgen-tool'

philemon 10 years ago
parent
commit
75ab55a2d3
9 changed files with 138 additions and 75 deletions
  1. 1 1
      mmgen-txcreate
  2. 1 1
      mmgen-txsign
  3. 8 2
      mmgen-walletgen
  4. 4 2
      mmgen/Opts.py
  5. 19 11
      mmgen/bitcoin.py
  6. 4 4
      mmgen/config.py
  7. 95 38
      mmgen/tool.py
  8. 3 8
      mmgen/tx.py
  9. 3 8
      mmgen/util.py

+ 1 - 1
mmgen-txcreate

@@ -137,7 +137,7 @@ if not 'info' in opts: do_license_msg(immed=True)
 #write_to_file("bogus_unspent.json", repr(us)); sys.exit()
 #write_to_file("bogus_unspent.json", repr(us)); sys.exit()
 if g.bogus_wallet_data:
 if g.bogus_wallet_data:
 	import mmgen.rpc
 	import mmgen.rpc
-	us = eval(get_data_from_file("bogus_unspent.json"))
+	us = eval(get_data_from_file(g.bogus_wallet_data))
 else:
 else:
 	us = c.listunspent()
 	us = c.listunspent()
 
 

+ 1 - 1
mmgen-txsign

@@ -107,6 +107,7 @@ for tx_file in tx_files:
 	tx_data = get_lines_from_file(tx_file,m)
 	tx_data = get_lines_from_file(tx_file,m)
 
 
 	metadata,tx_hex,inputs_data,b2m_map = parse_tx_data(tx_data,tx_file)
 	metadata,tx_hex,inputs_data,b2m_map = parse_tx_data(tx_data,tx_file)
+	qmsg("Successfully opened transaction file '%s'" % tx_file)
 
 
 	if 'tx_id' in opts:
 	if 'tx_id' in opts:
 		msg(metadata[0])
 		msg(metadata[0])
@@ -135,7 +136,6 @@ for tx_file in tx_files:
 
 
 	if len(tx_files) > 1:
 	if len(tx_files) > 1:
 		msg("\nTransaction %s/%s:" % (tx_files.index(tx_file)+1,len(tx_files)))
 		msg("\nTransaction %s/%s:" % (tx_files.index(tx_file)+1,len(tx_files)))
-	qmsg("Successfully opened transaction file '%s'" % tx_file)
 
 
 	prompt = "View transaction data? (y)es, (N)o, (v)iew in pager"
 	prompt = "View transaction data? (y)es, (N)o, (v)iew in pager"
 	reply = prompt_and_get_char(prompt,"YyNnVv",enter_ok=True)
 	reply = prompt_and_get_char(prompt,"YyNnVv",enter_ok=True)

+ 8 - 2
mmgen-walletgen

@@ -141,6 +141,11 @@ if g.debug: display_user_random_data(usr_keys,key_timings)
 usr_rand_data = sha256(usr_keys).digest() + \
 usr_rand_data = sha256(usr_keys).digest() + \
 				sha256("".join(key_timings)).digest()
 				sha256("".join(key_timings)).digest()
 
 
+if 'from_brain' in opts and not g.quiet:
+	confirm_or_exit(cmessages['brain_warning'].format(
+			g.proj_name, *get_from_brain_opt_params(opts)),
+		"continue")
+
 for i in 'from_mnemonic','from_brain','from_seed','from_incog':
 for i in 'from_mnemonic','from_brain','from_seed','from_incog':
 	if infile or (i in opts):
 	if infile or (i in opts):
 		seed = get_seed_retry(infile,opts)
 		seed = get_seed_retry(infile,opts)
@@ -156,11 +161,12 @@ else:
 salt = os_rand_data[1] + usr_rand_data
 salt = os_rand_data[1] + usr_rand_data
 salt = sha256(salt).digest()[:g.salt_len]
 salt = sha256(salt).digest()[:g.salt_len]
 
 
-qmsg("""Now you must choose a passphrase to encrypt the seed with.  A key will be
+qmsg("""
+Now you must choose a passphrase to encrypt the wallet with.  A key will be
 generated from your passphrase using a hash preset of '%s'.  Please note that
 generated from your passphrase using a hash preset of '%s'.  Please note that
 no strength checking of passphrases is performed.  For an empty passphrase,
 no strength checking of passphrases is performed.  For an empty passphrase,
 just hit ENTER twice.
 just hit ENTER twice.
-""" % opts['hash_preset'])
+""".strip() % opts['hash_preset'])
 
 
 passwd = get_new_passphrase("{} wallet passphrase".format(g.proj_name), opts)
 passwd = get_new_passphrase("{} wallet passphrase".format(g.proj_name), opts)
 
 

+ 4 - 2
mmgen/Opts.py

@@ -94,6 +94,8 @@ def parse_opts(argv,help_data):
 	)
 	)
 	opts,infiles = process_opts(argv,help_data,short_opts,long_opts)
 	opts,infiles = process_opts(argv,help_data,short_opts,long_opts)
 
 
+	if g.debug: print "processed user opts: %s" % opts
+
 	if not check_opts(opts,long_opts): sys.exit(1) # MMGen only!
 	if not check_opts(opts,long_opts): sys.exit(1) # MMGen only!
 
 
 	return opts,infiles
 	return opts,infiles
@@ -121,8 +123,8 @@ def check_opts(opts,long_opts):
 
 
 		# Check for file existence and readability
 		# Check for file existence and readability
 		if opt in ('keys_from_file','addrlist','passwd_file','keysforaddrs'):
 		if opt in ('keys_from_file','addrlist','passwd_file','keysforaddrs'):
-			check_infile(val)
-			return True
+			check_infile(val)  # exits on error
+			continue
 
 
 		if opt == 'outdir':
 		if opt == 'outdir':
 			what = "output directory"
 			what = "output directory"

+ 19 - 11
mmgen/bitcoin.py

@@ -51,17 +51,22 @@ b58a='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
 # The "zero address":
 # The "zero address":
 # 1111111111111111111114oLvT2 (use step2 = ("0" * 40) to generate)
 # 1111111111111111111114oLvT2 (use step2 = ("0" * 40) to generate)
 #
 #
-def pubhex2addr(pubhex):
+def pubhex2hexaddr(pubhex):
 	step1 = sha256(unhexlify(pubhex)).digest()
 	step1 = sha256(unhexlify(pubhex)).digest()
-	step2 = hashlib_new('ripemd160',step1).hexdigest()
+	return hashlib_new('ripemd160',step1).hexdigest()
+
+def hexaddr2addr(hexaddr):
 	# See above:
 	# See above:
-	extra_ones = (len(step2) - len(step2.lstrip("0"))) / 2
-	step3 = sha256(unhexlify('00'+step2)).digest()
-	step4 = sha256(step3).hexdigest()
-	pubkey = int(step2 + step4[:8], 16)
+	extra_ones = (len(hexaddr) - len(hexaddr.lstrip("0"))) / 2
+	step1 = sha256(unhexlify('00'+hexaddr)).digest()
+	step2 = sha256(step1).hexdigest()
+	pubkey = int(hexaddr + step2[:8], 16)
 	return "1" + ("1" * extra_ones) + _numtob58(pubkey)
 	return "1" + ("1" * extra_ones) + _numtob58(pubkey)
 
 
-def verify_addr(addr,verbose=False):
+def pubhex2addr(pubhex):
+	return hexaddr2addr(pubhex2hexaddr(pubhex))
+
+def verify_addr(addr,verbose=False,return_hex=False):
 
 
 	if addr[0] != "1":
 	if addr[0] != "1":
 		if verbose: print "%s: Invalid address" % addr
 		if verbose: print "%s: Invalid address" % addr
@@ -78,7 +83,7 @@ def verify_addr(addr,verbose=False):
 		if verbose: print "Invalid checksum in address %s" % ("1" + addr)
 		if verbose: print "Invalid checksum in address %s" % ("1" + addr)
 		return False
 		return False
 
 
-	return True
+	return addr_hex[:40] if return_hex else True
 
 
 # Reworked code from here:
 # Reworked code from here:
 
 
@@ -172,14 +177,17 @@ def hextowif(hexpriv,compressed=False):
 	key = step1 + step3[:8]
 	key = step1 + step3[:8]
 	return _numtob58(int(key,16))
 	return _numtob58(int(key,16))
 
 
-def privnum2addr(numpriv,compressed=False):
+def privnum2pubhex(numpriv,compressed=False):
 	pko = ecdsa.SigningKey.from_secret_exponent(numpriv,secp256k1)
 	pko = ecdsa.SigningKey.from_secret_exponent(numpriv,secp256k1)
 	pubkey = hexlify(pko.get_verifying_key().to_string())
 	pubkey = hexlify(pko.get_verifying_key().to_string())
 	if compressed:
 	if compressed:
 		p = '03' if pubkey[-1] in "13579bdf" else '02'
 		p = '03' if pubkey[-1] in "13579bdf" else '02'
-		return pubhex2addr(p+pubkey[:64])
+		return p+pubkey[:64]
 	else:
 	else:
-		return pubhex2addr('04'+pubkey)
+		return '04'+pubkey
+
+def privnum2addr(numpriv,compressed=False):
+	return pubhex2addr(privnum2pubhex(numpriv,compressed))
 
 
 # Used only in test suite.  To check validity, recode with numtowif()
 # Used only in test suite.  To check validity, recode with numtowif()
 def wiftonum(wifpriv):
 def wiftonum(wifpriv):

+ 4 - 4
mmgen/config.py

@@ -22,7 +22,7 @@ config.py:  Constants and configuration options for the mmgen suite
 author = "Philemon"
 author = "Philemon"
 email = "<mmgen-py@yandex.com>"
 email = "<mmgen-py@yandex.com>"
 Cdates = '2013-2014'
 Cdates = '2013-2014'
-version = '0.7.4'
+version = '0.7.5'
 
 
 quiet,verbose = False,False
 quiet,verbose = False,False
 min_screen_width = 80
 min_screen_width = 80
@@ -62,9 +62,9 @@ http_timeout = 30
 keyconv_exec = "keyconv"
 keyconv_exec = "keyconv"
 
 
 from os import getenv
 from os import getenv
-debug      = True if getenv("MMGEN_DEBUG") else False
-no_license = True if getenv("MMGEN_NOLICENSE") else False
-bogus_wallet_data = True if getenv("MMGEN_BOGUS_WALLET_DATA") else False
+debug      = getenv("MMGEN_DEBUG")
+no_license = getenv("MMGEN_NOLICENSE")
+bogus_wallet_data = getenv("MMGEN_BOGUS_WALLET_DATA")
 
 
 mins_per_block = 8.5
 mins_per_block = 8.5
 passwd_max_tries = 5
 passwd_max_tries = 5

+ 95 - 38
mmgen/tool.py

@@ -21,31 +21,29 @@ tool.py:  Routines and data for the mmgen-tool utility
 
 
 import sys
 import sys
 import mmgen.bitcoin as bitcoin
 import mmgen.bitcoin as bitcoin
+import binascii as ba
 
 
 from mmgen.util import *
 from mmgen.util import *
 from mmgen.tx import *
 from mmgen.tx import *
 
 
+def Msg(s):    sys.stdout.write(s + "\n")
+def Msg_r(s):  sys.stdout.write(s)
+def Vmsg(s):
+	if g.verbose: sys.stdout.write(s + "\n")
+def Vmsg_r(s):
+	if g.verbose: sys.stdout.write(s)
+
 commands = {
 commands = {
-#	"keyconv_compare":          ['wif [str]'],
-#	"keyconv_compare_randloop": ['iterations [int]'],
-#	"hextob58_pad":             ['hexnum [str]],
-#	"b58tohex_pad":             ['b58num [str]'],
-#	"hextob58_pad_randloop":    ['iterations [int]'],
-#	"test_wiftohex":            ['wif [str]'],
-#	"hextosha256":              ['hexnum [str]'],
-#	"hextowiftopubkey":         ['hexnum [str]'],
-#	"pubhextoaddr":             ['hexnum [str]'],
-#	"hextowif_comp":            ['hexnum [str]'],
-#	"wiftohex_comp":            ['wif [str]'],
-#	"privhextoaddr_comp":       ['hexnum [str]'],
-#	"wiftoaddr_comp":           ['wif [str]'],
 	"strtob58":     ['<string> [str]'],
 	"strtob58":     ['<string> [str]'],
 	"hextob58":     ['<hex number> [str]'],
 	"hextob58":     ['<hex number> [str]'],
 	"b58tohex":     ['<b58 number> [str]'],
 	"b58tohex":     ['<b58 number> [str]'],
 	"b58randenc":   [],
 	"b58randenc":   [],
+	"getrand":      ['bytes [int=32]'],
 	"randwif":      ['compressed [bool=False]'],
 	"randwif":      ['compressed [bool=False]'],
 	"randpair":     ['compressed [bool=False]'],
 	"randpair":     ['compressed [bool=False]'],
+	"wif2hex":      ['<wif> [str]', 'compressed [bool=False]'],
 	"wif2addr":     ['<wif> [str]', 'compressed [bool=False]'],
 	"wif2addr":     ['<wif> [str]', 'compressed [bool=False]'],
+	"hex2wif":      ['<private key in hex format> [str]', 'compressed [bool=False]'],
 	"hexdump":      ['<infile> [str]', 'cols [int=8]', 'line_nums [bool=True]'],
 	"hexdump":      ['<infile> [str]', 'cols [int=8]', 'line_nums [bool=True]'],
 	"unhexdump":    ['<infile> [str]'],
 	"unhexdump":    ['<infile> [str]'],
 	"mn_rand128":   ['wordlist [str="electrum"]'],
 	"mn_rand128":   ['wordlist [str="electrum"]'],
@@ -58,7 +56,16 @@ commands = {
 	"listaddresses": ['minconf [int=1]', 'showempty [bool=False]'],
 	"listaddresses": ['minconf [int=1]', 'showempty [bool=False]'],
 	"getbalance":   ['minconf [int=1]'],
 	"getbalance":   ['minconf [int=1]'],
 	"viewtx":       ['<MMGen tx file> [str]'],
 	"viewtx":       ['<MMGen tx file> [str]'],
-	"check_addrfile":  ['<MMGen addr file> [str]']
+	"check_addrfile":  ['<MMGen addr file> [str]'],
+	"hexreverse":   ['<hexadecimal string> [str]'],
+	"sha256x2":     ['<str, hexstr or filename> [str]',
+					'hex_input [bool=False]','file_input [bool=False]'],
+	"hexlify":      ['<string> [str]'],
+	"hexaddr2addr": ['<btc address in hex format> [str]'],
+	"addr2hexaddr": ['<btc address> [str]'],
+	"pubkey2addr":  ['<public key in hex format> [str]'],
+	"pubkey2hexaddr": ['<public key in hex format> [str]'],
+	"privhex2addr": ['<private key in hex format> [str]','compressed [bool=False]'],
 }
 }
 
 
 command_help = """
 command_help = """
@@ -69,6 +76,7 @@ command_help = """
   MMGen-specific operations
   MMGen-specific operations
   id8          - generate 8-character MMGen ID checksum for file (or stdin)
   id8          - generate 8-character MMGen ID checksum for file (or stdin)
   id6          - generate 6-character MMGen ID checksum for file (or stdin)
   id6          - generate 6-character MMGen ID checksum for file (or stdin)
+  check_addrfile - compute checksum and address list for MMGen address file
 
 
   Bitcoin operations:
   Bitcoin operations:
   strtob58     - convert a string to base 58
   strtob58     - convert a string to base 58
@@ -77,7 +85,20 @@ command_help = """
   b58randenc   - generate a random 32-byte number and convert it to base 58
   b58randenc   - generate a random 32-byte number and convert it to base 58
   randwif      - generate a random private key in WIF format
   randwif      - generate a random private key in WIF format
   randpair     - generate a random private key/address pair
   randpair     - generate a random private key/address pair
+  wif2hex      - convert a private key from WIF to hex format
+  hex2wif      - convert a private key from hex to WIF format
   wif2addr     - generate a Bitcoin address from a key in WIF format
   wif2addr     - generate a Bitcoin address from a key in WIF format
+  pubkey2addr  - convert Bitcoin public key to address
+  pubkey2hexaddr  - convert Bitcoin public key to address in hex format
+  hexaddr2addr - convert Bitcoin address from hex to base58 format
+  addr2hexaddr - convert Bitcoin address from base58 to hex format
+  privhex2addr - generate Bitcoin address from private key in hex format
+
+  Miscellaneous operations:
+  hexreverse   - reverse bytes of a hexadecimal string
+  hexlify      - display string in hexadecimal format
+  sha256x2     - compute a double sha256 hash of data
+  getrand      - print 'n' bytes (default 32) of random data in hex format
 
 
   Mnemonic operations (choose "electrum" (default), "tirosh" or "all"
   Mnemonic operations (choose "electrum" (default), "tirosh" or "all"
   wordlists):
   wordlists):
@@ -92,7 +113,6 @@ command_help = """
   getbalance    - like 'bitcoind getbalance' but shows confirmed/unconfirmed,
   getbalance    - like 'bitcoind getbalance' but shows confirmed/unconfirmed,
                   spendable/unspendable
                   spendable/unspendable
   viewtx        - show raw transaction in human-readable form
   viewtx        - show raw transaction in human-readable form
-  check_addrfile - compute checksum and address list for MMGen address file
 
 
   IMPORTANT NOTE: Though MMGen mnemonics use the Electrum wordlist, they're
   IMPORTANT NOTE: Though MMGen mnemonics use the Electrum wordlist, they're
   computed using a different algorithm and are NOT Electrum-compatible!
   computed using a different algorithm and are NOT Electrum-compatible!
@@ -117,7 +137,6 @@ def process_args(prog_name, command, uargs):
 
 
 	n = len(cargs_req)
 	n = len(cargs_req)
 	if len(uargs_req) != n:
 	if len(uargs_req) != n:
-		print "ERROR: %s argument%s required" % (n, " is" if n==1 else "s are")
 		tool_usage(prog_name, command)
 		tool_usage(prog_name, command)
 		sys.exit(1)
 		sys.exit(1)
 
 
@@ -166,15 +185,16 @@ def process_args(prog_name, command, uargs):
 # Individual commands
 # Individual commands
 
 
 def print_convert_results(indata,enc,dec,no_recode=False):
 def print_convert_results(indata,enc,dec,no_recode=False):
-	vmsg("Input:         [%s]" % indata)
-	vmsg_r("Encoded data:  ["); msg_r(enc); vmsg_r("]"); msg("")
+	Vmsg("Input:         [%s]" % indata)
+	Vmsg_r("Encoded data:  ["); Msg_r(enc); Vmsg_r("]"); Msg("")
 	if not no_recode:
 	if not no_recode:
-		vmsg("Recoded data:  [%s]" % dec)
+		Vmsg("Recoded data:  [%s]" % dec)
 		if indata != dec:
 		if indata != dec:
-			msg("WARNING! Recoded number doesn't match input stringwise!")
+			Msg("WARNING! Recoded number doesn't match input stringwise!")
 
 
 def hexdump(infile, cols=8, line_nums=True):
 def hexdump(infile, cols=8, line_nums=True):
-	print pretty_hexdump(get_data_from_file(infile,dash=True), 2, cols, line_nums)
+	print pretty_hexdump(get_data_from_file(infile,dash=True),
+			cols=cols, line_nums=line_nums)
 
 
 def unhexdump(infile):
 def unhexdump(infile):
 	sys.stdout.write(decode_pretty_hexdump(get_data_from_file(infile,dash=True)))
 	sys.stdout.write(decode_pretty_hexdump(get_data_from_file(infile,dash=True)))
@@ -185,15 +205,15 @@ def strtob58(s):
 	print_convert_results(s,enc,dec)
 	print_convert_results(s,enc,dec)
 
 
 def hextob58(s,f_enc=bitcoin.b58encode, f_dec=bitcoin.b58decode):
 def hextob58(s,f_enc=bitcoin.b58encode, f_dec=bitcoin.b58decode):
-	enc = f_enc(unhexlify(s))
-	dec = hexlify(f_dec(enc))
+	enc = f_enc(ba.unhexlify(s))
+	dec = ba.hexlify(f_dec(enc))
 	print_convert_results(s,enc,dec)
 	print_convert_results(s,enc,dec)
 
 
 def b58tohex(s,f_enc=bitcoin.b58decode, f_dec=bitcoin.b58encode):
 def b58tohex(s,f_enc=bitcoin.b58decode, f_dec=bitcoin.b58encode):
 	tmp = f_enc(s)
 	tmp = f_enc(s)
 	if tmp == False: sys.exit(1)
 	if tmp == False: sys.exit(1)
-	enc = hexlify(tmp)
-	dec = f_dec(unhexlify(enc))
+	enc = ba.hexlify(tmp)
+	dec = f_dec(ba.unhexlify(enc))
 	print_convert_results(s,enc,dec)
 	print_convert_results(s,enc,dec)
 
 
 def get_random(length):
 def get_random(length):
@@ -204,28 +224,31 @@ def b58randenc():
 	r = get_random(32)
 	r = get_random(32)
 	enc = bitcoin.b58encode(r)
 	enc = bitcoin.b58encode(r)
 	dec = bitcoin.b58decode(enc)
 	dec = bitcoin.b58decode(enc)
-	print_convert_results(hexlify(r),enc,hexlify(dec))
+	print_convert_results(ba.hexlify(r),enc,ba.hexlify(dec))
+
+def getrand(bytes='32'):
+	print ba.hexlify(get_random(int(bytes)))
 
 
 def randwif(compressed=False):
 def randwif(compressed=False):
-	r_hex = hexlify(get_random(32))
+	r_hex = ba.hexlify(get_random(32))
 	enc = bitcoin.hextowif(r_hex,compressed)
 	enc = bitcoin.hextowif(r_hex,compressed)
 	print_convert_results(r_hex,enc,"",no_recode=True)
 	print_convert_results(r_hex,enc,"",no_recode=True)
 
 
 def randpair(compressed=False):
 def randpair(compressed=False):
-	r_hex = hexlify(get_random(32))
+	r_hex = ba.hexlify(get_random(32))
 	wif = bitcoin.hextowif(r_hex,compressed)
 	wif = bitcoin.hextowif(r_hex,compressed)
 	addr = bitcoin.privnum2addr(int(r_hex,16),compressed)
 	addr = bitcoin.privnum2addr(int(r_hex,16),compressed)
-	vmsg("Key (hex):  %s" % r_hex)
-	vmsg_r("Key (WIF):  "); msg(wif)
-	vmsg_r("Addr:       "); msg(addr)
+	Vmsg("Key (hex):  %s" % r_hex)
+	Vmsg_r("Key (WIF):  "); Msg(wif)
+	Vmsg_r("Addr:       "); Msg(addr)
 
 
-def wif2addr(s_in,compressed=False):
-	s_enc = bitcoin.wiftohex(s_in,compressed)
+def wif2addr(wif,compressed=False):
+	s_enc = bitcoin.wiftohex(wif,compressed)
 	if s_enc == False:
 	if s_enc == False:
-		msg("Invalid address")
+		Msg("Invalid address")
 		sys.exit(1)
 		sys.exit(1)
 	addr = bitcoin.privnum2addr(int(s_enc,16),compressed)
 	addr = bitcoin.privnum2addr(int(s_enc,16),compressed)
-	vmsg_r("Addr: "); msg(addr)
+	Vmsg_r("Addr: "); Msg(addr)
 
 
 from mmgen.mnemonic import *
 from mmgen.mnemonic import *
 from mmgen.mn_electrum  import electrum_words as el
 from mmgen.mn_electrum  import electrum_words as el
@@ -236,7 +259,7 @@ wordlists = sorted(wl_checksums.keys())
 def get_wordlist(wordlist):
 def get_wordlist(wordlist):
 	wordlist = wordlist.lower()
 	wordlist = wordlist.lower()
 	if wordlist not in wordlists:
 	if wordlist not in wordlists:
-		msg('"%s": invalid wordlist.  Valid choices: %s' %
+		Msg('"%s": invalid wordlist.  Valid choices: %s' %
 			(wordlist,'"'+'" "'.join(wordlists)+'"'))
 			(wordlist,'"'+'" "'.join(wordlists)+'"'))
 		sys.exit(1)
 		sys.exit(1)
 	return el if wordlist == "electrum" else tl
 	return el if wordlist == "electrum" else tl
@@ -246,10 +269,10 @@ def do_random_mn(nbytes,wordlist):
 	wlists = wordlists if wordlist == "all" else [wordlist]
 	wlists = wordlists if wordlist == "all" else [wordlist]
 	for wl in wlists:
 	for wl in wlists:
 		l = get_wordlist(wl)
 		l = get_wordlist(wl)
-		if wl == wlists[0]: vmsg("Seed: %s" % hexlify(r))
+		if wl == wlists[0]: Vmsg("Seed: %s" % ba.hexlify(r))
 		mn = get_mnemonic_from_seed(r,l.strip().split("\n"),
 		mn = get_mnemonic_from_seed(r,l.strip().split("\n"),
 				wordlist,print_info=False)
 				wordlist,print_info=False)
-		vmsg("%s wordlist mnemonic:" % (wl.capitalize()))
+		Vmsg("%s wordlist mnemonic:" % (wl.capitalize()))
 		print " ".join(mn)
 		print " ".join(mn)
 
 
 def mn_rand128(wordlist="electrum"): do_random_mn(16,wordlist)
 def mn_rand128(wordlist="electrum"): do_random_mn(16,wordlist)
@@ -340,3 +363,37 @@ def viewtx(infile):
 	view_tx_data(c,inputs_data,tx_hex,b2m_map,metadata)
 	view_tx_data(c,inputs_data,tx_hex,b2m_map,metadata)
 
 
 def check_addrfile(infile): parse_addrs_file(infile)
 def check_addrfile(infile): parse_addrs_file(infile)
+
+def hexreverse(hex_str):
+	print ba.hexlify(decode_pretty_hexdump(hex_str)[::-1])
+
+def hexlify(s):
+	print ba.hexlify(s)
+
+def sha256x2(s, file_input=False, hex_input=False):
+	from hashlib import sha256
+	if file_input:  b = get_data_from_file(s)
+	elif hex_input: b = decode_pretty_hexdump(s)
+	else:           b = s
+	print sha256(sha256(b).digest()).hexdigest()
+
+def hexaddr2addr(hexaddr):
+	print bitcoin.hexaddr2addr(hexaddr)
+
+def addr2hexaddr(addr):
+	print bitcoin.verify_addr(addr,return_hex=True)
+
+def pubkey2hexaddr(pubkeyhex):
+	print bitcoin.pubhex2hexaddr(pubkeyhex)
+
+def pubkey2addr(pubkeyhex):
+	print bitcoin.pubhex2addr(pubkeyhex)
+
+def privhex2addr(privkeyhex,compressed=False):
+	print bitcoin.privnum2addr(int(privkeyhex,16),compressed)
+
+def wif2hex(wif,compressed=False):
+	print bitcoin.wiftohex(wif,compressed)
+
+def hex2wif(hexpriv,compressed=False):
+	print bitcoin.hextowif(hexpriv,compressed)

+ 3 - 8
mmgen/tx.py

@@ -373,14 +373,8 @@ def view_tx_data(c,inputs_data,tx_hex,b2m_map,metadata=[],pager=False):
 				days = int(j['confirmations'] * g.mins_per_block / (60*24))
 				days = int(j['confirmations'] * g.mins_per_block / (60*24))
 				total_in += j['amount']
 				total_in += j['amount']
 				addr = j['address']
 				addr = j['address']
-
-				if j['account']:
-					tmp = j['account'].split(None,1)
-					mmid,label = tmp if len(tmp) == 2 else (tmp[0],"")
-					label = label or ""
-				else:
-					mmid,label = "",""
-
+				mmid,label = parse_mmgen_label(j['account']) \
+							 if 'account' in j else ("","")
 				mmid_str = ((34-len(addr))*" " + " (%s)" % mmid) if mmid else ""
 				mmid_str = ((34-len(addr))*" " + " (%s)" % mmid) if mmid else ""
 
 
 				for d in (
 				for d in (
@@ -650,6 +644,7 @@ def get_seed_for_seed_id(seed_id,infiles,saved_seeds,opts):
 			or "from_seed" in opts or "from_incog" in opts:
 			or "from_seed" in opts or "from_incog" in opts:
 			msg("Need data for seed ID %s" % seed_id)
 			msg("Need data for seed ID %s" % seed_id)
 			seed = get_seed_retry("",opts)
 			seed = get_seed_retry("",opts)
+			msg("User input produced seed ID %s" % make_chksum_8(seed))
 		else:
 		else:
 			msg("ERROR: No seed source found for seed ID: %s" % seed_id)
 			msg("ERROR: No seed source found for seed ID: %s" % seed_id)
 			sys.exit(2)
 			sys.exit(2)

+ 3 - 8
mmgen/util.py

@@ -279,7 +279,7 @@ def _scrypt_hash_passphrase(passwd, salt, hash_preset, buflen=32):
 	return scrypt.hash(passwd, salt, 2**N, r, p, buflen=buflen)
 	return scrypt.hash(passwd, salt, 2**N, r, p, buflen=buflen)
 
 
 
 
-def _get_from_brain_opt_params(opts):
+def get_from_brain_opt_params(opts):
 	l,p = opts['from_brain'].split(",")
 	l,p = opts['from_brain'].split(",")
 	return(int(l),p)
 	return(int(l),p)
 
 
@@ -287,7 +287,7 @@ def _get_from_brain_opt_params(opts):
 def _get_seed_from_brain_passphrase(words,opts):
 def _get_seed_from_brain_passphrase(words,opts):
 	bp = " ".join(words)
 	bp = " ".join(words)
 	if g.debug: print "Sanitized brain passphrase: %s" % bp
 	if g.debug: print "Sanitized brain passphrase: %s" % bp
-	seed_len,hash_preset = _get_from_brain_opt_params(opts)
+	seed_len,hash_preset = get_from_brain_opt_params(opts)
 	if g.debug: print "Brainwallet l = %s, p = %s" % (seed_len,hash_preset)
 	if g.debug: print "Brainwallet l = %s, p = %s" % (seed_len,hash_preset)
 	vmsg_r("Hashing brainwallet data.  Please wait...")
 	vmsg_r("Hashing brainwallet data.  Please wait...")
 	# Use buflen arg of scrypt.hash() to get seed of desired length
 	# Use buflen arg of scrypt.hash() to get seed of desired length
@@ -905,11 +905,6 @@ def get_seed(infile,opts,silent=False):
 		if 'from_brain' not in opts:
 		if 'from_brain' not in opts:
 			msg("'--from-brain' parameters must be specified for brainwallet file")
 			msg("'--from-brain' parameters must be specified for brainwallet file")
 			sys.exit(2)
 			sys.exit(2)
-		if not g.quiet:
-			confirm_or_exit(
-				cmessages['brain_warning'].format(
-					g.proj_name, *_get_from_brain_opt_params(opts)),
-				"continue")
 		prompt = "Enter brainwallet passphrase: "
 		prompt = "Enter brainwallet passphrase: "
 		words = _get_words(infile,"brainwallet data",prompt,opts)
 		words = _get_words(infile,"brainwallet data",prompt,opts)
 		seed = _get_seed_from_brain_passphrase(words,opts)
 		seed = _get_seed_from_brain_passphrase(words,opts)
@@ -996,7 +991,7 @@ def export_to_hidden_incog(incog_enc,opts):
 			"Data written to file")
 			"Data written to file")
 
 
 
 
-def pretty_hexdump(data,gw,cols,line_nums=False):
+def pretty_hexdump(data,gw=2,cols=8,line_nums=False):
 	r = 1 if len(data) % gw else 0
 	r = 1 if len(data) % gw else 0
 	return "".join(
 	return "".join(
 		[
 		[