|
@@ -1,4 +1,5 @@
|
|
|
#!/usr/bin/env python
|
|
|
+# -*- coding: UTF-8 -*-
|
|
|
#
|
|
|
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
|
|
|
# Copyright (C)2013-2017 Philemon <mmgen-py@yandex.com>
|
|
@@ -31,84 +32,99 @@ pnm = g.proj_name
|
|
|
|
|
|
from collections import OrderedDict
|
|
|
cmd_data = OrderedDict([
|
|
|
- ('help', ['<tool command> [str]']),
|
|
|
- ('usage', ['<tool command> [str]']),
|
|
|
- ('strtob58', ['<string> [str-]','pad [int=0]']),
|
|
|
- ('b58tostr', ['<b58 number> [str-]']),
|
|
|
- ('hextob58', ['<hex number> [str-]','pad [int=0]']),
|
|
|
- ('b58tohex', ['<b58 number> [str-]','pad [int=0]']),
|
|
|
- ('b58randenc', []),
|
|
|
- ('b32tohex', ['<b32 num> [str-]','pad [int=0]']),
|
|
|
- ('hextob32', ['<hex num> [str-]','pad [int=0]']),
|
|
|
- ('randhex', ['nbytes [int=32]']),
|
|
|
- ('id8', ['<infile> [str]']),
|
|
|
- ('id6', ['<infile> [str]']),
|
|
|
- ('sha256x2', ['<str, hexstr or filename> [str]', # TODO handle stdin
|
|
|
+ ('Help', ['<tool command> [str]']),
|
|
|
+ ('Usage', ['<tool command> [str]']),
|
|
|
+ ('Strtob58', ['<string> [str-]','pad [int=0]']),
|
|
|
+ ('B58tostr', ['<b58 number> [str-]']),
|
|
|
+ ('Hextob58', ['<hex number> [str-]','pad [int=0]']),
|
|
|
+ ('B58tohex', ['<b58 number> [str-]','pad [int=0]']),
|
|
|
+ ('B58randenc', []),
|
|
|
+ ('B32tohex', ['<b32 num> [str-]','pad [int=0]']),
|
|
|
+ ('Hextob32', ['<hex num> [str-]','pad [int=0]']),
|
|
|
+ ('Randhex', ['nbytes [int=32]']),
|
|
|
+ ('Id8', ['<infile> [str]']),
|
|
|
+ ('Id6', ['<infile> [str]']),
|
|
|
+ ('Hash160', ['<hexadecimal string> [str-]']),
|
|
|
+ ('Hash256', ['<str, hexstr or filename> [str]', # TODO handle stdin
|
|
|
'hex_input [bool=False]','file_input [bool=False]']),
|
|
|
- ('str2id6', ['<string (spaces are ignored)> [str-]']),
|
|
|
- ('hexdump', ['<infile> [str]', 'cols [int=8]', 'line_nums [bool=True]']),
|
|
|
- ('unhexdump', ['<infile> [str]']),
|
|
|
- ('hexreverse', ['<hexadecimal string> [str-]']),
|
|
|
- ('hexlify', ['<string> [str-]']),
|
|
|
- ('rand2file', ['<outfile> [str]','<nbytes> [str]','threads [int=4]','silent [bool=False]']),
|
|
|
-
|
|
|
- ('randwif', ['compressed [bool=False]']),
|
|
|
- ('randpair', ['compressed [bool=False]']),
|
|
|
- ('hex2wif', ['<private key in hex format> [str-]', 'compressed [bool=False]']),
|
|
|
- ('wif2hex', ['<wif> [str-]', 'compressed [bool=False]']),
|
|
|
- ('wif2addr', ['<wif> [str-]', 'compressed [bool=False]']),
|
|
|
- ('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]']),
|
|
|
-
|
|
|
- ('hex2mn', ['<hexadecimal string> [str-]',"wordlist [str='electrum']"]),
|
|
|
- ('mn2hex', ['<mnemonic> [str-]', "wordlist [str='electrum']"]),
|
|
|
- ('mn_rand128', ["wordlist [str='electrum']"]),
|
|
|
- ('mn_rand192', ["wordlist [str='electrum']"]),
|
|
|
- ('mn_rand256', ["wordlist [str='electrum']"]),
|
|
|
- ('mn_stats', ["wordlist [str='electrum']"]),
|
|
|
- ('mn_printlist', ["wordlist [str='electrum']"]),
|
|
|
-
|
|
|
- ('listaddresses',["addrs [str='']",'minconf [int=1]','showempty [bool=False]','pager [bool=False]','showbtcaddrs [bool=False]']),
|
|
|
- ('getbalance', ['minconf [int=1]']),
|
|
|
- ('txview', ['<{} TX file> [str]'.format(pnm),'pager [bool=False]','terse [bool=False]']),
|
|
|
- ('twview', ["sort [str='age']",'reverse [bool=False]','minconf [int=1]','wide [bool=False]','pager [bool=False]']),
|
|
|
-
|
|
|
- ('add_label', ['<{} address> [str]'.format(pnm),'<label> [str]']),
|
|
|
- ('remove_label', ['<{} address> [str]'.format(pnm)]),
|
|
|
- ('addrfile_chksum', ['<{} addr file> [str]'.format(pnm)]),
|
|
|
- ('keyaddrfile_chksum', ['<{} addr file> [str]'.format(pnm)]),
|
|
|
- ('passwdfile_chksum', ['<{} password file> [str]'.format(pnm)]),
|
|
|
- ('find_incog_data', ['<file or device name> [str]','<Incog ID> [str]','keep_searching [bool=False]']),
|
|
|
-
|
|
|
- ('encrypt', ['<infile> [str]',"outfile [str='']","hash_preset [str='']"]),
|
|
|
- ('decrypt', ['<infile> [str]',"outfile [str='']","hash_preset [str='']"]),
|
|
|
- ('bytespec', ['<bytespec> [str]']),
|
|
|
+ ('Str2id6', ['<string (spaces are ignored)> [str-]']),
|
|
|
+ ('Hexdump', ['<infile> [str]', 'cols [int=8]', 'line_nums [bool=True]']),
|
|
|
+ ('Unhexdump', ['<infile> [str]']),
|
|
|
+ ('Hexreverse', ['<hexadecimal string> [str-]']),
|
|
|
+ ('Hexlify', ['<string> [str-]']),
|
|
|
+ ('Rand2file', ['<outfile> [str]','<nbytes> [str]','threads [int=4]','silent [bool=False]']),
|
|
|
+
|
|
|
+ ('Randwif', ['compressed [bool=False]']),
|
|
|
+ ('Randpair', ['compressed [bool=False]','segwit [bool=False]']),
|
|
|
+ ('Hex2wif', ['<private key in hex format> [str-]','compressed [bool=False]']),
|
|
|
+ ('Wif2hex', ['<wif> [str-]']),
|
|
|
+ ('Wif2addr', ['<wif> [str-]','segwit [bool=False]']),
|
|
|
+ ('Wif2segwit_pair',['<wif> [str-]']),
|
|
|
+ ('Hexaddr2addr', ['<btc address in hex format> [str-]']),
|
|
|
+ ('Addr2hexaddr', ['<btc address> [str-]']),
|
|
|
+ ('Privhex2addr', ['<private key in hex format> [str-]','compressed [bool=False]','segwit [bool=False]']),
|
|
|
+ ('Privhex2pubhex',['<private key in hex format> [str-]','compressed [bool=False]']),
|
|
|
+ ('Pubhex2addr', ['<public key in hex format> [str-]','p2sh [bool=False]']), # new
|
|
|
+ ('Pubhex2redeem_script',['<public key in hex format> [str-]']), # new
|
|
|
+ ('Wif2redeem_script', ['<private key in WIF format> [str-]']), # new
|
|
|
+
|
|
|
+ ('Hex2mn', ['<hexadecimal string> [str-]',"wordlist [str='electrum']"]),
|
|
|
+ ('Mn2hex', ['<mnemonic> [str-]', "wordlist [str='electrum']"]),
|
|
|
+ ('Mn_rand128', ["wordlist [str='electrum']"]),
|
|
|
+ ('Mn_rand192', ["wordlist [str='electrum']"]),
|
|
|
+ ('Mn_rand256', ["wordlist [str='electrum']"]),
|
|
|
+ ('Mn_stats', ["wordlist [str='electrum']"]),
|
|
|
+ ('Mn_printlist', ["wordlist [str='electrum']"]),
|
|
|
+
|
|
|
+ ('Listaddress',['<{} address> [str]'.format(pnm),'minconf [int=1]','pager [bool=False]','showempty [bool=True]''showbtcaddr [bool=True]']),
|
|
|
+ ('Listaddresses',["addrs [str='']",'minconf [int=1]','showempty [bool=False]','pager [bool=False]','showbtcaddrs [bool=False]']),
|
|
|
+ ('Getbalance', ['minconf [int=1]']),
|
|
|
+ ('Txview', ['<{} TX file(s)> [str]'.format(pnm),'pager [bool=False]','terse [bool=False]',"sort [str='mtime'] (options: 'ctime','atime')",'MARGS']),
|
|
|
+ ('Twview', ["sort [str='age']",'reverse [bool=False]','show_days [bool=True]','show_mmid [bool=True]','minconf [int=1]','wide [bool=False]','pager [bool=False]']),
|
|
|
+
|
|
|
+ ('Add_label', ['<{} address> [str]'.format(pnm),'<label> [str]']),
|
|
|
+ ('Remove_label', ['<{} address> [str]'.format(pnm)]),
|
|
|
+ ('Addrfile_chksum', ['<{} addr file> [str]'.format(pnm)]),
|
|
|
+ ('Keyaddrfile_chksum', ['<{} addr file> [str]'.format(pnm)]),
|
|
|
+ ('Passwdfile_chksum', ['<{} password file> [str]'.format(pnm)]),
|
|
|
+ ('Find_incog_data', ['<file or device name> [str]','<Incog ID> [str]','keep_searching [bool=False]']),
|
|
|
+
|
|
|
+ ('Encrypt', ['<infile> [str]',"outfile [str='']","hash_preset [str='']"]),
|
|
|
+ ('Decrypt', ['<infile> [str]',"outfile [str='']","hash_preset [str='']"]),
|
|
|
+ ('Bytespec', ['<bytespec> [str]']),
|
|
|
])
|
|
|
|
|
|
+stdin_msg = """
|
|
|
+To force a command to read from STDIN in place of its first argument (for
|
|
|
+supported commands), use '-' as the first argument.
|
|
|
+""".strip()
|
|
|
+
|
|
|
cmd_help = """
|
|
|
- Bitcoin address/key operations (compressed public keys supported):
|
|
|
- addr2hexaddr - convert Bitcoin address from base58 to hex format
|
|
|
- hex2wif - convert a private key from hex to WIF format
|
|
|
- hexaddr2addr - convert Bitcoin address from hex to base58 format
|
|
|
- privhex2addr - generate Bitcoin address from private key in hex format
|
|
|
- pubkey2addr - convert Bitcoin public key to address
|
|
|
- pubkey2hexaddr - convert Bitcoin public key to address in hex format
|
|
|
- randpair - generate a random private key/address pair
|
|
|
- randwif - generate a random private key in WIF format
|
|
|
- wif2addr - generate a Bitcoin address from a key in WIF format
|
|
|
- wif2hex - convert a private key from WIF to hex format
|
|
|
-
|
|
|
- Wallet/TX operations (bitcoind must be running):
|
|
|
+Bitcoin address/key operations (compressed public keys supported):
|
|
|
+ addr2hexaddr - convert Bitcoin address from base58 to hex format
|
|
|
+ hex2wif - convert a private key from hex to WIF format
|
|
|
+ hexaddr2addr - convert Bitcoin address from hex to base58 format
|
|
|
+ privhex2addr - generate Bitcoin address from private key in hex format
|
|
|
+ privhex2pubhex - generate a hex public key from a hex private key
|
|
|
+ pubhex2addr - convert a hex pubkey to an address
|
|
|
+ pubhex2redeem_script - convert a hex pubkey to a witness redeem script
|
|
|
+ wif2redeem_script - convert a WIF private key to a witness redeem script
|
|
|
+ wif2segwit_pair - generate both a Segwit redeem script and address from WIF
|
|
|
+ pubkey2addr - convert Bitcoin public key to address
|
|
|
+ randpair - generate a random private key/address pair
|
|
|
+ randwif - generate a random private key in WIF format
|
|
|
+ wif2addr - generate a Bitcoin address from a key in WIF format
|
|
|
+ wif2hex - convert a private key from WIF to hex format
|
|
|
+
|
|
|
+Wallet/TX operations (bitcoind must be running):
|
|
|
getbalance - like 'bitcoin-cli getbalance' but shows confirmed/unconfirmed,
|
|
|
spendable/unspendable balances for individual {pnm} wallets
|
|
|
+ listaddress - list the specified {pnm} address and its balance
|
|
|
listaddresses - list {pnm} addresses and their balances
|
|
|
txview - show raw/signed {pnm} transaction in human-readable form
|
|
|
twview - view tracking wallet
|
|
|
|
|
|
- General utilities:
|
|
|
+General utilities:
|
|
|
hexdump - encode data into formatted hexadecimal form (file or stdin)
|
|
|
unhexdump - decode formatted hexadecimal data (file or stdin)
|
|
|
bytespec - convert a byte specifier such as '1GB' into an integer
|
|
@@ -116,7 +132,8 @@ cmd_help = """
|
|
|
hexreverse - reverse bytes of a hexadecimal string
|
|
|
rand2file - write 'n' bytes of random data to specified file
|
|
|
randhex - print 'n' bytes (default 32) of random data in hex format
|
|
|
- sha256x2 - compute a double sha256 hash of data
|
|
|
+ hash256 - compute sha256(sha256(data)) (double sha256)
|
|
|
+ hash160 - compute ripemd160(sha256(data)) (converts hexpubkey to hexaddr)
|
|
|
b58randenc - generate a random 32-byte number and convert it to base 58
|
|
|
b58tostr - convert a base 58 number to a string
|
|
|
strtob58 - convert a string to base 58
|
|
@@ -125,7 +142,7 @@ cmd_help = """
|
|
|
b32tohex - convert a base 32 number to hexadecimal
|
|
|
hextob32 - convert a hexadecimal number to base 32
|
|
|
|
|
|
- File encryption:
|
|
|
+File encryption:
|
|
|
encrypt - encrypt a file
|
|
|
decrypt - decrypt a file
|
|
|
{pnm} encryption suite:
|
|
@@ -133,7 +150,7 @@ cmd_help = """
|
|
|
* Enc: AES256_CTR, 16-byte rand IV, sha256 hash + 32-byte nonce + data
|
|
|
* The encrypted file is indistinguishable from random data
|
|
|
|
|
|
- {pnm}-specific operations:
|
|
|
+{pnm}-specific operations:
|
|
|
add_label - add descriptive label for {pnm} address in tracking wallet
|
|
|
remove_label - remove descriptive label for {pnm} address in tracking wallet
|
|
|
addrfile_chksum - compute checksum for {pnm} address file
|
|
@@ -144,7 +161,7 @@ cmd_help = """
|
|
|
id8 - generate 8-character {pnm} ID for a file (or stdin)
|
|
|
str2id6 - generate 6-character {pnm} ID for a string, ignoring spaces
|
|
|
|
|
|
- Mnemonic operations (choose 'electrum' (default), 'tirosh' or 'all'
|
|
|
+Mnemonic operations (choose 'electrum' (default), 'tirosh' or 'all'
|
|
|
wordlists):
|
|
|
mn_rand128 - generate random 128-bit mnemonic
|
|
|
mn_rand192 - generate random 192-bit mnemonic
|
|
@@ -156,63 +173,97 @@ cmd_help = """
|
|
|
|
|
|
IMPORTANT NOTE: Though {pnm} mnemonics use the Electrum wordlist, they're
|
|
|
computed using a different algorithm and are NOT Electrum-compatible!
|
|
|
-""".format(pnm=pnm)
|
|
|
|
|
|
-def tool_usage(prog_name, command):
|
|
|
- if command in cmd_data:
|
|
|
+ {sm}
|
|
|
+""".format(pnm=pnm,sm='\n '.join(stdin_msg.split('\n')))
|
|
|
+
|
|
|
+def usage(command):
|
|
|
+
|
|
|
+ for v in cmd_data.values():
|
|
|
+ if v and v[0][-2:] == '-]':
|
|
|
+ v[0] = v[0][:-2] + ' or STDIN]'
|
|
|
+ if 'MARGS' in v: v.remove('MARGS')
|
|
|
+
|
|
|
+ if not command:
|
|
|
+ Msg('Usage information for mmgen-tool commands:')
|
|
|
+ for k,v in cmd_data.items():
|
|
|
+ Msg(' {:18} {}'.format(k.lower(),' '.join(v)))
|
|
|
+ Msg('\n '+'\n '.join(stdin_msg.split('\n')))
|
|
|
+ sys.exit(0)
|
|
|
+
|
|
|
+ Command = command.capitalize()
|
|
|
+ if Command in cmd_data:
|
|
|
+ import re
|
|
|
for line in cmd_help.split('\n'):
|
|
|
- if ' ' + command in line:
|
|
|
+ if re.match(r'\s+{}\s+'.format(command),line):
|
|
|
c,h = line.split('-',1)
|
|
|
Msg('MMGEN-TOOL {}: {}'.format(c.strip().upper(),h.strip()))
|
|
|
- cd = cmd_data[command]
|
|
|
- if cd and cd[0][-2:] == '-]':
|
|
|
- cd[0] = cd[0][:-2] + ' or STDIN]'
|
|
|
- msg('USAGE: %s %s %s' % (prog_name, command, ' '.join(cd)))
|
|
|
+ cd = cmd_data[Command]
|
|
|
+ msg('USAGE: %s %s %s' % (g.prog_name, command, ' '.join(cd)))
|
|
|
else:
|
|
|
msg("'%s': no such tool command" % command)
|
|
|
sys.exit(1)
|
|
|
|
|
|
-def process_args(prog_name, command, cmd_args):
|
|
|
+Help = usage
|
|
|
+
|
|
|
+def process_args(command,cmd_args):
|
|
|
+ if 'MARGS' in cmd_data[command]:
|
|
|
+ cmd_data[command].remove('MARGS')
|
|
|
+ margs = True
|
|
|
+ else:
|
|
|
+ margs = False
|
|
|
+
|
|
|
c_args = [[i.split(' [')[0],i.split(' [')[1][:-1]]
|
|
|
for i in cmd_data[command] if '=' not in i]
|
|
|
c_kwargs = dict([[
|
|
|
i.split(' [')[0],
|
|
|
[i.split(' [')[1].split('=')[0], i.split(' [')[1].split('=')[1][:-1]]
|
|
|
] for i in cmd_data[command] if '=' in i])
|
|
|
- u_args = [a for a in cmd_args[:len(c_args)]]
|
|
|
|
|
|
- if c_args and c_args[0][1][-1] == '-':
|
|
|
- c_args[0][1] = c_args[0][1][:-1] # [str-] -> [str]
|
|
|
- # If we're reading from a pipe, make the input the first argument
|
|
|
- if len(u_args) < len(c_kwargs) + len(c_args):
|
|
|
- if not sys.stdin.isatty():
|
|
|
- u_args = [sys.stdin.read()] + u_args
|
|
|
+ if not margs:
|
|
|
+ u_args = [a for a in cmd_args[:len(c_args)]]
|
|
|
+
|
|
|
+ if c_args and c_args[0][1][-1] == '-':
|
|
|
+ c_args[0][1] = c_args[0][1][:-1] # [str-] -> [str]
|
|
|
+ # If we're reading from a pipe, replace '-' with output of previous command
|
|
|
+ if u_args and u_args[0] == '-':
|
|
|
+ if not sys.stdin.isatty():
|
|
|
+ u_args[0] = sys.stdin.read().strip()
|
|
|
+ if not u_args[0]:
|
|
|
+ die(2,'{}: ERROR: no output from previous command in pipe'.format(command.lower()))
|
|
|
|
|
|
- if len(u_args) < len(c_args):
|
|
|
- m1 = 'Command requires exactly %s non-keyword argument%s'
|
|
|
- msg(m1 % (len(c_args),suf(c_args,'k')))
|
|
|
- tool_usage(prog_name,command)
|
|
|
+ if not margs and len(u_args) < len(c_args):
|
|
|
+ m1 = 'Command requires exactly %s non-keyword argument%s'
|
|
|
+ msg(m1 % (len(c_args),suf(c_args,'s')))
|
|
|
+ usage(command)
|
|
|
|
|
|
-# print u_args
|
|
|
extra_args = len(cmd_args) - len(c_args)
|
|
|
u_kwargs = {}
|
|
|
- if extra_args > 0:
|
|
|
+ if margs:
|
|
|
+ t = [a.split('=') for a in cmd_args if '=' in a]
|
|
|
+ tk = [a[0] for a in t]
|
|
|
+ tk_bad = [a for a in tk if a not in c_kwargs]
|
|
|
+ if set(tk_bad) != set(tk[:len(tk_bad)]):
|
|
|
+ die(1,"'{}': illegal keyword argument".format(tk_bad[-1]))
|
|
|
+ u_kwargs = dict(t[len(tk_bad):])
|
|
|
+ u_args = cmd_args[:-len(u_kwargs) or None]
|
|
|
+ elif extra_args > 0:
|
|
|
u_kwargs = dict([a.split('=') for a in cmd_args[len(c_args):] if '=' in a])
|
|
|
if len(u_kwargs) != extra_args:
|
|
|
msg('Command requires exactly %s non-keyword argument%s'
|
|
|
- % (len(c_args),suf(c_args,'k')))
|
|
|
- tool_usage(prog_name,command)
|
|
|
+ % (len(c_args),suf(c_args,'s')))
|
|
|
+ usage(command)
|
|
|
if len(u_kwargs) > len(c_kwargs):
|
|
|
msg('Command requires exactly %s keyword argument%s'
|
|
|
- % (len(c_kwargs),suf(c_kwargs,'k')))
|
|
|
- tool_usage(prog_name,command)
|
|
|
+ % (len(c_kwargs),suf(c_kwargs,'s')))
|
|
|
+ usage(command)
|
|
|
|
|
|
# mdie(c_args,c_kwargs,u_args,u_kwargs)
|
|
|
|
|
|
for k in u_kwargs:
|
|
|
if k not in c_kwargs:
|
|
|
msg("'%s': invalid keyword argument" % k)
|
|
|
- tool_usage(prog_name,command)
|
|
|
+ usage(command)
|
|
|
|
|
|
def conv_type(arg,arg_name,arg_type):
|
|
|
if arg_type == 'str': arg_type = 'unicode'
|
|
@@ -221,17 +272,19 @@ def process_args(prog_name, command, cmd_args):
|
|
|
elif arg.lower() in ('false','no','0','off'): arg = False
|
|
|
else:
|
|
|
msg("'%s': invalid boolean value for keyword argument" % arg)
|
|
|
- tool_usage(prog_name,command)
|
|
|
+ usage(command)
|
|
|
try:
|
|
|
return __builtins__[arg_type](arg)
|
|
|
except:
|
|
|
die(1,"'%s': Invalid argument for argument %s ('%s' required)" % \
|
|
|
(arg, arg_name, arg_type))
|
|
|
|
|
|
- args = [conv_type(u_args[i],c_args[i][0],c_args[i][1]) for i in range(len(c_args))]
|
|
|
+ if margs:
|
|
|
+ args = [conv_type(u_args[i],c_args[0][0],c_args[0][1]) for i in range(len(u_args))]
|
|
|
+ else:
|
|
|
+ args = [conv_type(u_args[i],c_args[i][0],c_args[i][1]) for i in range(len(c_args))]
|
|
|
kwargs = dict([(k,conv_type(u_kwargs[k],k,c_kwargs[k][0])) for k in u_kwargs])
|
|
|
|
|
|
-# mdie(args,kwargs)
|
|
|
return args,kwargs
|
|
|
|
|
|
# Individual cmd_data
|
|
@@ -252,53 +305,86 @@ def print_convert_results(indata,enc,dec,dtype):
|
|
|
if error:
|
|
|
die(3,"Error! Recoded data doesn't match input!")
|
|
|
|
|
|
-def usage(cmd):
|
|
|
- tool_usage(g.prog_name, cmd)
|
|
|
-
|
|
|
-help = usage
|
|
|
-
|
|
|
-def hexdump(infile, cols=8, line_nums=True):
|
|
|
+def Hexdump(infile, cols=8, line_nums=True):
|
|
|
Msg(pretty_hexdump(
|
|
|
get_data_from_file(infile,dash=True,silent=True,binary=True),
|
|
|
cols=cols,line_nums=line_nums))
|
|
|
|
|
|
-def unhexdump(infile):
|
|
|
+def Unhexdump(infile):
|
|
|
if g.platform == 'win':
|
|
|
import msvcrt
|
|
|
msvcrt.setmode(sys.stdout.fileno(),os.O_BINARY)
|
|
|
sys.stdout.write(decode_pretty_hexdump(
|
|
|
get_data_from_file(infile,dash=True,silent=True)))
|
|
|
|
|
|
-def b58randenc():
|
|
|
+def B58randenc():
|
|
|
r = get_random(32)
|
|
|
enc = mmb.b58encode(r)
|
|
|
dec = mmb.b58decode(enc)
|
|
|
print_convert_results(r,enc,dec,'str')
|
|
|
|
|
|
-def randhex(nbytes='32'):
|
|
|
+def Randhex(nbytes='32'):
|
|
|
Msg(ba.hexlify(get_random(int(nbytes))))
|
|
|
|
|
|
-def randwif(compressed=False):
|
|
|
+def Randwif(compressed=False):
|
|
|
r_hex = ba.hexlify(get_random(32))
|
|
|
enc = mmb.hex2wif(r_hex,compressed)
|
|
|
- dec = mmb.wif2hex(enc)
|
|
|
+ dec = wif2hex(enc)
|
|
|
print_convert_results(r_hex,enc,dec,'hex')
|
|
|
|
|
|
-def randpair(compressed=False):
|
|
|
+def Randpair(compressed=False,segwit=False):
|
|
|
+ if segwit: compressed = True
|
|
|
r_hex = ba.hexlify(get_random(32))
|
|
|
wif = mmb.hex2wif(r_hex,compressed)
|
|
|
- addr = mmb.privnum2addr(int(r_hex,16),compressed)
|
|
|
+ addr = mmb.privnum2addr(int(r_hex,16),compressed,segwit=segwit)
|
|
|
Vmsg('Key (hex): %s' % r_hex)
|
|
|
Vmsg_r('Key (WIF): '); Msg(wif)
|
|
|
Vmsg_r('Addr: '); Msg(addr)
|
|
|
|
|
|
-def wif2addr(wif,compressed=False):
|
|
|
- s_enc = mmb.wif2hex(wif)
|
|
|
- if s_enc == False:
|
|
|
- die(1,'Invalid address')
|
|
|
- addr = mmb.privnum2addr(int(s_enc,16),compressed)
|
|
|
+def Wif2addr(wif,segwit=False):
|
|
|
+ compressed = mmb.wif_is_compressed(wif)
|
|
|
+ if segwit and not compressed:
|
|
|
+ die(1,'Segwit address cannot be generated from uncompressed WIF')
|
|
|
+ privhex = wif2hex(wif)
|
|
|
+ addr = mmb.privnum2addr(int(privhex,16),compressed,segwit=segwit)
|
|
|
Vmsg_r('Addr: '); Msg(addr)
|
|
|
|
|
|
+def Wif2segwit_pair(wif):
|
|
|
+ if not mmb.wif_is_compressed(wif):
|
|
|
+ die(1,'Segwit address cannot be generated from uncompressed WIF')
|
|
|
+ privhex = wif2hex(wif)
|
|
|
+ pubhex = mmb.privnum2pubhex(int(privhex,16),compressed=True)
|
|
|
+ rs = mmb.pubhex2redeem_script(pubhex)
|
|
|
+ addr = mmb.hexaddr2addr(mmb.hash160(rs),p2sh=True)
|
|
|
+ addr_chk = mmb.privnum2addr(int(privhex,16),compressed=True,segwit=True)
|
|
|
+ assert addr == addr_chk
|
|
|
+ Msg('{}\n{}'.format(rs,addr))
|
|
|
+
|
|
|
+def Hexaddr2addr(hexaddr): Msg(mmb.hexaddr2addr(hexaddr))
|
|
|
+def Addr2hexaddr(addr): Msg(mmb.verify_addr(addr,return_hex=True))
|
|
|
+def Hash160(pubkeyhex): Msg(mmb.hash160(pubkeyhex))
|
|
|
+def Pubhex2addr(pubkeyhex,p2sh=False): Msg(mmb.hexaddr2addr(mmb.hash160(pubkeyhex),p2sh=p2sh))
|
|
|
+def Wif2hex(wif): Msg(wif2hex(wif))
|
|
|
+def Hex2wif(hexpriv,compressed=False):
|
|
|
+ Msg(mmb.hex2wif(hexpriv,compressed))
|
|
|
+def Privhex2addr(privhex,compressed=False,segwit=False):
|
|
|
+ if segwit and not compressed:
|
|
|
+ die(1,'Segwit address can be generated only from a compressed pubkey')
|
|
|
+ Msg(mmb.privnum2addr(int(privhex,16),compressed,segwit=segwit))
|
|
|
+def Privhex2pubhex(privhex,compressed=False): # new
|
|
|
+ Msg(mmb.privnum2pubhex(int(privhex,16),compressed))
|
|
|
+def Pubhex2redeem_script(pubhex): # new
|
|
|
+ Msg(mmb.pubhex2redeem_script(pubhex))
|
|
|
+def Wif2redeem_script(wif): # new
|
|
|
+ if not mmb.wif_is_compressed(wif):
|
|
|
+ die(1,'Witness redeem script cannot be generated from uncompressed WIF')
|
|
|
+ pubhex = mmb.privnum2pubhex(int(wif2hex(wif),16),compressed=True)
|
|
|
+ Msg(mmb.pubhex2redeem_script(pubhex))
|
|
|
+
|
|
|
+def wif2hex(wif): # wrapper
|
|
|
+ ret = mmb.wif2hex(wif)
|
|
|
+ return ret or die(1,'{}: Invalid WIF'.format(wif))
|
|
|
+
|
|
|
wordlists = 'electrum','tirosh'
|
|
|
dfl_wl_id = 'electrum'
|
|
|
|
|
@@ -311,123 +397,157 @@ def do_random_mn(nbytes,wordlist):
|
|
|
mn = baseconv.fromhex(hexrand,wl_id)
|
|
|
Msg(' '.join(mn))
|
|
|
|
|
|
-def mn_rand128(wordlist=dfl_wl_id): do_random_mn(16,wordlist)
|
|
|
-def mn_rand192(wordlist=dfl_wl_id): do_random_mn(24,wordlist)
|
|
|
-def mn_rand256(wordlist=dfl_wl_id): do_random_mn(32,wordlist)
|
|
|
+def Mn_rand128(wordlist=dfl_wl_id): do_random_mn(16,wordlist)
|
|
|
+def Mn_rand192(wordlist=dfl_wl_id): do_random_mn(24,wordlist)
|
|
|
+def Mn_rand256(wordlist=dfl_wl_id): do_random_mn(32,wordlist)
|
|
|
|
|
|
-def hex2mn(s,wordlist=dfl_wl_id): Msg(' '.join(baseconv.fromhex(s,wordlist)))
|
|
|
-def mn2hex(s,wordlist=dfl_wl_id): Msg(baseconv.tohex(s.split(),wordlist))
|
|
|
+def Hex2mn(s,wordlist=dfl_wl_id): Msg(' '.join(baseconv.fromhex(s,wordlist)))
|
|
|
+def Mn2hex(s,wordlist=dfl_wl_id): Msg(baseconv.tohex(s.split(),wordlist))
|
|
|
|
|
|
-def strtob58(s,pad=None): Msg(''.join(baseconv.fromhex(ba.hexlify(s),'b58',pad)))
|
|
|
-def hextob58(s,pad=None): Msg(''.join(baseconv.fromhex(s,'b58',pad)))
|
|
|
-def hextob32(s,pad=None): Msg(''.join(baseconv.fromhex(s,'b32',pad)))
|
|
|
-def b58tostr(s): Msg(ba.unhexlify(baseconv.tohex(s,'b58')))
|
|
|
-def b58tohex(s,pad=None): Msg(baseconv.tohex(s,'b58',pad))
|
|
|
-def b32tohex(s,pad=None): Msg(baseconv.tohex(s.upper(),'b32',pad))
|
|
|
+def Strtob58(s,pad=None): Msg(''.join(baseconv.fromhex(ba.hexlify(s),'b58',pad)))
|
|
|
+def Hextob58(s,pad=None): Msg(''.join(baseconv.fromhex(s,'b58',pad)))
|
|
|
+def Hextob32(s,pad=None): Msg(''.join(baseconv.fromhex(s,'b32',pad)))
|
|
|
+def B58tostr(s): Msg(ba.unhexlify(baseconv.tohex(s,'b58')))
|
|
|
+def B58tohex(s,pad=None): Msg(baseconv.tohex(s,'b58',pad))
|
|
|
+def B32tohex(s,pad=None): Msg(baseconv.tohex(s.upper(),'b32',pad))
|
|
|
|
|
|
from mmgen.seed import Mnemonic
|
|
|
-def mn_stats(wordlist=dfl_wl_id):
|
|
|
+def Mn_stats(wordlist=dfl_wl_id):
|
|
|
wordlist in baseconv.digits or die(1,"'{}': not a valid wordlist".format(wordlist))
|
|
|
baseconv.check_wordlist(wordlist)
|
|
|
-def mn_printlist(wordlist=dfl_wl_id):
|
|
|
+def Mn_printlist(wordlist=dfl_wl_id):
|
|
|
wordlist in baseconv.digits or die(1,"'{}': not a valid wordlist".format(wordlist))
|
|
|
Msg('\n'.join(baseconv.digits[wordlist]))
|
|
|
|
|
|
-def id8(infile):
|
|
|
+def Id8(infile):
|
|
|
Msg(make_chksum_8(
|
|
|
get_data_from_file(infile,dash=True,silent=True,binary=True)
|
|
|
))
|
|
|
-def id6(infile):
|
|
|
+def Id6(infile):
|
|
|
Msg(make_chksum_6(
|
|
|
get_data_from_file(infile,dash=True,silent=True,binary=True)
|
|
|
))
|
|
|
-def str2id6(s): # retain ignoring of space for backwards compat
|
|
|
+def Str2id6(s): # retain ignoring of space for backwards compat
|
|
|
Msg(make_chksum_6(''.join(s.split())))
|
|
|
|
|
|
-# List MMGen addresses and their balances:
|
|
|
-def listaddresses(addrs='',minconf=1,showempty=False,pager=False,showbtcaddrs=False):
|
|
|
+def Listaddress(addr,minconf=1,pager=False,showempty=True,showbtcaddr=True):
|
|
|
+ return Listaddresses(addrs=addr,minconf=minconf,pager=pager,showempty=showempty,showbtcaddrs=showbtcaddr)
|
|
|
+
|
|
|
+# List MMGen addresses and their balances. TODO: move this code to AddrList
|
|
|
+def Listaddresses(addrs='',minconf=1,showempty=False,pager=False,showbtcaddrs=False):
|
|
|
+
|
|
|
+ c = bitcoin_connection()
|
|
|
+
|
|
|
+ def check_dup_mmid(accts):
|
|
|
+ help_msg = """
|
|
|
+ Your tracking wallet is corrupted or has been altered by a non-{pnm} program.
|
|
|
+
|
|
|
+ You might be able to salvage your wallet by determining which of the offending
|
|
|
+ addresses doesn't belong to {pnm} ID {mid} and then typing:
|
|
|
+
|
|
|
+ bitcoin-cli importaddress <offending address> "" false
|
|
|
+ """
|
|
|
+ m_prev = None
|
|
|
+
|
|
|
+ for m in sorted([l.mmid for l in accts]):
|
|
|
+ if m == m_prev:
|
|
|
+ msg('Duplicate MMGen ID ({}) discovered in tracking wallet!\n'.format(m))
|
|
|
+ bad_accts = MMGenList([l for l in accts if l.mmid == m])
|
|
|
+ msg(' Affected Bitcoin RPC accounts:\n {}\n'.format('\n '.join(bad_accts)))
|
|
|
+ bad_addrs = [a[0] for a in c.getaddressesbyaccount([[a] for a in bad_accts],batch=True)]
|
|
|
+ if len(set(bad_addrs)) != 1:
|
|
|
+ msg(' Offending addresses:\n {}'.format('\n '.join(bad_addrs)))
|
|
|
+ msg(help_msg.format(mid=m,pnm=pnm))
|
|
|
+ die(3,red('Exiting on error'))
|
|
|
+ m_prev = m
|
|
|
|
|
|
- # TODO - move some or all of this code to AddrList
|
|
|
usr_addr_list = []
|
|
|
if addrs:
|
|
|
- sid_s,idxs = split2(addrs,':')
|
|
|
- sid = SeedID(sid=sid_s)
|
|
|
- usr_addr_list = ['{}:{}'.format(sid,a) for a in AddrIdxList(idxs)]
|
|
|
+ a = addrs.rsplit(':',1)
|
|
|
+ if len(a) != 2:
|
|
|
+ m = "'{}': invalid address list argument (must be in form <seed ID>:[<type>:]<idx list>)"
|
|
|
+ die(1,m.format(addrs))
|
|
|
+ usr_addr_list = [MMGenID('{}:{}'.format(a[0],i)) for i in AddrIdxList(a[1])]
|
|
|
|
|
|
- c = bitcoin_connection()
|
|
|
- addrs = {} # reusing variable name!
|
|
|
+ class TwAddrList(dict,MMGenObject): pass
|
|
|
+
|
|
|
+ addrs = TwAddrList() # reusing name!
|
|
|
total = BTCAmt('0')
|
|
|
+
|
|
|
for d in c.listunspent(0):
|
|
|
- mmaddr,comment = split2(d['account'])
|
|
|
- if usr_addr_list and (mmaddr not in usr_addr_list): continue
|
|
|
- if (mmaddr[:4] == 'btc:' or is_mmgen_id(mmaddr)) and d['confirmations'] >= minconf:
|
|
|
- key = mmaddr.replace(':','_')
|
|
|
- if key in addrs:
|
|
|
- if addrs[key][2] != d['address']:
|
|
|
+ if not 'account' in d: continue # skip coinbase outputs with missing account
|
|
|
+ if d['confirmations'] < minconf: continue
|
|
|
+ label = TwLabel(d['account'],on_fail='silent')
|
|
|
+ if label:
|
|
|
+ if usr_addr_list and (label.mmid not in usr_addr_list): continue
|
|
|
+ if label.mmid in addrs:
|
|
|
+ if addrs[label.mmid]['addr'] != d['address']:
|
|
|
die(2,'duplicate BTC address ({}) for this MMGen address! ({})'.format(
|
|
|
- (d['address'], addrs[key][2])))
|
|
|
+ (d['address'], addrs[label.mmid]['addr'])))
|
|
|
else:
|
|
|
- addrs[key] = [BTCAmt('0'),MMGenAddrLabel(comment),BTCAddr(d['address'])]
|
|
|
- addrs[key][0] += d['amount']
|
|
|
+ addrs[label.mmid] = { 'amt':BTCAmt('0'), 'lbl':label, 'addr':BTCAddr(d['address']) }
|
|
|
+ addrs[label.mmid]['amt'] += d['amount']
|
|
|
total += d['amount']
|
|
|
|
|
|
# We use listaccounts only for empty addresses, as it shows false positive balances
|
|
|
if showempty:
|
|
|
- accts = c.listaccounts(0,True) # minconf,watchonly
|
|
|
- save_a = []
|
|
|
- for acct in accts:
|
|
|
- mmaddr,comment = split2(acct)
|
|
|
- if usr_addr_list and (mmaddr not in usr_addr_list): continue
|
|
|
- if mmaddr[:4] == 'btc:' or is_mmgen_id(mmaddr):
|
|
|
- key = mmaddr.replace(':','_')
|
|
|
- if key not in addrs:
|
|
|
- if showbtcaddrs: save_a.append([acct])
|
|
|
- addrs[key] = [BTCAmt('0'),MMGenAddrLabel(comment),'']
|
|
|
-
|
|
|
- for acct,addr in zip(save_a,c.getaddressesbyaccount(save_a,batch=True)):
|
|
|
- if len(addr) != 1:
|
|
|
- die(2,"Account '%s' has more or less than one BTC address!" % addr)
|
|
|
- key = split2(acct[0])[0].replace(':','_')
|
|
|
- addrs[key][2] = BTCAddr(addr[0])
|
|
|
+ # args: minconf,watchonly
|
|
|
+ accts = MMGenList([b for b in [TwLabel(a,on_fail='silent') for a in c.listaccounts(0,True)] if b])
|
|
|
+ check_dup_mmid(accts)
|
|
|
+ acct_addrs = c.getaddressesbyaccount([[a] for a in accts],batch=True)
|
|
|
+ assert len(accts) == len(acct_addrs), 'listaccounts() and getaddressesbyaccount() not of same length'
|
|
|
+ for a in acct_addrs:
|
|
|
+ if len(a) != 1:
|
|
|
+ die(2,"'{}': more than one BTC address in account!".format(a))
|
|
|
+ for label,addr in zip(accts,[b[0] for b in acct_addrs]):
|
|
|
+ if usr_addr_list and (label.mmid not in usr_addr_list): continue
|
|
|
+ if label.mmid not in addrs:
|
|
|
+ addrs[label.mmid] = { 'amt':BTCAmt('0'), 'lbl':label, 'addr':'' }
|
|
|
+ if showbtcaddrs:
|
|
|
+ addrs[label.mmid]['addr'] = BTCAddr(addr)
|
|
|
|
|
|
if not addrs:
|
|
|
- die(0,('No addresses with balances!','No tracked addresses!')[showempty])
|
|
|
+ die(0,('No tracked addresses with balances!','No tracked addresses!')[showempty])
|
|
|
|
|
|
- fs = ('{mid} {lbl} {amt}','{mid} {addr} {lbl} {amt}')[showbtcaddrs]
|
|
|
- max_mmid_len = max([len(k) for k in addrs if k[:4] != 'btc_'] or [10])
|
|
|
- max_lbl_len = max(len(addrs[k][1]) for k in addrs) or 7
|
|
|
- out = [fs.format(
|
|
|
+ out = ([],[green('Chain: {}'.format(g.chain.upper()))])[g.chain in ('testnet','regtest')]
|
|
|
+
|
|
|
+ fs = ('{mid} {cmt} {amt}','{mid} {addr} {cmt} {amt}')[showbtcaddrs]
|
|
|
+ mmaddrs = [k for k in addrs.keys() if k.type == 'mmgen']
|
|
|
+ max_mmid_len = max(len(k) for k in mmaddrs) + 2 if mmaddrs else 10
|
|
|
+ max_cmt_len = max(max(len(addrs[k]['lbl'].comment) for k in addrs),7)
|
|
|
+ out += [fs.format(
|
|
|
mid=MMGenID.fmtc('MMGenID',width=max_mmid_len),
|
|
|
addr=BTCAddr.fmtc('ADDRESS'),
|
|
|
- lbl=MMGenAddrLabel.fmtc('COMMENT',width=max_lbl_len),
|
|
|
+ cmt=TwComment.fmtc('COMMENT',width=max_cmt_len),
|
|
|
amt='BALANCE'
|
|
|
)]
|
|
|
|
|
|
- old_sid = ''
|
|
|
- def s_mmgen(k):
|
|
|
- s = k.split('_')
|
|
|
- a,b = s if len(s) == 2 else (k,'')
|
|
|
- return '{}_{:>0{w}}'.format(a,b,w=AddrIdx.max_digits+9)
|
|
|
- for k in sorted(addrs,key=s_mmgen):
|
|
|
- if old_sid and old_sid != k.split('_')[0]: out.append('')
|
|
|
- old_sid = k.split('_')[0]
|
|
|
- m = 'non-'+g.proj_name if k[:4] == 'btc_' else k.replace('_',':')
|
|
|
+ al_id_save = None
|
|
|
+ for mmid in sorted(addrs,key=lambda j: j.sort_key):
|
|
|
+ if mmid.type == 'mmgen':
|
|
|
+ if al_id_save and al_id_save != mmid.obj.al_id:
|
|
|
+ out.append('')
|
|
|
+ al_id_save = mmid.obj.al_id
|
|
|
+ mmid_disp = mmid
|
|
|
+ else:
|
|
|
+ if al_id_save:
|
|
|
+ out.append('')
|
|
|
+ al_id_save = None
|
|
|
+ mmid_disp = mmid.type
|
|
|
out.append(fs.format(
|
|
|
- mid = MMGenID.fmtc(m,width=max_mmid_len,color=True),
|
|
|
- addr=(addrs[k][2].fmt(color=True) if showbtcaddrs else None),
|
|
|
- lbl=addrs[k][1].fmt(width=max_lbl_len,color=True,nullrepl='-'),
|
|
|
- amt=addrs[k][0].fmt('3.0',color=True)))
|
|
|
+ mid = MMGenID.fmtc(mmid_disp,width=max_mmid_len,color=True),
|
|
|
+ addr=(addrs[mmid]['addr'].fmt(color=True) if showbtcaddrs else None),
|
|
|
+ cmt=addrs[mmid]['lbl'].comment.fmt(width=max_cmt_len,color=True,nullrepl='-'),
|
|
|
+ amt=addrs[mmid]['amt'].fmt('3.0',color=True)))
|
|
|
|
|
|
out.append('\nTOTAL: %s BTC' % total.hl(color=True))
|
|
|
o = '\n'.join(out)
|
|
|
- if pager: do_pager(o)
|
|
|
- else: Msg(o)
|
|
|
-
|
|
|
-def getbalance(minconf=1):
|
|
|
+ return do_pager(o) if pager else Msg(o)
|
|
|
|
|
|
+def Getbalance(minconf=1):
|
|
|
accts = {}
|
|
|
for d in bitcoin_connection().listunspent(0):
|
|
|
- ma = split2(d['account'])[0]
|
|
|
+ ma = split2(d['account'] if 'account' in d else '')[0] # include coinbase outputs if spendable
|
|
|
keys = ['TOTAL']
|
|
|
if d['spendable']: keys += ['SPENDABLE']
|
|
|
if is_mmgen_id(ma): keys += [ma.split(':')[0]]
|
|
@@ -445,77 +565,62 @@ def getbalance(minconf=1):
|
|
|
*[s.ljust(16) for s in ' Unconfirmed',' <%s %s'%(mc,lbl),' >=%s %s'%(mc,lbl)]))
|
|
|
for key in sorted(accts.keys()):
|
|
|
Msg(fs.format(key+':', *[a.fmt(color=True,suf=' BTC') for a in accts[key]]))
|
|
|
-
|
|
|
-def txview(infile,pager=False,terse=False):
|
|
|
- c = bitcoin_connection()
|
|
|
- tx = MMGenTX(infile)
|
|
|
- tx.view(pager,pause=False,terse=terse)
|
|
|
-
|
|
|
-def twview(pager=False,reverse=False,wide=False,minconf=1,sort='age'):
|
|
|
+ if 'SPENDABLE' in accts:
|
|
|
+ Msg(red('Warning: this wallet contains PRIVATE KEYS for the SPENDABLE balance!'))
|
|
|
+
|
|
|
+def Txview(*infiles,**kwargs):
|
|
|
+ from mmgen.filename import MMGenFileList
|
|
|
+ pager = 'pager' in kwargs and kwargs['pager']
|
|
|
+ terse = 'terse' in kwargs and kwargs['terse']
|
|
|
+ sort_key = kwargs['sort'] if 'sort' in kwargs else 'mtime'
|
|
|
+ flist = MMGenFileList(infiles,ftype=MMGenTX)
|
|
|
+ flist.sort_by_age(key=sort_key) # in-place sort
|
|
|
+ from mmgen.term import get_terminal_size
|
|
|
+ sep = u'—'*get_terminal_size()[0]+'\n'
|
|
|
+ out = sep.join([MMGenTX(fn).format_view(terse=terse) for fn in flist.names()])
|
|
|
+ (Msg,do_pager)[pager](out.rstrip())
|
|
|
+
|
|
|
+def Twview(pager=False,reverse=False,wide=False,minconf=1,sort='age',show_days=True,show_mmid=True):
|
|
|
from mmgen.tw import MMGenTrackingWallet
|
|
|
tw = MMGenTrackingWallet(minconf=minconf)
|
|
|
tw.do_sort(sort,reverse=reverse)
|
|
|
+ tw.show_days = show_days
|
|
|
+ tw.show_mmid = show_mmid
|
|
|
out = tw.format_for_printing(color=True) if wide else tw.format_for_display()
|
|
|
- do_pager(out) if pager else sys.stdout.write(out)
|
|
|
+ (Msg_r,do_pager)[pager](out)
|
|
|
|
|
|
-def add_label(mmaddr,label):
|
|
|
+def Add_label(mmaddr,label):
|
|
|
from mmgen.tw import MMGenTrackingWallet
|
|
|
- if MMGenTrackingWallet.add_label(mmaddr,label): # returns on failure
|
|
|
- s = '{pnm} address {a} in tracking wallet'.format(a=mmaddr,pnm=pnm)
|
|
|
- if label: msg("Added label '{}' for {}".format(label,s))
|
|
|
- else: msg('Removed label for {}'.format(s))
|
|
|
- else:
|
|
|
- die(1,'Label could not be %s' % ('removed','added')[bool(label)])
|
|
|
+ MMGenTrackingWallet.add_label(mmaddr,label) # dies on failure
|
|
|
|
|
|
-def remove_label(mmaddr): add_label(mmaddr,'')
|
|
|
+def Remove_label(mmaddr): Add_label(mmaddr,'')
|
|
|
|
|
|
-def addrfile_chksum(infile):
|
|
|
+def Addrfile_chksum(infile):
|
|
|
from mmgen.addr import AddrList
|
|
|
AddrList(infile,chksum_only=True)
|
|
|
|
|
|
-def keyaddrfile_chksum(infile):
|
|
|
+def Keyaddrfile_chksum(infile):
|
|
|
from mmgen.addr import KeyAddrList
|
|
|
KeyAddrList(infile,chksum_only=True)
|
|
|
|
|
|
-def passwdfile_chksum(infile):
|
|
|
+def Passwdfile_chksum(infile):
|
|
|
from mmgen.addr import PasswordList
|
|
|
PasswordList(infile=infile,chksum_only=True)
|
|
|
|
|
|
-def hexreverse(s):
|
|
|
+def Hexreverse(s):
|
|
|
Msg(ba.hexlify(ba.unhexlify(s.strip())[::-1]))
|
|
|
|
|
|
-def hexlify(s):
|
|
|
+def Hexlify(s):
|
|
|
Msg(ba.hexlify(s))
|
|
|
|
|
|
-def sha256x2(s, file_input=False, hex_input=False):
|
|
|
+def Hash256(s, file_input=False, hex_input=False):
|
|
|
from hashlib import sha256
|
|
|
if file_input: b = get_data_from_file(s,binary=True)
|
|
|
elif hex_input: b = decode_pretty_hexdump(s)
|
|
|
else: b = s
|
|
|
Msg(sha256(sha256(b).digest()).hexdigest())
|
|
|
|
|
|
-def hexaddr2addr(hexaddr):
|
|
|
- Msg(mmb.hexaddr2addr(hexaddr))
|
|
|
-
|
|
|
-def addr2hexaddr(addr):
|
|
|
- Msg(mmb.verify_addr(addr,return_hex=True))
|
|
|
-
|
|
|
-def pubkey2hexaddr(pubkeyhex):
|
|
|
- Msg(mmb.pubhex2hexaddr(pubkeyhex))
|
|
|
-
|
|
|
-def pubkey2addr(pubkeyhex):
|
|
|
- Msg(mmb.hexaddr2addr(mmb.pubhex2hexaddr(pubkeyhex)))
|
|
|
-
|
|
|
-def privhex2addr(privkeyhex,compressed=False):
|
|
|
- Msg(mmb.privnum2addr(int(privkeyhex,16),compressed))
|
|
|
-
|
|
|
-def wif2hex(wif,compressed=False):
|
|
|
- Msg(mmb.wif2hex(wif))
|
|
|
-
|
|
|
-def hex2wif(hexpriv,compressed=False):
|
|
|
- Msg(mmb.hex2wif(hexpriv,compressed))
|
|
|
-
|
|
|
-def encrypt(infile,outfile='',hash_preset=''):
|
|
|
+def Encrypt(infile,outfile='',hash_preset=''):
|
|
|
data = get_data_from_file(infile,'data for encryption',binary=True)
|
|
|
enc_d = mmgen_encrypt(data,'user data',hash_preset)
|
|
|
if not outfile:
|
|
@@ -523,7 +628,7 @@ def encrypt(infile,outfile='',hash_preset=''):
|
|
|
|
|
|
write_data_to_file(outfile,enc_d,'encrypted data',binary=True)
|
|
|
|
|
|
-def decrypt(infile,outfile='',hash_preset=''):
|
|
|
+def Decrypt(infile,outfile='',hash_preset=''):
|
|
|
enc_d = get_data_from_file(infile,'encrypted data',binary=True)
|
|
|
while True:
|
|
|
dec_d = mmgen_decrypt(enc_d,'user data',hash_preset)
|
|
@@ -537,7 +642,7 @@ def decrypt(infile,outfile='',hash_preset=''):
|
|
|
|
|
|
write_data_to_file(outfile,dec_d,'decrypted data',binary=True)
|
|
|
|
|
|
-def find_incog_data(filename,iv_id,keep_searching=False):
|
|
|
+def Find_incog_data(filename,iv_id,keep_searching=False):
|
|
|
ivsize,bsize,mod = g.aesctr_iv_len,4096,4096*8
|
|
|
n,carry = 0,' '*ivsize
|
|
|
flgs = os.O_RDONLY|os.O_BINARY if g.platform == 'win' else os.O_RDONLY
|
|
@@ -554,7 +659,7 @@ def find_incog_data(filename,iv_id,keep_searching=False):
|
|
|
if n+i < ivsize: continue
|
|
|
msg('\rIncog data for ID %s found at offset %s' %
|
|
|
(iv_id,n+i-ivsize))
|
|
|
- if not keep_searching: sys.exit()
|
|
|
+ if not keep_searching: sys.exit(0)
|
|
|
carry = d[len(d)-ivsize:]
|
|
|
n += bsize
|
|
|
if not n % mod: msg_r('\rSearched: %s bytes' % n)
|
|
@@ -562,7 +667,7 @@ def find_incog_data(filename,iv_id,keep_searching=False):
|
|
|
msg('')
|
|
|
os.close(f)
|
|
|
|
|
|
-def rand2file(outfile, nbytes, threads=4, silent=False):
|
|
|
+def Rand2file(outfile, nbytes, threads=4, silent=False):
|
|
|
nbytes = parse_nbytes(nbytes)
|
|
|
from Crypto import Random
|
|
|
rh = Random.new()
|
|
@@ -620,4 +725,4 @@ def rand2file(outfile, nbytes, threads=4, silent=False):
|
|
|
q2.join()
|
|
|
f.close()
|
|
|
|
|
|
-def bytespec(s): Msg(str(parse_nbytes(s)))
|
|
|
+def Bytespec(s): Msg(str(parse_nbytes(s)))
|