various minor fixes and cleanups

This commit is contained in:
The MMGen Project 2019-05-12 09:24:00 +00:00
commit 3a09017804
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
16 changed files with 67 additions and 28 deletions

View file

@ -1,5 +1,6 @@
include README.md SIGNING_KEYS.pub LICENSE INSTALL
include doc/wiki/using-mmgen/*
include test/*.py
include test/test_py_d/*.py
include test/ref/*
@ -10,6 +11,9 @@ include test/ref/dash/*
include test/ref/zcash/*
include test/ref/monero/*
include mmgen/altcoins/eth/rlp/LICENSE
include mmgen/altcoins/eth/pyethereum/LICENSE
include scripts/compute-file-chksum.py
include scripts/create-token.py
include scripts/test-release.sh

View file

@ -375,7 +375,6 @@ Removed {{}} duplicate WIF key{{}} from keylist (also in {pnm} key-address file
gen_keys = False
has_keys = False
ext = 'addrs'
scramble_hash_rounds = 10 # not too many rounds, so hand decoding can still be feasible
chksum_rec_f = lambda foo,e: (str(e.idx), e.addr)
def __init__(self,addrfile='',al_id='',adata=[],seed='',addr_idxs='',src='',
@ -497,7 +496,7 @@ Removed {{}} duplicate WIF key{{}} from keylist (also in {pnm} key-address file
if g.proto.is_testnet():
scramble_key += ':testnet'
dmsg_sc('str',scramble_key)
return scramble_seed(seed,scramble_key.encode(),self.scramble_hash_rounds)
return scramble_seed(seed,scramble_key.encode(),g.scramble_hash_rounds)
def encrypt(self,desc='new key list'):
from mmgen.crypto import mmgen_encrypt
@ -886,7 +885,7 @@ Record this checksum: it will be used to verify the password file in the future
# NB: In original implementation, pw_id_str was 'baseN', not 'bN'
scramble_key = '{}:{}:{}'.format(self.pw_fmt,self.pw_len,self.pw_id_str)
from mmgen.crypto import scramble_seed
return scramble_seed(seed,scramble_key.encode(),self.scramble_hash_rounds)
return scramble_seed(seed,scramble_key.encode(),g.scramble_hash_rounds)
class AddrData(MMGenObject):
msgs = {

View file

@ -41,6 +41,8 @@ def help_notes(k):
'rel_fee_desc': MMGenTX().rel_fee_desc,
'fee_spec_letters': fee_spec_letters(),
'passwd': """
PASSPHRASE NOTE:
For passphrases all combinations of whitespace are equal, and leading and
trailing space are ignored. This permits reading passphrase or brainwallet
data from a multi-line file with free spacing and indentation.

View file

@ -45,8 +45,9 @@ def sha256_rounds(s,n):
def scramble_seed(seed,scramble_key,hash_rounds):
import hmac
scr_seed = hmac.new(seed,scramble_key,sha256).digest()
fs = 'Seed: {}\nScramble key: {}\nScrambled seed: {}'
dmsg(fs.format(seed.hex(),scramble_key.decode(),scr_seed.hex()))
if g.debug:
fs = 'Seed: {!r}\nScramble key: {}\nScrambled seed: {}\n'
msg(fs.format(seed.hex(),scramble_key,scr_seed.hex()))
return sha256_rounds(scr_seed,hash_rounds)
def encrypt_seed(seed,key):

View file

@ -200,6 +200,7 @@ class g(object):
min_urandchars = 10
seed_lens = 128,192,256
scramble_hash_rounds = 10
mmenc_ext = 'mmenc'
salt_len = 16

View file

@ -20,11 +20,11 @@
main.py - Script launcher for the MMGen suite
"""
def launch(what):
def launch(mod):
if what in ('walletgen','walletchk','walletconv','passchg'):
what = 'wallet'
if what == 'keygen': what = 'addrgen'
if mod in ('walletgen','walletchk','walletconv','passchg'):
mod = 'wallet'
if mod == 'keygen': mod = 'addrgen'
import sys,os
from mmgen.globalvars import g
@ -36,7 +36,7 @@ def launch(what):
atexit.register(lambda: termios.tcsetattr(fd,termios.TCSADRAIN,old))
try:
__import__('mmgen.main_' + what)
__import__('mmgen.main_' + mod)
except KeyboardInterrupt:
sys.stderr.write('\nUser interrupt\n')
except EOFError:

View file

@ -30,8 +30,14 @@ usage = '[opts] [infile]'
nargs = 1
iaction = 'convert'
oaction = 'convert'
invoked_as = 'passchg' if g.prog_name == 'mmgen-passchg' else g.prog_name.partition('-wallet')[2]
bw_note = True
do_bw_note = True
invoked_as = {
'mmgen-walletgen': 'gen',
'mmgen-walletconv': 'conv',
'mmgen-walletchk': 'chk',
'mmgen-passchg': 'passchg',
}[g.prog_name]
# full: defhHiJkKlLmoOpPqrSvz-
if invoked_as == 'gen':
@ -51,9 +57,7 @@ elif invoked_as == 'passchg':
desc = 'Change the passphrase, hash preset or label of an {pnm} wallet'
opt_filter = 'efhdiHkKOlLmpPqrSvz-'
iaction = 'input'
bw_note = False
else:
die(1,"'{}': unrecognized invocation".format(g.prog_name))
do_bw_note = False
opts_data = {
'text': {
@ -108,7 +112,7 @@ FMT CODES:
'notes': lambda s: s.format(
f='\n '.join(SeedSource.format_fmt_codes().splitlines()),
n_pw=help_notes('passwd'),
n_bw=('','\n\n' + help_notes('brainwallet'))[bw_note]
n_bw=('','\n\n'+help_notes('brainwallet'))[do_bw_note]
)
}
}
@ -128,6 +132,7 @@ if invoked_as in ('conv','passchg'):
msg(m1+m2)
ss_in = None if invoked_as == 'gen' else SeedSource(sf,passchg=(invoked_as=='passchg'))
if invoked_as == 'chk':
lbl = ss_in.ssdata.label.hl() if hasattr(ss_in.ssdata,'label') else 'NONE'
vmsg('Wallet label: {}'.format(lbl))

View file

@ -118,7 +118,8 @@ class InitErrors(object):
@staticmethod
def arg_chk(cls,on_fail):
assert on_fail in ('die','return','silent','raise'),'arg_chk in class {}'.format(cls.__name__)
assert on_fail in ('die','return','silent','raise'),(
"'{}': invalid value for 'on_fail' in class {}".format(on_fail,cls.__name__) )
@staticmethod
def init_fail(m,on_fail):

View file

@ -331,6 +331,7 @@ def init(opts_data,add_opts=[],opt_filter=None,parse_only=False):
if hasattr(g,'cfg_options_changed'):
ymsg("Warning: config file options have changed! See '{}' for details".format(g.cfg_file+'.sample'))
from mmgen.util import my_raw_input
my_raw_input('Hit ENTER to continue: ')
if g.debug and g.prog_name != 'test.py':

View file

@ -94,6 +94,8 @@ def _usage(cmd=None,exit_val=1):
Msg('')
Msg(m2)
elif cmd in MMGenToolCmd._user_commands():
docstr = getattr(MMGenToolCmd,cmd).__doc__.strip()
msg('{}\n'.format(capfirst(docstr)))
msg('USAGE: {} {} {}'.format(g.prog_name,cmd,_create_call_sig(cmd)))
else:
die(1,"'{}': no such tool command".format(cmd))
@ -678,8 +680,8 @@ class MMGenToolCmdWallet(MMGenToolCmdBase):
def gen_addr(self,mmgen_addr:str,wallet='',target='addr'):
"generate a single MMGen address from default or specified wallet"
addr = MMGenID(mmgen_addr)
sf = get_seed_file([wallet] if wallet else [],1)
opt.quiet = True
sf = get_seed_file([wallet] if wallet else [],1)
from mmgen.seed import SeedSource
ss = SeedSource(sf)
if ss.seed.sid != addr.sid:
@ -885,8 +887,9 @@ class MMGenToolCmdMonero(MMGenToolCmdBase):
while True:
ret = p.expect([r' / .*',r'\[wallet.*:.*'])
if ret == 0: # TODO: coverage
height = p.after
msg_r('\r Block {}{}'.format(p.before.split()[-1],height))
cur_block = p.before.decode().split()[-1]
height = p.after.decode()
msg_r('\r Block {}{}'.format(cur_block,height))
elif ret == 1:
if height:
height = height.split()[-1]

View file

@ -41,8 +41,12 @@ if g.platform == 'win':
def msg(s): msg_r(s + '\n')
def Msg(s): Msg_r(s + '\n')
else:
def msg_r(s): g.stderr.write(s)
def Msg_r(s): g.stdout.write(s)
def msg_r(s):
g.stderr.write(s)
g.stderr.flush()
def Msg_r(s):
g.stdout.write(s)
g.stdout.flush()
def msg(s): g.stderr.write(s + '\n')
def Msg(s): g.stdout.write(s + '\n')

View file

@ -117,12 +117,10 @@ setup(
'mmgen.altcoins.eth.tx',
'mmgen.altcoins.eth.tw',
'mmgen/altcoins/eth/pyethereum/LICENSE',
'mmgen.altcoins.eth.pyethereum.__init__',
'mmgen.altcoins.eth.pyethereum.transactions',
'mmgen.altcoins.eth.pyethereum.utils',
'mmgen/altcoins/eth/rlp/LICENSE',
'mmgen/altcoins/eth/rlp/__init__',
'mmgen/altcoins/eth/rlp/atomic',
'mmgen/altcoins/eth/rlp/codec',

View file

@ -67,6 +67,8 @@ def run_test(test,arg,input_data):
del arg['ret']
del arg_copy['ret']
kwargs.update(arg)
elif type(arg) == tuple:
args = arg
else:
args = [arg]
try:

View file

@ -199,7 +199,6 @@ class TestSuiteMain(TestSuiteBase,TestSuiteShared):
t.expect('move it to the data directory? (Y/n): ','y')
self.have_dfl_wallet = True
t.written_to_file('MMGen wallet')
t.req_exit_val = 0
return t
def passchg(self,wf,pf,label_action='cmdline'):

View file

@ -40,6 +40,15 @@ from mmgen.seed import is_mnemonic
def is_str(s): return type(s) == str
def md5_hash(s):
from hashlib import md5
return md5(s.encode()).hexdigest()
def md5_hash_strip(s):
import re
s = re.sub('\x1b\[[;0-9]+?m','',s) # strip ANSI color sequences
return md5_hash(s.strip())
opts_data = {
'text': {
'desc': "Simple test suite for the 'mmgen-tool' utility",
@ -592,7 +601,12 @@ def run_test(gid,cmd_name):
cmd_err = p.stderr.read()
if cmd_err: vmsg(cmd_err.strip().decode())
if p.wait() != 0:
die(1,'Spawned program exited with error')
import re
m = re.match(b"tool command returned '(None|False)'\n",cmd_err)
if m:
return { b'None': None, b'False': False }[m.group(1)]
else:
ydie(1,'Spawned program exited with error: {}'.format(cmd_err))
return cmd_out
@ -655,7 +669,11 @@ def run_test(gid,cmd_name):
elif out is not None:
assert cmd_out == out,"Output ({!r}) doesn't match expected output ({!r})".format(cmd_out,out)
if type(out) in (list,tuple):
if type(out) == tuple and type(out[0]).__name__ == 'function':
func_out = out[0](cmd_out)
assert func_out == out[1],(
"{}({}) == {} failed!\nOutput: {}".format(out[0].__name__,cmd_out,out[1],func_out))
elif type(out) in (list,tuple):
for co,o in zip(cmd_out.split('\n') if opt.fork else cmd_out,out):
check_output(co,o)
else:

View file

@ -117,7 +117,8 @@ class UnitTests(object):
extra_desc,
'' if opt.quiet else '\n'))
else:
Msg('Testing transactions from {!r}'.format(fn))
Msg_r('Testing transactions from {!r}'.format(fn))
if not opt.quiet: Msg('')
def test_core_vectors():
self._get_core_repo_root()