From d7fe969d8cb4255c7d3d55f6442ba67d7099869f Mon Sep 17 00:00:00 2001 From: MMGen Date: Tue, 15 Oct 2019 12:51:40 +0000 Subject: [PATCH] passgen: code cleanups, new tests, new --passwd-fmt option --- mmgen/addr.py | 81 ++++++++++--------- mmgen/exception.py | 1 + mmgen/main_passgen.py | 41 +++++----- mmgen/tool.py | 28 ++++--- ...1F3A-фубар@crypto.org-b32-12[1,4,1100].pws | 6 ++ ...1F3A-фубар@crypto.org-b32-24[1,4,1100].pws | 6 ++ ...1F3A-фубар@crypto.org-b58-10[1,4,1100].pws | 6 ++ ...98831F3A-фубар@crypto.org-b58-20[1,4,1100].pws} | 7 +- ...1F3A-фубар@crypto.org-hex-64[1,4,1100].pws | 6 ++ test/test_py_d/ts_ref.py | 58 +++++++++---- test/test_py_d/ts_ref_3seed.py | 19 +++-- 11 files changed, 168 insertions(+), 91 deletions(-) create mode 100644 test/ref/98831F3A-фубар@crypto.org-b32-12[1,4,1100].pws create mode 100644 test/ref/98831F3A-фубар@crypto.org-b32-24[1,4,1100].pws create mode 100644 test/ref/98831F3A-фубар@crypto.org-b58-10[1,4,1100].pws rename test/ref/{98831F3A-фубар@crypto.org-b58-20[1,4,9-11,1100].pws => 98831F3A-фубар@crypto.org-b58-20[1,4,1100].pws} (68%) create mode 100644 test/ref/98831F3A-фубар@crypto.org-hex-64[1,4,1100].pws diff --git a/mmgen/addr.py b/mmgen/addr.py index cbf27fd5..db6e54f7 100755 --- a/mmgen/addr.py +++ b/mmgen/addr.py @@ -350,10 +350,10 @@ class AddrList(MMGenObject): # Address info for a single seed ID # # This file is editable. # Everything following a hash symbol '#' is a comment and ignored by {pnm}. -# A text label of {n} characters or less may be added to the right of each +# A text label of {n} screen cells or less may be added to the right of each # address, and it will be appended to the tracking wallet label upon import. # The label may contain any printable ASCII symbol. -""".strip().format(n=TwComment.max_len,pnm=pnm), +""".strip().format(n=TwComment.max_screen_width,pnm=pnm), 'record_chksum': """ Record this checksum: it will be used to verify the address file in the future """.strip(), @@ -624,33 +624,33 @@ Removed {{}} duplicate WIF key{{}} from keylist (also in {pnm} key-address file out.append('}') self.fmt_data = '\n'.join([l.rstrip() for l in out]) + '\n' + def get_line(self,lines): + ret = lines.pop(0).split(None,2) + if ret[0] == 'orig_hex:': # hacky + ret = lines.pop(0).split(None,2) + return ret if len(ret) == 3 else ret + [''] + def parse_file_body(self,lines): ret = AddrListList() le = self.entry_type - def get_line(): - ret = lines.pop(0).split(None,2) - if ret[0] == 'orig_hex:': # hacky - return lines.pop(0).split(None,2) - return ret - while lines: - d = get_line() + idx,addr,lbl = self.get_line(lines) - assert is_mmgen_idx(d[0]),"'{}': invalid address num. in line: '{}'".format(d[0],' '.join(d)) - assert self.check_format(d[1]),"'{}': invalid {}".format(d[1],self.data_desc) + assert is_mmgen_idx(idx), ( + "'{}': invalid address num. in line: '{}'".format(idx,' '.join([idx,addr,lbl]))) + assert self.check_format(addr),"'{}': invalid {}".format(addr,self.data_desc) - if len(d) != 3: d.append('') - a = le(**{'idx':int(d[0]),self.main_attr:d[1],'label':d[2]}) + a = le(**{ 'idx':int(idx), self.main_attr:addr, 'label':lbl }) if self.has_keys: # order: wif,(orig_hex),viewkey,wallet_passwd - d = get_line() + d = self.get_line(lines) assert d[0] == self.al_id.mmtype.wif_label,"Invalid line in file: '{}'".format(' '.join(d)) a.sec = PrivKey(wif=d[1]) for k,dtype in (('viewkey',ViewKey),('wallet_passwd',WalletPassword)): if k in self.al_id.mmtype.extra_attrs: - d = get_line() + d = self.get_line(lines) assert d[0] == k+':',"Invalid line in file: '{}'".format(' '.join(d)) setattr(a,k,dtype(d[1])) @@ -696,7 +696,7 @@ Removed {{}} duplicate WIF key{{}} from keylist (also in {pnm} key-address file from mmgen.protocol import CoinProtocol base_coin = CoinProtocol(al_coin or 'BTC',testnet=False).base_coin - return base_coin,mmtype + return base_coin,mmtype,tn def check_coin_mismatch(base_coin): # die if addrfile coin doesn't match g.coin m = '{} address file format, but base coin is {}!' @@ -719,16 +719,20 @@ Removed {{}} duplicate WIF key{{}} from keylist (also in {pnm} key-address file self.set_pw_fmt(ss[0]) self.set_pw_len(ss[1]) self.pw_id_str = MMGenPWIDString(ls.pop()) - mmtype = MMGenPasswordType('P') + base_coin,mmtype = None,MMGenPasswordType('P') + testnet = False elif len(ls) == 1: - base_coin,mmtype = parse_addrfile_label(ls[0]) + base_coin,mmtype,testnet = parse_addrfile_label(ls[0]) check_coin_mismatch(base_coin) elif len(ls) == 0: base_coin,mmtype = 'BTC',MMGenAddrType('L') + testnet = False check_coin_mismatch(base_coin) else: raise ValueError("'{}': Invalid first line for {} file '{}'".format(lines[0],self.gen_desc,fn)) + self.base_coin = base_coin + self.is_testnet = testnet self.al_id = AddrListID(SeedID(sid=sid),mmtype) data = self.parse_file_body(lines[1:-1]) @@ -771,6 +775,7 @@ class KeyList(AddrList): ext = 'keys' chksum_rec_f = lambda foo,e: (str(e.idx), e.addr, e.sec.wif) +from collections import namedtuple class PasswordList(AddrList): msgs = { 'file_header': """ @@ -778,10 +783,10 @@ class PasswordList(AddrList): # # This file is editable. # Everything following a hash symbol '#' is a comment and ignored by {pnm}. -# A text label of {n} characters or less may be added to the right of each +# A text label of {n} screen cells or less may be added to the right of each # password. The label may contain any printable ASCII symbol. # -""".strip().format(n=TwComment.max_len,pnm=pnm), +""".strip().format(n=TwComment.max_screen_width,pnm=pnm), 'record_chksum': """ Record this checksum: it will be used to verify the password file in the future """.strip() @@ -798,12 +803,13 @@ Record this checksum: it will be used to verify the password file in the future has_keys = False ext = 'pws' pw_len = None - pw_fmt = None + dfl_pw_fmt = 'b58' + pwinfo = namedtuple('passwd_info',['min_len','max_len','dfl_len','desc','chk_func']) pw_info = { - 'b58': { 'min_len': 8 , 'max_len': 36 ,'dfl_len': 20, 'desc': 'base-58 password' }, - 'b32': { 'min_len': 10 ,'max_len': 42 ,'dfl_len': 24, 'desc': 'base-32 password' }, - 'hex': { 'min_len': 64 ,'max_len': 64 ,'dfl_len': 64, 'desc': 'raw hex password' } - } + 'b32': pwinfo(10, 42 ,24, 'base32 password', is_b32_str), + 'b58': pwinfo(8, 36 ,20, 'base58 password', is_b58_str), + 'hex': pwinfo(64, 64 ,64, 'hexadecimal password', is_hex_str), + } chksum_rec_f = lambda foo,e: (str(e.idx), e.passwd) def __init__( self,infile=None,seed=None, @@ -815,8 +821,9 @@ Record this checksum: it will be used to verify the password file in the future if infile: self.data = self.parse_file(infile) # sets self.pw_id_str,self.pw_fmt,self.pw_len else: - for k in seed,pw_idxs: assert chk_params_only or k - for k in (pw_id_str,pw_fmt): assert k + if not chk_params_only: + for k in (seed,pw_idxs): + assert k self.pw_id_str = MMGenPWIDString(pw_id_str) self.set_pw_fmt(pw_fmt) self.set_pw_len(pw_len) @@ -835,7 +842,9 @@ Record this checksum: it will be used to verify the password file in the future qmsg(self.msgs[('record_chksum','check_chksum')[bool(infile)]]) def set_pw_fmt(self,pw_fmt): - assert pw_fmt in self.pw_info + if pw_fmt not in self.pw_info: + m = '{!r}: invalid password format. Valid formats: {}' + raise InvalidPasswdFormat(m.format(pw_fmt,', '.join(sorted(self.pw_info)))) self.pw_fmt = pw_fmt def chk_pw_len(self,passwd=None): @@ -847,21 +856,21 @@ Record this checksum: it will be used to verify the password file in the future pw_len = len(passwd) fs = '{pw}: {b} has invalid length {l} ({c}{m} characters)' d = self.pw_info[self.pw_fmt] - if pw_len > d['max_len']: - die(2,fs.format(l=pw_len,b=d['desc'],c='>',m=d['max_len'],pw=passwd)) - elif pw_len < d['min_len']: - die(2,fs.format(l=pw_len,b=d['desc'],c='<',m=d['min_len'],pw=passwd)) + if pw_len > d.max_len: + die(2,fs.format(l=pw_len,b=d.desc,c='>',m=d.max_len,pw=passwd)) + elif pw_len < d.min_len: + die(2,fs.format(l=pw_len,b=d.desc,c='<',m=d.min_len,pw=passwd)) def set_pw_len(self,pw_len): assert self.pw_fmt in self.pw_info d = self.pw_info[self.pw_fmt] if pw_len is None: - self.pw_len = d['dfl_len'] + self.pw_len = d.dfl_len return if not is_int(pw_len): - die(2,"'{}': invalid user-requested password length (not an integer)".format(pw_len,d['desc'])) + die(2,"'{}': invalid user-requested password length (not an integer)".format(pw_len,d.desc)) self.pw_len = int(pw_len) self.chk_pw_len() @@ -874,8 +883,8 @@ Record this checksum: it will be used to verify the password file in the future return baseconv.fromhex(hex_sec,self.pw_fmt,pad=self.pw_len,tostr=True)[-self.pw_len:] def check_format(self,pw): - if not {'b58':is_b58_str,'b32':is_b32_str,'hex':is_hex_str}[self.pw_fmt](pw): - msg('Password is not a valid {} string'.format(self.pw_fmt)) + if not self.pw_info[self.pw_fmt].chk_func(pw): + msg('Password is not valid {} data'.format(self.pw_fmt)) return False if len(pw) != self.pw_len: msg('Password has incorrect length ({} != {})'.format(len(pw),self.pw_len)) diff --git a/mmgen/exception.py b/mmgen/exception.py index 41d44302..ed1922b3 100755 --- a/mmgen/exception.py +++ b/mmgen/exception.py @@ -30,6 +30,7 @@ class UserAddressNotInWallet(Exception): mmcode = 1 class MnemonicError(Exception): mmcode = 1 class RangeError(Exception): mmcode = 1 class FileNotFound(Exception): mmcode = 1 +class InvalidPasswdFormat(Exception): mmcode = 1 # 2: yellow hl, message only class InvalidTokenAddress(Exception): mmcode = 2 diff --git a/mmgen/main_passgen.py b/mmgen/main_passgen.py index 25e6d1f4..d95134d9 100755 --- a/mmgen/main_passgen.py +++ b/mmgen/main_passgen.py @@ -27,11 +27,8 @@ from mmgen.addr import PasswordList,AddrIdxList from mmgen.seed import SeedSource from mmgen.obj import MMGenPWIDString -dfl_len = { - 'b58': PasswordList.pw_info['b58']['dfl_len'], - 'b32': PasswordList.pw_info['b32']['dfl_len'], - 'hex': PasswordList.pw_info['hex']['dfl_len'] -} +pwi = PasswordList.pw_info +pwi_fs = '{:5} {:1} {:26} {:<7} {:<7} {}' opts_data = { 'sets': [('print_checksum',True,'quiet',True)], @@ -44,18 +41,17 @@ opts_data = { 'options': """ -h, --help Print this help message --, --longhelp Print help message for long options (common options) --b, --base32 Generate passwords in Base32 format instead of Base58 --x, --hex Generate passwords in raw hex format instead of Base58 -d, --outdir= d Output files to directory 'd' instead of working dir -e, --echo-passphrase Echo passphrase or mnemonic to screen upon entry +-f, --passwd-fmt= f Generate passwords of format 'f'. Default: {dpf}. + See PASSWORD FORMATS below -i, --in-fmt= f Input is from wallet format 'f' (see FMT CODES below) -H, --hidden-incog-input-params=f,o Read hidden incognito data from file 'f' at offset 'o' (comma-separated) -O, --old-incog-fmt Specify old-format incognito input --L, --passwd-len= l Specify length of generated passwords - (default: {d58} chars [base58], {d32} chars [base32], - {dhex} chars [hex]). An argument of 'h' will generate - passwords of half the default length. +-L, --passwd-len= l Specify length of generated passwords. For defaults, + see PASSWORD FORMATS below. An argument of 'h' will + generate passwords of half the default length. -l, --seed-len= l Specify wallet seed length of 'l' bits. This option is required only for brainwallet and incognito inputs with non-standard (< {g.seed_len}-bit) seed lengths @@ -82,15 +78,19 @@ range(s). Changing either the password format (base32,base58) or length alters the seed and thus generates a completely new set of passwords. -EXAMPLE: +PASSWORD FORMATS: - Generate ten base58 passwords of length {d58} for Alice's email account: + {pfi} + +EXAMPLES: + + Generate ten base58 passwords of length {i58.dfl_len} for Alice's email account: {g.prog_name} alice@nowhere.com 1-10 Generate ten base58 passwords of length 16 for Alice's email account: {g.prog_name} -L16 alice@nowhere.com 1-10 - Generate ten base32 passwords of length {d32} for Alice's email account: + Generate ten base32 passwords of length {i32.dfl_len} for Alice's email account: {g.prog_name} -b alice@nowhere.com 1-10 The three sets of passwords are completely unrelated to each other, so @@ -111,15 +111,19 @@ FMT CODES: 'code': { 'options': lambda s: s.format( seed_lens=', '.join(map(str,g.seed_lens)), - g=g,pnm=g.proj_name,d58=dfl_len['b58'],d32=dfl_len['b32'],dhex=dfl_len['hex'], + g=g,pnm=g.proj_name, + dpf=PasswordList.dfl_pw_fmt, kgs=' '.join(['{}:{}'.format(n,k) for n,k in enumerate(g.key_generators,1)]) ), 'notes': lambda s: s.format( - o=opts,g=g,d58=dfl_len['b58'],d32=dfl_len['b32'], + o=opts,g=g,i58=pwi['b58'],i32=pwi['b32'], ml=MMGenPWIDString.max_len, fs="', '".join(MMGenPWIDString.forbidden), n_pw=help_notes('passwd'), n_bw=help_notes('brainwallet'), + pfi='\n '.join( + [pwi_fs.format('Code','','Description','Min Len','Max Len','Default Len')] + + [pwi_fs.format(k,'-',v.desc,v.min_len,v.max_len,v.dfl_len) for k,v in pwi.items()]), n_fmt='\n '.join(SeedSource.format_fmt_codes().splitlines()) ) } @@ -135,9 +139,8 @@ pw_id_str = cmd_args.pop() sf = get_seed_file(cmd_args,1) -pw_fmt = ('b58','b32','hex')[bool(opt.base32)+2*bool(opt.hex)] - -pw_len = (opt.passwd_len,dfl_len[pw_fmt]//2)[opt.passwd_len in ('h','H')] +pw_fmt = opt.passwd_fmt or PasswordList.dfl_pw_fmt +pw_len = pwi[pw_fmt].dfl_len // 2 if opt.passwd_len in ('h','H') else opt.passwd_len PasswordList(pw_id_str=pw_id_str,pw_len=pw_len,pw_fmt=pw_fmt,chk_params_only=True) do_license_msg() diff --git a/mmgen/tool.py b/mmgen/tool.py index c5bffe17..1de0cc94 100755 --- a/mmgen/tool.py +++ b/mmgen/tool.py @@ -530,24 +530,32 @@ class MMGenToolCmdMnemonic(MMGenToolCmdBase): class MMGenToolCmdFile(MMGenToolCmdBase): "utilities for viewing/checking MMGen address and transaction files" - def addrfile_chksum(self,mmgen_addrfile:str): - "compute checksum for MMGen address file" + def _file_chksum(self,mmgen_addrfile,objname): opt.yes = True opt.quiet = True - from mmgen.addr import AddrList - return AddrList(mmgen_addrfile).chksum + from mmgen.addr import AddrList,KeyAddrList,PasswordList + ret = locals()[objname](mmgen_addrfile) + if opt.verbose: + if ret.al_id.mmtype.name == 'password': + fs = 'Passwd fmt: {}\nPasswd len: {}\nID string: {}' + msg(fs.format(capfirst(ret.pw_info[ret.pw_fmt].desc),ret.pw_len,ret.pw_id_str)) + else: + msg('Base coin: {} {}'.format(ret.base_coin,('Mainnet','Testnet')[ret.is_testnet])) + msg('MMType: {}'.format(capfirst(ret.al_id.mmtype.name))) + msg('List length: {}'.format(len(ret.data))) + return ret.chksum + + def addrfile_chksum(self,mmgen_addrfile:str): + "compute checksum for MMGen address file" + return self._file_chksum(mmgen_addrfile,'AddrList') def keyaddrfile_chksum(self,mmgen_keyaddrfile:str): "compute checksum for MMGen key-address file" - opt.yes = True - opt.quiet = True - from mmgen.addr import KeyAddrList - return KeyAddrList(mmgen_keyaddrfile).chksum + return self._file_chksum(mmgen_keyaddrfile,'KeyAddrList') def passwdfile_chksum(self,mmgen_passwdfile:str): "compute checksum for MMGen password file" - from mmgen.addr import PasswordList - return PasswordList(infile=mmgen_passwdfile).chksum + return self._file_chksum(mmgen_passwdfile,'PasswordList') def txview( varargs_call_sig = { # hack to allow for multiple filenames 'args': ( diff --git a/test/ref/98831F3A-фубар@crypto.org-b32-12[1,4,1100].pws b/test/ref/98831F3A-фубар@crypto.org-b32-12[1,4,1100].pws new file mode 100644 index 00000000..7fac2197 --- /dev/null +++ b/test/ref/98831F3A-фубар@crypto.org-b32-12[1,4,1100].pws @@ -0,0 +1,6 @@ +# checksum: 7252 CD8D EF0D 3DB1 +98831F3A фубар@crypto.org b32:12 { + 1 RKJQF2WWSLM4 + 4 TI6GBLACNOY7 + 1100 7DT7HQ4XRX47 +} diff --git a/test/ref/98831F3A-фубар@crypto.org-b32-24[1,4,1100].pws b/test/ref/98831F3A-фубар@crypto.org-b32-24[1,4,1100].pws new file mode 100644 index 00000000..a3515c73 --- /dev/null +++ b/test/ref/98831F3A-фубар@crypto.org-b32-24[1,4,1100].pws @@ -0,0 +1,6 @@ +# checksum: 8D56 3845 A072 A5B9 +98831F3A фубар@crypto.org b32:24 { + 1 HB562PVXOENVQUFW2IEGVNCY + 4 PR2CWXFIFYRDM6GAAGV6DW2G + 1100 MXFSBMRBMSAGFAGMWZRHLUCP +} diff --git a/test/ref/98831F3A-фубар@crypto.org-b58-10[1,4,1100].pws b/test/ref/98831F3A-фубар@crypto.org-b58-10[1,4,1100].pws new file mode 100644 index 00000000..d7942f6d --- /dev/null +++ b/test/ref/98831F3A-фубар@crypto.org-b58-10[1,4,1100].pws @@ -0,0 +1,6 @@ +# checksum: 534F CC1A 6701 9FED +98831F3A фубар@crypto.org b58:10 { + 1 NctypN7ezP + 4 X8yVG6o97A + 1100 31Lu2icDDX +} diff --git a/test/ref/98831F3A-фубар@crypto.org-b58-20[1,4,9-11,1100].pws b/test/ref/98831F3A-фубар@crypto.org-b58-20[1,4,1100].pws similarity index 68% rename from test/ref/98831F3A-фубар@crypto.org-b58-20[1,4,9-11,1100].pws rename to test/ref/98831F3A-фубар@crypto.org-b58-20[1,4,1100].pws index 86769ab2..5e54aeaf 100644 --- a/test/ref/98831F3A-фубар@crypto.org-b58-20[1,4,9-11,1100].pws +++ b/test/ref/98831F3A-фубар@crypto.org-b58-20[1,4,1100].pws @@ -2,16 +2,13 @@ # # This file is editable. # Everything following a hash symbol '#' is a comment and ignored by MMGen. -# A text label of 32 characters or less may be added to the right of each +# A text label of 80 screen cells or less may be added to the right of each # password. The label may contain any printable ASCII symbol. # -# Password data checksum for 98831F3A-фубар@crypto.org-b58-20[1,4,9-11,1100]: A983 DAB9 5514 27FB +# Password data checksum for 98831F3A-фубар@crypto.org-b58-20[1,4,1100]: DDD9 44B0 CA28 183F # Record this value to a secure location. 98831F3A фубар@crypto.org b58:20 { 1 MZ5eTt6xjpK1h6YeFuzJ 4 E5gXkqxwpLPRzCVSHNfv - 9 qaoShe24QgvDXA19Ue5r - 10 kSMEeWLRH29Fthd6pDE7 - 11 5JXuV3oRdG2KQcejAYhE 1100 n3VQMkfGutW49yZDUny1 } diff --git a/test/ref/98831F3A-фубар@crypto.org-hex-64[1,4,1100].pws b/test/ref/98831F3A-фубар@crypto.org-hex-64[1,4,1100].pws new file mode 100644 index 00000000..07cc1ae2 --- /dev/null +++ b/test/ref/98831F3A-фубар@crypto.org-hex-64[1,4,1100].pws @@ -0,0 +1,6 @@ +# checksum: F11D CB0A 8AE3 4D21 +98831F3A фубар@crypto.org hex:64 { + 1 9eeed8f75ae71bd1a2b1a457bcd353da193f31fc67943704189f7b16fe351a52 + 4 9f4b2d455a471dfce7f7e65b5aa527fb16fd150ba58a4c4ed9cb27ab32510a4f + 1100 75a18569e42f22464af109fbe39509e66fa3f0b9c334d4de87f0d4fe515d13df +} diff --git a/test/test_py_d/ts_ref.py b/test/test_py_d/ts_ref.py index 5b5b0baf..c5ef0f37 100755 --- a/test/test_py_d/ts_ref.py +++ b/test/test_py_d/ts_ref.py @@ -41,7 +41,11 @@ class TestSuiteRef(TestSuiteBase,TestSuiteShared): 'ref_segwitaddrfile':'98831F3A{}-S[1,31-33,500-501,1010-1011]{}.addrs', 'ref_bech32addrfile':'98831F3A{}-B[1,31-33,500-501,1010-1011]{}.addrs', 'ref_keyaddrfile': '98831F3A{}[1,31-33,500-501,1010-1011]{}.akeys.mmenc', - 'ref_passwdfile': '98831F3A-фубар@crypto.org-b58-20[1,4,9-11,1100].pws', + 'ref_passwdfile_b32_24': '98831F3A-фубар@crypto.org-b32-24[1,4,1100].pws', + 'ref_passwdfile_b32_12': '98831F3A-фубар@crypto.org-b32-12[1,4,1100].pws', + 'ref_passwdfile_b58_10': '98831F3A-фубар@crypto.org-b58-10[1,4,1100].pws', + 'ref_passwdfile_b58_20': '98831F3A-фубар@crypto.org-b58-20[1,4,1100].pws', + 'ref_passwdfile_hex_64': '98831F3A-фубар@crypto.org-hex-64[1,4,1100].pws', 'ref_tx_file': { # data shared with ref_altcoin, autosign 'btc': ('0B8D5A[15.31789,14,tl=1320969600].rawtx', '0C7115[15.86255,14,tl=1320969600].testnet.rawtx'), @@ -77,7 +81,11 @@ class TestSuiteRef(TestSuiteBase,TestSuiteShared): 'btc': ('9F2D D781 1812 8BAD','88CC 5120 9A91 22C2'), 'ltc': ('B804 978A 8796 3ED4','98B5 AC35 F334 0398'), }, - 'ref_passwdfile_chksum': 'A983 DAB9 5514 27FB', + 'ref_passwdfile_b32_12_chksum': '7252 CD8D EF0D 3DB1', + 'ref_passwdfile_b32_24_chksum': '8D56 3845 A072 A5B9', + 'ref_passwdfile_b58_10_chksum': '534F CC1A 6701 9FED', + 'ref_passwdfile_b58_20_chksum': 'DDD9 44B0 CA28 183F', + 'ref_passwdfile_hex_64_chksum': 'F11D CB0A 8AE3 4D21', } cmd_group = ( # TODO: move to tooltest2 ('ref_words_to_subwallet_chk1','subwallet generation from reference words file (long subseed)'), @@ -90,7 +98,13 @@ class TestSuiteRef(TestSuiteBase,TestSuiteShared): ('ref_segwitaddrfile_chk','saved reference address file (segwit)'), ('ref_bech32addrfile_chk','saved reference address file (bech32)'), ('ref_keyaddrfile_chk','saved reference key-address file'), - ('ref_passwdfile_chk', 'saved reference password file'), + + ('ref_passwdfile_chk_b58_20','saved reference password file (base58, 20 chars)'), + ('ref_passwdfile_chk_b58_10','saved reference password file (base58, 10 chars)'), + ('ref_passwdfile_chk_b32_24','saved reference password file (base32, 24 chars)'), + ('ref_passwdfile_chk_b32_12','saved reference password file (base32, 12 chars)'), + ('ref_passwdfile_chk_hex_64','saved reference password file (hexadecimal, 64 chars)'), + # Create the fake inputs: # ('txcreate8', 'transaction creation (8)'), ('ref_tx_chk', 'signing saved reference tx file'), @@ -161,19 +175,29 @@ class TestSuiteRef(TestSuiteBase,TestSuiteShared): def ref_subwallet_keygen2(self): return self.ref_subwallet_addrgen('1S',target='key') - def ref_addrfile_chk(self,ftype='addr',coin=None,subdir=None,pfx=None,mmtype=None,add_args=[]): - af_key = 'ref_{}file'.format(ftype) + def ref_addrfile_chk( + self, + ftype = 'addr', + coin = None, + subdir = None, + pfx = None, + mmtype = None, + add_args = [], + id_key = None, + pat = 'BTC Mainnet.*Legacy'): + af_key = 'ref_{}file'.format(ftype) + ('_' + id_key if id_key else '') af_fn = TestSuiteRef.sources[af_key].format(pfx or self.altcoin_pfx,'' if coin else self.tn_ext) af = joinpath(ref_dir,(subdir or self.ref_subdir,'')[ftype=='passwd'],af_fn) coin_arg = [] if coin == None else ['--coin='+coin] tool_cmd = ftype.replace('segwit','').replace('bech32','')+'file_chksum' - t = self.spawn('mmgen-tool',coin_arg+['-p1',tool_cmd,af]+add_args) + t = self.spawn('mmgen-tool',coin_arg+['--verbose','-p1',tool_cmd,af]+add_args) if ftype == 'keyaddr': t.do_decrypt_ka_data(hp=ref_kafile_hash_preset,pw=ref_kafile_pass,have_yes_opt=True) - rc = self.chk_data[ 'ref_' + ftype + 'file_chksum' + - ('_'+coin.lower() if coin else '') + - ('_'+mmtype if mmtype else '')] + chksum_key = '_'.join([af_key,'chksum'] + ([coin.lower()] if coin else []) + ([mmtype] if mmtype else [])) + rc = self.chk_data[chksum_key] ref_chksum = rc if (ftype == 'passwd' or coin) else rc[g.proto.base_coin.lower()][g.testnet] + if pat: + t.expect(pat,regex=True) t.expect(chksum_pat,regex=True) m = t.p.match.group(0) t.read() @@ -183,20 +207,24 @@ class TestSuiteRef(TestSuiteBase,TestSuiteShared): def ref_segwitaddrfile_chk(self): if not 'S' in g.proto.mmtypes: return skip('not supported') - else: - return self.ref_addrfile_chk(ftype='segwitaddr') + return self.ref_addrfile_chk(ftype='segwitaddr',pat='BTC Mainnet.*Segwit') def ref_bech32addrfile_chk(self): if not 'B' in g.proto.mmtypes: return skip('not supported') - else: - return self.ref_addrfile_chk(ftype='bech32addr') + return self.ref_addrfile_chk(ftype='bech32addr',pat='BTC Mainnet.*Bech32') def ref_keyaddrfile_chk(self): return self.ref_addrfile_chk(ftype='keyaddr') - def ref_passwdfile_chk(self): - return self.ref_addrfile_chk(ftype='passwd') + def ref_passwdfile_chk(self,key,pat): + return self.ref_addrfile_chk(ftype='passwd',id_key=key,pat=pat) + + def ref_passwdfile_chk_b58_20(self): return self.ref_passwdfile_chk(key='b58_20',pat='Base58.*len.* 20\n') + def ref_passwdfile_chk_b58_10(self): return self.ref_passwdfile_chk(key='b58_10',pat='Base58.*len.* 10\n') + def ref_passwdfile_chk_b32_24(self): return self.ref_passwdfile_chk(key='b32_24',pat='Base32.*len.* 24\n') + def ref_passwdfile_chk_b32_12(self): return self.ref_passwdfile_chk(key='b32_12',pat='Base32.*len.* 12\n') + def ref_passwdfile_chk_hex_64(self): return self.ref_passwdfile_chk(key='hex_64',pat='Hexadec.*len.* 64\n') def ref_tx_chk(self): fn = self.sources['ref_tx_file'][g.coin.lower()][bool(self.tn_ext)] diff --git a/test/test_py_d/ts_ref_3seed.py b/test/test_py_d/ts_ref_3seed.py index 4d720def..d4272b95 100755 --- a/test/test_py_d/ts_ref_3seed.py +++ b/test/test_py_d/ts_ref_3seed.py @@ -73,6 +73,7 @@ class TestSuiteRef3Seed(TestSuiteBase,TestSuiteShared): 'ltc': ('A6AD DF53 5968 7B6A','9572 43E0 A4DC 0B2E'), }, 'refpasswdgen_1': 'EB29 DC4F 924B 289F', + 'refpasswdgen_half_1':'D310 2593 B5D9 2E88', 'ref_b32passwdgen_1': '37B6 C218 2ABC 7508', 'ref_hexpasswdgen_1': '523A F547 0E69 8323', 'refaddrgen_legacy_2': { @@ -108,6 +109,7 @@ class TestSuiteRef3Seed(TestSuiteBase,TestSuiteShared): 'ltc': ('5C12 FDD4 17AB F179','E195 B28C 59C4 C5EC'), }, 'refpasswdgen_2': 'ADEA 0083 094D 489A', + 'refpasswdgen_half_2':'12B3 4929 9506 76E0', 'ref_b32passwdgen_2': '2A28 C5C7 36EC 217A', 'ref_hexpasswdgen_2': 'B11C AC6A 1464 608D', 'refaddrgen_legacy_3': { @@ -143,6 +145,7 @@ class TestSuiteRef3Seed(TestSuiteBase,TestSuiteShared): 'ltc': ('74A0 7DD5 963B 6326','2CDA A007 4B9F E9A5'), }, 'refpasswdgen_3': '2D6D 8FBA 422E 1315', + 'refpasswdgen_half_3':'272C B770 0176 D7EA', 'ref_b32passwdgen_3': 'F6C1 CDFB 97D9 FCAE', 'ref_hexpasswdgen_3': 'BD4F A0AC 8628 4BE4', } @@ -171,9 +174,10 @@ class TestSuiteRef3Seed(TestSuiteBase,TestSuiteShared): ('refkeyaddrgen_compressed', (['mmdat',pwfile],'new refwallet key-addr chksum (compressed)')), ('refkeyaddrgen_segwit', (['mmdat',pwfile],'new refwallet key-addr chksum (segwit)')), ('refkeyaddrgen_bech32', (['mmdat',pwfile],'new refwallet key-addr chksum (bech32)')), - ('refpasswdgen', (['mmdat',pwfile],'new refwallet passwd file chksum')), - ('ref_b32passwdgen',(['mmdat',pwfile],'new refwallet passwd file chksum (base32)')), - ('ref_hexpasswdgen',(['mmdat',pwfile],'new refwallet passwd file chksum (base32)')), + ('refpasswdgen', (['mmdat',pwfile],'new refwallet passwd file chksum')), + ('refpasswdgen_half', (['mmdat',pwfile],'new refwallet passwd file chksum (half-length)')), + ('ref_b32passwdgen', (['mmdat',pwfile],'new refwallet passwd file chksum (base32)')), + ('ref_hexpasswdgen', (['mmdat',pwfile],'new refwallet passwd file chksum (base32)')), ) def __init__(self,trunner,cfgs,spawn): @@ -315,11 +319,14 @@ class TestSuiteRef3Seed(TestSuiteBase,TestSuiteShared): def refpasswdgen(self,wf,pf): return self.addrgen(wf,pf,check_ref=True,ftype='pass',id_str='alice@crypto.org') + def refpasswdgen_half(self,wf,pf): + ea = ['--passwd-len=h'] + return self.addrgen(wf,pf,check_ref=True,ftype='pass',id_str='alice@crypto.org',extra_args=ea) + def ref_b32passwdgen(self,wf,pf): - ea = ['--base32','--passwd-len','17'] + ea = ['--passwd-fmt=b32','--passwd-len=17'] return self.addrgen(wf,pf,check_ref=True,ftype='pass32',id_str='фубар@crypto.org',extra_args=ea) def ref_hexpasswdgen(self,wf,pf): - ea = ['--hex'] + ea = ['--passwd-fmt=hex'] return self.addrgen(wf,pf,check_ref=True,ftype='passhex',id_str='фубар@crypto.org',extra_args=ea) -