#!/usr/bin/env python3 """ test.modtest_d.ut_xmrseed: Monero mnemonic unit test for the MMGen suite """ altcoin_dep = True from mmgen.util import ymsg from mmgen.xmrseed import xmrseed from ..include.common import cfg, vmsg class unit_tests: vectors = ( # private keys are reduced ( '148d78d2aba7dbca5cd8f6abcfb0b3c009ffbdbea1ff373d50ed94d78286640e', # Monero repo 'velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches ' + 'lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted', ), ( 'e8164dda6d42bd1e261a3406b2038dcbddadbeefdeadbeefdeadbeefdeadbe0f', 'viewpoint donuts ardent template unveil agile meant unafraid urgent athlete rustled mime azure ' + 'jaded hawk baby jagged haystack baby jagged haystack ramped oncoming point template' ), ( '6900dea9753f5c7ced87b53bdcfb109a8417bca6a2797a708194157b227fb60b', 'criminal bamboo scamper gnaw limits womanly wrong tuition birth mundane donuts square cohesive ' + 'dolphin titans narrate fuel saved wrap aloof magically mirror together update wrap' ), ( '0000000000000000000000000000000000000000000000000000000000000001', 'abbey abbey abbey abbey abbey abbey abbey abbey abbey abbey abbey abbey abbey abbey abbey abbey ' + 'abbey abbey abbey abbey abbey bamboo jaws jerseys abbey' ), ( '1c95988d7431ecd670cf7d73f45befc6feffffffffffffffffffffffffffff0f', 'powder directed sayings enmity bacon vapidly entrance bumper noodles iguana sleepless nasty flying ' + 'soil software foamy solved soggy foamy solved soggy jury yawning ankle solved' ), ( '2c94988d7431ecd670cf7d73f45befc6feffffffffffffffffffffffffffff0f', 'memoir apart olive enmity bacon vapidly entrance bumper noodles iguana sleepless nasty flying soil ' + 'software foamy solved soggy foamy solved soggy jury yawning ankle foamy' ), ( '4bb0288c9673b69fa68c2174851884abbaaedce6af48a03bbfd25e8cd0364102', 'rated bicycle pheasants dejected pouch fizzle shipped rash citadel queen avatar sample muzzle mews ' + 'jagged origin yeti dunes obtains godfather unbending pastry vortex washing citadel' ), ( '4bb0288c9673b69fa68c2174851884abbaaedce6af48a03bbfd25e8cd0364100', 'rated bicycle pheasants dejected pouch fizzle shipped rash citadel queen avatar sample muzzle mews ' + 'jagged origin yeti dunes obtains godfather unbending kangaroo auctions audio citadel' ), ( '1d95988d7431ecd670cf7d73f45befc6feffffffffffffffffffffffffffff0e', 'pram distance scamper enmity bacon vapidly entrance bumper noodles iguana sleepless nasty flying ' + 'soil software foamy solved soggy foamy solved soggy hashing mullet onboard solved' ), ( 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0f', 'foamy solved soggy foamy solved soggy foamy solved soggy foamy solved soggy foamy solved soggy ' + 'foamy solved soggy foamy solved soggy jury yawning ankle soggy' ), ) @property def _use_monero_python(self): if not hasattr(self, '_use_monero_python_'): try: from monero.wordlists.english import English self.wl = English() except ImportError: self._use_monero_python_ = False ymsg('Warning: unable to import monero-python, skipping external library checks') else: self._use_monero_python_ = True return self._use_monero_python_ def wordlist(self, name, ut, desc='Monero wordlist'): xmrseed().check_wordlist(cfg) return True def fromhex(self, name, ut, desc='fromhex() method'): b = xmrseed() vmsg('Checking seed to mnemonic conversion:') for privhex, chk in self.vectors: vmsg(f' {chk}') chk = tuple(chk.split()) res = b.fromhex(privhex) if self._use_monero_python: mp_chk = tuple(self.wl.encode(privhex).split()) assert res == mp_chk, f'check failed:\nres: {res}\nchk: {chk}' assert res == chk, f'check failed:\nres: {res}\nchk: {chk}' return True def tohex(self, name, ut, desc='tohex() method'): b = xmrseed() vmsg('Checking mnemonic to seed conversion:') for chk, words in self.vectors: vmsg(f' {chk}') res = b.tohex(words.split()) if self._use_monero_python: mp_chk = self.wl.decode(words) assert res == mp_chk, f'check failed:\nres: {res}\nchk: {mp_chk}' assert res == chk, f'check failed:\nres: {res}\nchk: {chk}' return True def errors(self, name, ut, desc='error handling'): bad_chksum_mn = ('abbey ' * 21 + 'bamboo jaws jerseys donuts').split() bad_word_mn = "admire zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo".split() bad_seed = 'deadbeef' good_mn = self.vectors[0][1].split() good_hex = self.vectors[0][0] bad_len_mn = good_mn[:22] b = xmrseed() th = b.tohex fh = b.fromhex hse = 'HexadecimalStringError' sle = 'SeedLengthError' ase = 'AssertionError' mne = 'MnemonicError' ut.process_bad_data(( ('hex', hse, 'not a hexadecimal', lambda: fh('xx')), ('seed len', sle, 'invalid seed byte len', lambda: fh(bad_seed)), ('mnemonic type', ase, 'must be list', lambda: th('string')), ('pad arg (fromhex)', ase, "invalid 'pad' arg", lambda: fh(good_hex, pad=23)), ('pad arg (tohex)', ase, "invalid 'pad' arg", lambda: th(good_mn, pad=23)), ('word', mne, "not in Monero", lambda: th(bad_word_mn)), ('checksum', mne, "checksum", lambda: th(bad_chksum_mn)), ('seed phrase len', mne, "phrase len", lambda: th(bad_len_mn)), )) return True