Browse Source

baseconv.py: convert class methods to instance methods

The MMGen Project 3 years ago
parent
commit
7b890a2c95

+ 3 - 3
mmgen/addrgen.py

@@ -97,10 +97,10 @@ class addr_generator:
 
 
 		def b58enc(self,addr_bytes):
 		def b58enc(self,addr_bytes):
 			from .baseconv import baseconv
 			from .baseconv import baseconv
-			enc = baseconv.frombytes
+			enc = baseconv('b58').frombytes
 			l = len(addr_bytes)
 			l = len(addr_bytes)
-			a = ''.join([enc( addr_bytes[i*8:i*8+8], 'b58', pad=11, tostr=True ) for i in range(l//8)])
-			b = enc( addr_bytes[l-l%8:], 'b58', pad=7, tostr=True )
+			a = ''.join([enc( addr_bytes[i*8:i*8+8], pad=11, tostr=True ) for i in range(l//8)])
+			b = enc( addr_bytes[l-l%8:], pad=7, tostr=True )
 			return a + b
 			return a + b
 
 
 		@check_data
 		@check_data

+ 59 - 78
mmgen/baseconv.py

@@ -31,7 +31,7 @@ def is_b32_str(s):
 	return set(list(s)) <= set(baseconv.digits['b32'])
 	return set(list(s)) <= set(baseconv.digits['b32'])
 
 
 def is_xmrseed(s):
 def is_xmrseed(s):
-	return bool(baseconv.tobytes(s.split(),wl_id='xmrseed'))
+	return bool( baseconv('xmrseed').tobytes(s.split()) )
 
 
 class baseconv(object):
 class baseconv(object):
 
 
@@ -77,58 +77,49 @@ class baseconv(object):
 		'xmrseed': { 25:32 },
 		'xmrseed': { 25:32 },
 	}
 	}
 
 
-	@classmethod
-	def init_mn(cls,mn_id):
-		if mn_id in cls.digits:
-			return
-		if mn_id == 'mmgen':
+	def __init__(self,wl_id):
+
+		if wl_id == 'mmgen':
 			from .mn_electrum import words
 			from .mn_electrum import words
-			cls.digits[mn_id] = words
-		elif mn_id == 'xmrseed':
+			self.digits[wl_id] = words
+		elif wl_id == 'xmrseed':
 			from .mn_monero import words
 			from .mn_monero import words
-			cls.digits[mn_id] = words
-		elif mn_id == 'tirosh':
+			self.digits[wl_id] = words
+		elif wl_id == 'tirosh':
 			from .mn_tirosh import words
 			from .mn_tirosh import words
-			cls.digits[mn_id] = words[:cls.mn_base]
-		else:
-			raise ValueError(f'{mn_id}: unrecognized mnemonic ID')
-
-	@classmethod
-	def get_wordlist(cls,wl_id):
-		cls.init_mn(wl_id)
-		return cls.digits[wl_id]
-
-	@classmethod
-	def get_wordlist_chksum(cls,wl_id):
-		cls.init_mn(wl_id)
-		return sha256(' '.join(cls.digits[wl_id]).encode()).hexdigest()[:8]
-
-	@classmethod
-	def check_wordlists(cls):
-		for k,v in list(cls.wl_chksums.items()):
-			res = cls.get_wordlist_chksum(k)
-			assert res == v,f'{res}: checksum mismatch for {k} (should be {v})'
-		return True
-
-	@classmethod
-	def check_wordlist(cls,wl_id):
-		cls.init_mn(wl_id)
-
-		wl = cls.digits[wl_id]
+			self.digits[wl_id] = words[:self.mn_base]
+		elif wl_id not in self.digits:
+			raise ValueError(f'{wl_id}: unrecognized mnemonic ID')
+
+		self.wl_id = wl_id
+
+	def get_wordlist(self):
+		return self.digits[self.wl_id]
+
+	def get_wordlist_chksum(self):
+		return sha256(' '.join(self.digits[self.wl_id]).encode()).hexdigest()[:8]
+
+	def check_wordlist(self):
+
+		wl = self.digits[self.wl_id]
 		from .util import qmsg,compare_chksums
 		from .util import qmsg,compare_chksums
-		ret = f'Wordlist: {wl_id}\nLength: {len(wl)} words'
-		new_chksum = cls.get_wordlist_chksum(wl_id)
+		ret = f'Wordlist: {self.wl_id}\nLength: {len(wl)} words'
+		new_chksum = self.get_wordlist_chksum()
 
 
-		a,b = 'generated','saved'
-		compare_chksums(new_chksum,a,cls.wl_chksums[wl_id],b,die_on_fail=True)
+		compare_chksums(
+			new_chksum,
+			'generated',
+			self.wl_chksums[self.wl_id],
+			'saved',
+			die_on_fail = True )
 
 
 		if tuple(sorted(wl)) == wl:
 		if tuple(sorted(wl)) == wl:
 			return ret + '\nList is sorted'
 			return ret + '\nList is sorted'
 		else:
 		else:
 			die(3,'ERROR: List is not sorted!')
 			die(3,'ERROR: List is not sorted!')
 
 
-	@classmethod
-	def get_pad(cls,pad,seed_pad_func):
+	@staticmethod
+	def get_pad(pad,seed_pad_func):
 		"""
 		"""
 		'pad' argument to baseconv conversion methods must be either None, 'seed' or an integer.
 		'pad' argument to baseconv conversion methods must be either None, 'seed' or an integer.
 		If None, output of minimum (but never zero) length will be produced.
 		If None, output of minimum (but never zero) length will be produced.
@@ -150,34 +141,29 @@ class baseconv(object):
 		wstr = ''.join(word[:3] for word in words)
 		wstr = ''.join(word[:3] for word in words)
 		return words[crc32(wstr.encode()) % len(words)]
 		return words[crc32(wstr.encode()) % len(words)]
 
 
-	@classmethod
-	def tohex(cls,words_arg,wl_id,pad=None):
-		"convert string or list data of base 'wl_id' to hex string"
-		return cls.tobytes(words_arg,wl_id,pad//2 if type(pad)==int else pad).hex()
+	def tohex(self,words_arg,pad=None):
+		"convert string or list data of instance base to hex string"
+		return self.tobytes(words_arg,pad//2 if type(pad)==int else pad).hex()
 
 
-	@classmethod
-	def tobytes(cls,words_arg,wl_id,pad=None):
-		"convert string or list data of base 'wl_id' to byte string"
-
-		if wl_id not in cls.digits:
-			cls.init_mn(wl_id)
+	def tobytes(self,words_arg,pad=None):
+		"convert string or list data of instance base to byte string"
 
 
 		words = words_arg if isinstance(words_arg,(list,tuple)) else tuple(words_arg.strip())
 		words = words_arg if isinstance(words_arg,(list,tuple)) else tuple(words_arg.strip())
-		desc = cls.desc[wl_id][0]
+		desc = self.desc[self.wl_id][0]
 
 
 		if len(words) == 0:
 		if len(words) == 0:
 			raise BaseConversionError(f'empty {desc} data')
 			raise BaseConversionError(f'empty {desc} data')
 
 
 		def get_seed_pad():
 		def get_seed_pad():
-			assert wl_id in cls.seedlen_map_rev,f'seed padding not supported for base {wl_id!r}'
-			d = cls.seedlen_map_rev[wl_id]
+			assert self.wl_id in self.seedlen_map_rev, f'seed padding not supported for base {self.wl_id!r}'
+			d = self.seedlen_map_rev[self.wl_id]
 			if not len(words) in d:
 			if not len(words) in d:
 				raise BaseConversionError(
 				raise BaseConversionError(
 					f'{len(words)}: invalid length for seed-padded {desc} data in base conversion' )
 					f'{len(words)}: invalid length for seed-padded {desc} data in base conversion' )
 			return d[len(words)]
 			return d[len(words)]
 
 
-		pad_val = max(cls.get_pad(pad,get_seed_pad),1)
-		wl = cls.digits[wl_id]
+		pad_val = max(self.get_pad(pad,get_seed_pad),1)
+		wl = self.digits[self.wl_id]
 		base = len(wl)
 		base = len(wl)
 
 
 		if not set(words) <= set(wl):
 		if not set(words) <= set(wl):
@@ -185,11 +171,11 @@ class baseconv(object):
 				( 'seed data' if pad == 'seed' else f'{words_arg!r}:' ) +
 				( 'seed data' if pad == 'seed' else f'{words_arg!r}:' ) +
 				f' not in {desc} format' )
 				f' not in {desc} format' )
 
 
-		if wl_id == 'xmrseed':
-			if len(words) not in cls.seedlen_map_rev['xmrseed']:
+		if self.wl_id == 'xmrseed':
+			if len(words) not in self.seedlen_map_rev['xmrseed']:
 				die(2,f'{len(words)}: invalid length for Monero mnemonic')
 				die(2,f'{len(words)}: invalid length for Monero mnemonic')
 
 
-			z = cls.monero_mn_checksum(words[:-1])
+			z = self.monero_mn_checksum(words[:-1])
 			assert z == words[-1],'invalid Monero mnemonic checksum'
 			assert z == words[-1],'invalid Monero mnemonic checksum'
 			words = tuple(words[:-1])
 			words = tuple(words[:-1])
 
 
@@ -204,9 +190,8 @@ class baseconv(object):
 		bl = ret.bit_length()
 		bl = ret.bit_length()
 		return ret.to_bytes(max(pad_val,bl//8+bool(bl%8)),'big')
 		return ret.to_bytes(max(pad_val,bl//8+bool(bl%8)),'big')
 
 
-	@classmethod
-	def fromhex(cls,hexstr,wl_id,pad=None,tostr=False):
-		"convert hex string to list or string data of base 'wl_id'"
+	def fromhex(self,hexstr,pad=None,tostr=False):
+		"convert hex string to list or string data of instance base"
 
 
 		from .util import is_hex_str
 		from .util import is_hex_str
 		if not is_hex_str(hexstr):
 		if not is_hex_str(hexstr):
@@ -214,32 +199,28 @@ class baseconv(object):
 				( 'seed data' if pad == 'seed' else f'{hexstr!r}:' ) +
 				( 'seed data' if pad == 'seed' else f'{hexstr!r}:' ) +
 				' not a hexadecimal string' )
 				' not a hexadecimal string' )
 
 
-		return cls.frombytes(bytes.fromhex(hexstr),wl_id,pad,tostr)
-
-	@classmethod
-	def frombytes(cls,bytestr,wl_id,pad=None,tostr=False):
-		"convert byte string to list or string data of base 'wl_id'"
+		return self.frombytes( bytes.fromhex(hexstr), pad, tostr )
 
 
-		if wl_id not in cls.digits:
-			cls.init_mn(wl_id)
+	def frombytes(self,bytestr,pad=None,tostr=False):
+		"convert byte string to list or string data of instance base"
 
 
 		if not bytestr:
 		if not bytestr:
 			raise BaseConversionError('empty data not allowed in base conversion')
 			raise BaseConversionError('empty data not allowed in base conversion')
 
 
 		def get_seed_pad():
 		def get_seed_pad():
-			assert wl_id in cls.seedlen_map, f'seed padding not supported for base {wl_id!r}'
-			d = cls.seedlen_map[wl_id]
+			assert self.wl_id in self.seedlen_map, f'seed padding not supported for base {self.wl_id!r}'
+			d = self.seedlen_map[self.wl_id]
 			if not len(bytestr) in d:
 			if not len(bytestr) in d:
 				raise SeedLengthError(
 				raise SeedLengthError(
 					f'{len(bytestr)}: invalid byte length for seed data in seed-padded base conversion' )
 					f'{len(bytestr)}: invalid byte length for seed data in seed-padded base conversion' )
 			return d[len(bytestr)]
 			return d[len(bytestr)]
 
 
-		pad = max(cls.get_pad(pad,get_seed_pad),1)
-		wl = cls.digits[wl_id]
+		pad = max(self.get_pad(pad,get_seed_pad),1)
+		wl = self.digits[self.wl_id]
 		base = len(wl)
 		base = len(wl)
 
 
-		if wl_id == 'xmrseed':
-			if len(bytestr) not in cls.seedlen_map['xmrseed']:
+		if self.wl_id == 'xmrseed':
+			if len(bytestr) not in self.seedlen_map['xmrseed']:
 				die(2, f'{len(bytestr)}: invalid seed byte length for Monero mnemonic')
 				die(2, f'{len(bytestr)}: invalid seed byte length for Monero mnemonic')
 
 
 			def num2base_monero(num):
 			def num2base_monero(num):
@@ -251,7 +232,7 @@ class baseconv(object):
 			o = []
 			o = []
 			for i in range(len(bytestr)//4):
 			for i in range(len(bytestr)//4):
 				o += num2base_monero(int.from_bytes(bytestr[i*4:i*4+4][::-1],'big'))
 				o += num2base_monero(int.from_bytes(bytestr[i*4:i*4+4][::-1],'big'))
-			o.append(cls.monero_mn_checksum(o))
+			o.append(self.monero_mn_checksum(o))
 		else:
 		else:
 			num = int.from_bytes(bytestr,'big')
 			num = int.from_bytes(bytestr,'big')
 			ret = []
 			ret = []
@@ -260,4 +241,4 @@ class baseconv(object):
 				num //= base
 				num //= base
 			o = [wl[n] for n in [0] * (pad-len(ret)) + ret[::-1]]
 			o = [wl[n] for n in [0] * (pad-len(ret)) + ret[::-1]]
 
 
-		return (' ' if wl_id in ('mmgen','xmrseed') else '').join(o) if tostr else o
+		return (' ' if self.wl_id in ('mmgen','xmrseed') else '').join(o) if tostr else o

+ 17 - 23
mmgen/bip39.py

@@ -27,7 +27,7 @@ from .baseconv import baseconv
 from .util import is_hex_str
 from .util import is_hex_str
 
 
 def is_bip39_str(s):
 def is_bip39_str(s):
-	return bool( bip39.tohex(s.split(), wl_id='bip39') )
+	return bool( bip39().tohex(s.split()) )
 
 
 # implements a subset of the baseconv API
 # implements a subset of the baseconv API
 class bip39(baseconv):
 class bip39(baseconv):
@@ -47,8 +47,12 @@ class bip39(baseconv):
 		224: bc(7, 21),
 		224: bc(7, 21),
 		256: bc(8, 24),
 		256: bc(8, 24),
 	}
 	}
-	from .mn_bip39 import words
-	digits = { 'bip39': words }
+
+	def __init__(self,wl_id='bip39'):
+		assert wl_id == 'bip39', "initialize with 'bip39' for compatibility with baseconv API"
+		from .mn_bip39 import words
+		self.digits = { 'bip39': words }
+		self.wl_id = 'bip39'
 
 
 	@classmethod
 	@classmethod
 	def nwords2seedlen(cls,nwords,in_bytes=False,in_hex=False):
 	def nwords2seedlen(cls,nwords,in_bytes=False,in_hex=False):
@@ -65,21 +69,17 @@ class bip39(baseconv):
 		except:
 		except:
 			raise ValueError(f'{seed_bits!r}: invalid seed length for BIP39 mnemonic')
 			raise ValueError(f'{seed_bits!r}: invalid seed length for BIP39 mnemonic')
 
 
-	@classmethod
-	def tobytes(cls,*args,**kwargs):
+	def tobytes(self,*args,**kwargs):
 		raise NotImplementedError('Method not supported')
 		raise NotImplementedError('Method not supported')
 
 
-	@classmethod
-	def frombytes(cls,*args,**kwargs):
+	def frombytes(self,*args,**kwargs):
 		raise NotImplementedError('Method not supported')
 		raise NotImplementedError('Method not supported')
 
 
-	@classmethod
-	def tohex(cls,words,wl_id,pad=None):
+	def tohex(self,words,pad=None):
 		assert isinstance(words,(list,tuple)),'words must be list or tuple'
 		assert isinstance(words,(list,tuple)),'words must be list or tuple'
-		assert wl_id == 'bip39',"'wl_id' must be 'bip39'"
 		assert pad == None, f"{pad}: invalid 'pad' argument (must be None)"
 		assert pad == None, f"{pad}: invalid 'pad' argument (must be None)"
 
 
-		wl = cls.digits[wl_id]
+		wl = self.digits['bip39']
 
 
 		for n,w in enumerate(words):
 		for n,w in enumerate(words):
 			if w not in wl:
 			if w not in wl:
@@ -87,7 +87,7 @@ class bip39(baseconv):
 
 
 		res = ''.join(['{:011b}'.format(wl.index(w)) for w in words])
 		res = ''.join(['{:011b}'.format(wl.index(w)) for w in words])
 
 
-		for k,v in cls.constants.items():
+		for k,v in self.constants.items():
 			if len(words) == v.mn_len:
 			if len(words) == v.mn_len:
 				bitlen = k
 				bitlen = k
 				break
 				break
@@ -100,7 +100,7 @@ class bip39(baseconv):
 		seed_hex = '{:0{w}x}'.format(int(seed_bin,2),w=bitlen//4)
 		seed_hex = '{:0{w}x}'.format(int(seed_bin,2),w=bitlen//4)
 		seed_bytes = bytes.fromhex(seed_hex)
 		seed_bytes = bytes.fromhex(seed_hex)
 
 
-		chk_len = cls.constants[bitlen].chk_len
+		chk_len = self.constants[bitlen].chk_len
 		chk_hex_chk = sha256(seed_bytes).hexdigest()
 		chk_hex_chk = sha256(seed_bytes).hexdigest()
 		chk_bin_chk = '{:0{w}b}'.format(int(chk_hex_chk,16),w=256)[:chk_len]
 		chk_bin_chk = '{:0{w}b}'.format(int(chk_hex_chk,16),w=256)[:chk_len]
 
 
@@ -109,19 +109,17 @@ class bip39(baseconv):
 
 
 		return seed_hex
 		return seed_hex
 
 
-	@classmethod
-	def fromhex(cls,seed_hex,wl_id,pad=None,tostr=False):
+	def fromhex(self,seed_hex,pad=None,tostr=False):
 		assert is_hex_str(seed_hex),'seed data not a hexadecimal string'
 		assert is_hex_str(seed_hex),'seed data not a hexadecimal string'
-		assert wl_id == 'bip39',"'wl_id' must be 'bip39'"
 		assert tostr == False,"'tostr' must be False for 'bip39'"
 		assert tostr == False,"'tostr' must be False for 'bip39'"
 		assert pad == None, f"{pad}: invalid 'pad' argument (must be None)"
 		assert pad == None, f"{pad}: invalid 'pad' argument (must be None)"
 
 
-		wl = cls.digits[wl_id]
+		wl = self.digits['bip39']
 		seed_bytes = bytes.fromhex(seed_hex)
 		seed_bytes = bytes.fromhex(seed_hex)
 		bitlen = len(seed_bytes) * 8
 		bitlen = len(seed_bytes) * 8
 
 
-		assert bitlen in cls.constants, f'{bitlen}: invalid seed bit length'
-		c = cls.constants[bitlen]
+		assert bitlen in self.constants, f'{bitlen}: invalid seed bit length'
+		c = self.constants[bitlen]
 
 
 		chk_hex = sha256(seed_bytes).hexdigest()
 		chk_hex = sha256(seed_bytes).hexdigest()
 
 
@@ -131,7 +129,3 @@ class bip39(baseconv):
 		res = seed_bin + chk_bin
 		res = seed_bin + chk_bin
 
 
 		return tuple(wl[int(res[i*11:(i+1)*11],2)] for i in range(c.mn_len))
 		return tuple(wl[int(res[i*11:(i+1)*11],2)] for i in range(c.mn_len))
-
-	@classmethod
-	def init_mn(cls,mn_id):
-		assert mn_id == 'bip39', "'mn_id' must be 'bip39'"

+ 4 - 5
mmgen/mn_entry.py

@@ -219,9 +219,8 @@ def mn_entry(wl_id,entry_mode=None):
 		wl_id = 'mmgen'
 		wl_id = 'mmgen'
 	me = MnemonicEntry.get_cls_by_wordlist(wl_id)
 	me = MnemonicEntry.get_cls_by_wordlist(wl_id)
 	import importlib
 	import importlib
-	me.conv_cls = getattr(importlib.import_module(f'mmgen.{me.modname}'),me.modname)
-	me.conv_cls.init_mn(wl_id)
-	me.wl = me.conv_cls.digits[wl_id]
+	me.bconv = getattr(importlib.import_module(f'mmgen.{me.modname}'),me.modname)(wl_id)
+	me.wl = me.bconv.digits[wl_id]
 	obj = me()
 	obj = me()
 	if entry_mode:
 	if entry_mode:
 		obj.em = globals()['MnEntryMode'+capfirst(entry_mode)](obj)
 		obj.em = globals()['MnEntryMode'+capfirst(entry_mode)](obj)
@@ -335,7 +334,7 @@ class MnemonicEntry(object):
 				msg_r(erase)
 				msg_r(erase)
 
 
 	def get_mnemonic_from_user(self,mn_len,validate=True):
 	def get_mnemonic_from_user(self,mn_len,validate=True):
-		mll = list(self.conv_cls.seedlen_map_rev[self.wl_id])
+		mll = list(self.bconv.seedlen_map_rev[self.wl_id])
 		assert mn_len in mll, f'{mn_len}: invalid mnemonic length (must be one of {mll})'
 		assert mn_len in mll, f'{mn_len}: invalid mnemonic length (must be one of {mll})'
 
 
 		if self.usr_dfl_entry_mode:
 		if self.usr_dfl_entry_mode:
@@ -375,7 +374,7 @@ class MnemonicEntry(object):
 		words = [self.wl[i] for i in idxs]
 		words = [self.wl[i] for i in idxs]
 
 
 		if validate:
 		if validate:
-			self.conv_cls.tohex(words,self.wl_id)
+			self.bconv.tohex(words)
 			if self.has_chksum:
 			if self.has_chksum:
 				qmsg('Mnemonic is valid')
 				qmsg('Mnemonic is valid')
 			else:
 			else:

+ 4 - 5
mmgen/passwdlist.py

@@ -166,7 +166,7 @@ class PasswordList(AddrList):
 		elif pf in ('b32','b58'):
 		elif pf in ('b32','b58'):
 			pw_int = (32 if pf == 'b32' else 58) ** self.pw_len
 			pw_int = (32 if pf == 'b32' else 58) ** self.pw_len
 			pw_bytes = pw_int.bit_length() // 8
 			pw_bytes = pw_int.bit_length() // 8
-			good_pw_len = len(baseconv.frombytes(b'\xff'*seed.byte_len,wl_id=pf))
+			good_pw_len = len( baseconv(pf).frombytes(b'\xff'*seed.byte_len) )
 		else:
 		else:
 			raise NotImplementedError(f'{pf!r}: unknown password format')
 			raise NotImplementedError(f'{pf!r}: unknown password format')
 
 
@@ -194,19 +194,18 @@ class PasswordList(AddrList):
 			from .bip39 import bip39
 			from .bip39 import bip39
 			pw_len_bytes = bip39.nwords2seedlen( self.pw_len, in_bytes=True )
 			pw_len_bytes = bip39.nwords2seedlen( self.pw_len, in_bytes=True )
 			# take most significant part
 			# take most significant part
-			return ' '.join( bip39.fromhex( secbytes[:pw_len_bytes].hex(), wl_id='bip39' ) )
+			return ' '.join( bip39().fromhex(secbytes[:pw_len_bytes].hex()) )
 		elif self.pw_fmt == 'xmrseed':
 		elif self.pw_fmt == 'xmrseed':
 			pw_len_bytes = baseconv.seedlen_map_rev['xmrseed'][self.pw_len]
 			pw_len_bytes = baseconv.seedlen_map_rev['xmrseed'][self.pw_len]
 			from .protocol import init_proto
 			from .protocol import init_proto
 			bytes_preproc = init_proto('xmr').preprocess_key(
 			bytes_preproc = init_proto('xmr').preprocess_key(
 				secbytes[:pw_len_bytes], # take most significant part
 				secbytes[:pw_len_bytes], # take most significant part
 				None )
 				None )
-			return ' '.join( baseconv.frombytes( bytes_preproc, wl_id='xmrseed' ) )
+			return ' '.join( baseconv('xmrseed').frombytes(bytes_preproc) )
 		else:
 		else:
 			# take least significant part
 			# take least significant part
-			return baseconv.frombytes(
+			return baseconv(self.pw_fmt).frombytes(
 				secbytes,
 				secbytes,
-				self.pw_fmt,
 				pad = self.pw_len,
 				pad = self.pw_len,
 				tostr = True )[-self.pw_len:]
 				tostr = True )[-self.pw_len:]
 
 

+ 3 - 2
mmgen/protocol.py

@@ -512,9 +512,10 @@ class CoinProtocol(MMGenObject):
 			from .baseconv import baseconv,is_b58_str
 			from .baseconv import baseconv,is_b58_str
 
 
 			def b58dec(addr_str):
 			def b58dec(addr_str):
+				bc = baseconv('b58')
 				l = len(addr_str)
 				l = len(addr_str)
-				a = b''.join([baseconv.tobytes(addr_str[i*11:i*11+11],'b58',pad=8) for i in range(l//11)])
-				b = baseconv.tobytes(addr_str[-(l%11):],'b58',pad=5)
+				a = b''.join([bc.tobytes( addr_str[i*11:i*11+11], pad=8 ) for i in range(l//11)])
+				b = bc.tobytes( addr_str[-(l%11):], pad=5 )
 				return a + b
 				return a + b
 
 
 			ret = b58dec(addr)
 			ret = b58dec(addr)

+ 15 - 15
mmgen/tool.py

@@ -390,24 +390,24 @@ class MMGenToolCmdUtil(MMGenToolCmds):
 
 
 	def randb58(self,nbytes=32,pad=0):
 	def randb58(self,nbytes=32,pad=0):
 		"generate random data (default: 32 bytes) and convert it to base 58"
 		"generate random data (default: 32 bytes) and convert it to base 58"
-		return baseconv.frombytes(get_random(nbytes),'b58',pad=pad,tostr=True)
+		return baseconv('b58').frombytes(get_random(nbytes),pad=pad,tostr=True)
 
 
 	def bytestob58(self,infile:str,pad=0):
 	def bytestob58(self,infile:str,pad=0):
 		"convert bytes to base 58 (supply data via STDIN)"
 		"convert bytes to base 58 (supply data via STDIN)"
 		data = get_data_from_file(infile,dash=True,quiet=True,binary=True)
 		data = get_data_from_file(infile,dash=True,quiet=True,binary=True)
-		return baseconv.frombytes(data,'b58',pad=pad,tostr=True)
+		return baseconv('b58').frombytes(data,pad=pad,tostr=True)
 
 
 	def b58tobytes(self,b58num:'sstr',pad=0):
 	def b58tobytes(self,b58num:'sstr',pad=0):
 		"convert a base 58 number to bytes (warning: outputs binary data)"
 		"convert a base 58 number to bytes (warning: outputs binary data)"
-		return baseconv.tobytes(b58num,'b58',pad=pad)
+		return baseconv('b58').tobytes(b58num,pad=pad)
 
 
 	def hextob58(self,hexstr:'sstr',pad=0):
 	def hextob58(self,hexstr:'sstr',pad=0):
 		"convert a hexadecimal number to base 58"
 		"convert a hexadecimal number to base 58"
-		return baseconv.fromhex(hexstr,'b58',pad=pad,tostr=True)
+		return baseconv('b58').fromhex(hexstr,pad=pad,tostr=True)
 
 
 	def b58tohex(self,b58num:'sstr',pad=0):
 	def b58tohex(self,b58num:'sstr',pad=0):
 		"convert a base 58 number to hexadecimal"
 		"convert a base 58 number to hexadecimal"
-		return baseconv.tohex(b58num,'b58',pad=pad)
+		return baseconv('b58').tohex(b58num,pad=pad)
 
 
 	def hextob58chk(self,hexstr:'sstr'):
 	def hextob58chk(self,hexstr:'sstr'):
 		"convert a hexadecimal number to base58-check encoding"
 		"convert a hexadecimal number to base58-check encoding"
@@ -421,20 +421,20 @@ class MMGenToolCmdUtil(MMGenToolCmds):
 
 
 	def hextob32(self,hexstr:'sstr',pad=0):
 	def hextob32(self,hexstr:'sstr',pad=0):
 		"convert a hexadecimal number to MMGen's flavor of base 32"
 		"convert a hexadecimal number to MMGen's flavor of base 32"
-		return baseconv.fromhex(hexstr,'b32',pad,tostr=True)
+		return baseconv('b32').fromhex(hexstr,pad,tostr=True)
 
 
 	def b32tohex(self,b32num:'sstr',pad=0):
 	def b32tohex(self,b32num:'sstr',pad=0):
 		"convert an MMGen-flavor base 32 number to hexadecimal"
 		"convert an MMGen-flavor base 32 number to hexadecimal"
-		return baseconv.tohex(b32num.upper(),'b32',pad)
+		return baseconv('b32').tohex(b32num.upper(),pad)
 
 
 	def hextob6d(self,hexstr:'sstr',pad=0,add_spaces=True):
 	def hextob6d(self,hexstr:'sstr',pad=0,add_spaces=True):
 		"convert a hexadecimal number to die roll base6 (base6d)"
 		"convert a hexadecimal number to die roll base6 (base6d)"
-		ret = baseconv.fromhex(hexstr,'b6d',pad,tostr=True)
+		ret = baseconv('b6d').fromhex(hexstr,pad,tostr=True)
 		return block_format(ret,gw=5,cols=None).strip() if add_spaces else ret
 		return block_format(ret,gw=5,cols=None).strip() if add_spaces else ret
 
 
 	def b6dtohex(self,b6d_num:'sstr',pad=0):
 	def b6dtohex(self,b6d_num:'sstr',pad=0):
 		"convert a die roll base6 (base6d) number to hexadecimal"
 		"convert a die roll base6 (base6d) number to hexadecimal"
-		return baseconv.tohex(remove_whitespace(b6d_num),'b6d',pad)
+		return baseconv('b6d').tohex(remove_whitespace(b6d_num),pad)
 
 
 class MMGenToolCmdCoin(MMGenToolCmds):
 class MMGenToolCmdCoin(MMGenToolCmds):
 	"""
 	"""
@@ -625,20 +625,20 @@ class MMGenToolCmdMnemonic(MMGenToolCmds):
 		"convert a 16, 24 or 32-byte hexadecimal number to a mnemonic seed phrase"
 		"convert a 16, 24 or 32-byte hexadecimal number to a mnemonic seed phrase"
 		if fmt == 'bip39':
 		if fmt == 'bip39':
 			from .bip39 import bip39
 			from .bip39 import bip39
-			return ' '.join(bip39.fromhex(hexstr,fmt))
+			return ' '.join(bip39(fmt).fromhex(hexstr))
 		else:
 		else:
 			bytestr = bytes.fromhex(hexstr)
 			bytestr = bytes.fromhex(hexstr)
 			if fmt == 'xmrseed':
 			if fmt == 'xmrseed':
 				bytestr = self._xmr_reduce(bytestr)
 				bytestr = self._xmr_reduce(bytestr)
-			return baseconv.frombytes(bytestr,fmt,'seed',tostr=True)
+			return baseconv(fmt).frombytes(bytestr,'seed',tostr=True)
 
 
 	def mn2hex( self, seed_mnemonic:'sstr', fmt:mn_opts_disp = dfl_mnemonic_fmt ):
 	def mn2hex( self, seed_mnemonic:'sstr', fmt:mn_opts_disp = dfl_mnemonic_fmt ):
 		"convert a mnemonic seed phrase to a hexadecimal number"
 		"convert a mnemonic seed phrase to a hexadecimal number"
 		if fmt == 'bip39':
 		if fmt == 'bip39':
 			from .bip39 import bip39
 			from .bip39 import bip39
-			return bip39.tohex(seed_mnemonic.split(),fmt)
+			return bip39(fmt).tohex(seed_mnemonic.split())
 		else:
 		else:
-			return baseconv.tohex(seed_mnemonic.split(),fmt,'seed')
+			return baseconv(fmt).tohex(seed_mnemonic.split(),'seed')
 
 
 	def mn2hex_interactive( self, fmt:mn_opts_disp = dfl_mnemonic_fmt, mn_len=24, print_mn=False ):
 	def mn2hex_interactive( self, fmt:mn_opts_disp = dfl_mnemonic_fmt, mn_len=24, print_mn=False ):
 		"convert an interactively supplied mnemonic seed phrase to a hexadecimal number"
 		"convert an interactively supplied mnemonic seed phrase to a hexadecimal number"
@@ -651,12 +651,12 @@ class MMGenToolCmdMnemonic(MMGenToolCmds):
 	def mn_stats(self, fmt:mn_opts_disp = dfl_mnemonic_fmt ):
 	def mn_stats(self, fmt:mn_opts_disp = dfl_mnemonic_fmt ):
 		"show stats for mnemonic wordlist"
 		"show stats for mnemonic wordlist"
 		conv_cls = mnemonic_fmts[fmt]['conv_cls']()
 		conv_cls = mnemonic_fmts[fmt]['conv_cls']()
-		return conv_cls.check_wordlist(fmt)
+		return conv_cls(fmt).check_wordlist()
 
 
 	def mn_printlist( self, fmt:mn_opts_disp = dfl_mnemonic_fmt, enum=False, pager=False ):
 	def mn_printlist( self, fmt:mn_opts_disp = dfl_mnemonic_fmt, enum=False, pager=False ):
 		"print mnemonic wordlist"
 		"print mnemonic wordlist"
 		conv_cls = mnemonic_fmts[fmt]['conv_cls']()
 		conv_cls = mnemonic_fmts[fmt]['conv_cls']()
-		ret = conv_cls.get_wordlist(fmt)
+		ret = conv_cls(fmt).get_wordlist()
 		if enum:
 		if enum:
 			ret = [f'{n:>4} {e}' for n,e in enumerate(ret)]
 			ret = [f'{n:>4} {e}' for n,e in enumerate(ret)]
 		return '\n'.join(ret)
 		return '\n'.join(ret)

+ 2 - 2
mmgen/txfile.py

@@ -81,7 +81,7 @@ class MMGenTxFile:
 				if c != '-':
 				if c != '-':
 					desc = 'encoded comment (not base58)'
 					desc = 'encoded comment (not base58)'
 					from .baseconv import baseconv
 					from .baseconv import baseconv
-					comment = baseconv.tobytes(c,'b58').decode()
+					comment = baseconv('b58').tobytes(c).decode()
 					assert comment != False,'invalid comment'
 					assert comment != False,'invalid comment'
 					desc = 'comment'
 					desc = 'comment'
 					tx.label = MMGenTxLabel(comment)
 					tx.label = MMGenTxLabel(comment)
@@ -177,7 +177,7 @@ class MMGenTxFile:
 
 
 		if tx.label:
 		if tx.label:
 			from .baseconv import baseconv
 			from .baseconv import baseconv
-			lines.append(baseconv.frombytes(tx.label.encode(),'b58',tostr=True))
+			lines.append(baseconv('b58').frombytes(tx.label.encode(),tostr=True))
 
 
 		if tx.coin_txid:
 		if tx.coin_txid:
 			if not tx.label:
 			if not tx.label:

+ 15 - 13
mmgen/wallet.py

@@ -425,8 +425,9 @@ class Mnemonic(WalletUnenc):
 
 
 		hexseed = self.seed.hexdata
 		hexseed = self.seed.hexdata
 
 
-		mn  = self.conv_cls.fromhex(hexseed,self.wl_id,self._hex2mn_pad(hexseed))
-		ret = self.conv_cls.tohex(mn,self.wl_id,self._mn2hex_pad(mn))
+		bc = self.conv_cls(self.wl_id)
+		mn  = bc.fromhex( hexseed, self._hex2mn_pad(hexseed) )
+		ret = bc.tohex( mn, self._mn2hex_pad(mn) )
 
 
 		# Internal error, so just die on fail
 		# Internal error, so just die on fail
 		compare_or_die(ret,'recomputed seed',hexseed,'original',e='Internal error')
 		compare_or_die(ret,'recomputed seed',hexseed,'original',e='Internal error')
@@ -436,7 +437,7 @@ class Mnemonic(WalletUnenc):
 
 
 	def _deformat(self):
 	def _deformat(self):
 
 
-		self.conv_cls.init_mn(self.wl_id)
+		bc = self.conv_cls(self.wl_id)
 		mn = self.fmt_data.split()
 		mn = self.fmt_data.split()
 
 
 		if len(mn) not in self.mn_lens:
 		if len(mn) not in self.mn_lens:
@@ -446,12 +447,12 @@ class Mnemonic(WalletUnenc):
 			return False
 			return False
 
 
 		for n,w in enumerate(mn,1):
 		for n,w in enumerate(mn,1):
-			if w not in self.conv_cls.digits[self.wl_id]:
+			if w not in bc.digits[self.wl_id]:
 				msg(f'Invalid mnemonic: word #{n} is not in the {self.wl_id.upper()} wordlist')
 				msg(f'Invalid mnemonic: word #{n} is not in the {self.wl_id.upper()} wordlist')
 				return False
 				return False
 
 
-		hexseed = self.conv_cls.tohex(mn,self.wl_id,self._mn2hex_pad(mn))
-		ret     = self.conv_cls.fromhex(hexseed,self.wl_id,self._hex2mn_pad(hexseed))
+		hexseed = bc.tohex( mn, self._mn2hex_pad(mn) )
+		ret     = bc.fromhex( hexseed, self._hex2mn_pad(hexseed) )
 
 
 		if len(hexseed) * 4 not in g.seed_lens:
 		if len(hexseed) * 4 not in g.seed_lens:
 			msg('Invalid mnemonic (produces too large a number)')
 			msg('Invalid mnemonic (produces too large a number)')
@@ -502,7 +503,7 @@ class MMGenSeedFile(WalletUnenc):
 	ext = 'mmseed'
 	ext = 'mmseed'
 
 
 	def _format(self):
 	def _format(self):
-		b58seed = baseconv.frombytes(self.seed.data,'b58',pad='seed',tostr=True)
+		b58seed = baseconv('b58').frombytes(self.seed.data,pad='seed',tostr=True)
 		self.ssdata.chksum = make_chksum_6(b58seed)
 		self.ssdata.chksum = make_chksum_6(b58seed)
 		self.ssdata.b58seed = b58seed
 		self.ssdata.b58seed = b58seed
 		self.fmt_data = '{} {}\n'.format(
 		self.fmt_data = '{} {}\n'.format(
@@ -532,7 +533,7 @@ class MMGenSeedFile(WalletUnenc):
 		if not compare_chksums(a,'file',make_chksum_6(b),'computed',verbose=True):
 		if not compare_chksums(a,'file',make_chksum_6(b),'computed',verbose=True):
 			return False
 			return False
 
 
-		ret = baseconv.tobytes(b,'b58',pad='seed')
+		ret = baseconv('b58').tobytes(b,pad='seed')
 
 
 		if ret == False:
 		if ret == False:
 			msg(f'Invalid base-58 encoded seed: {val}')
 			msg(f'Invalid base-58 encoded seed: {val}')
@@ -562,7 +563,7 @@ class DieRollSeedFile(WalletUnenc):
 	interactive_input = False
 	interactive_input = False
 
 
 	def _format(self):
 	def _format(self):
-		d = baseconv.frombytes(self.seed.data,'b6d',pad='seed',tostr=True) + '\n'
+		d = baseconv('b6d').frombytes(self.seed.data,pad='seed',tostr=True) + '\n'
 		self.fmt_data = block_format(d,gw=5,cols=5)
 		self.fmt_data = block_format(d,gw=5,cols=5)
 
 
 	def _deformat(self):
 	def _deformat(self):
@@ -578,7 +579,7 @@ class DieRollSeedFile(WalletUnenc):
 
 
 		# truncate seed to correct length, discarding high bits
 		# truncate seed to correct length, discarding high bits
 		seed_len = rmap[len(d)]
 		seed_len = rmap[len(d)]
-		seed_bytes = baseconv.tobytes(d,'b6d',pad='seed')[-seed_len:]
+		seed_bytes = baseconv('b6d').tobytes(d,pad='seed')[-seed_len:]
 
 
 		if self.interactive_input and opt.usr_randchars:
 		if self.interactive_input and opt.usr_randchars:
 			if keypress_confirm(self.user_entropy_prompt):
 			if keypress_confirm(self.user_entropy_prompt):
@@ -781,8 +782,9 @@ class MMGenWallet(WalletEnc):
 	def _format(self):
 	def _format(self):
 		d = self.ssdata
 		d = self.ssdata
 		s = self.seed
 		s = self.seed
-		slt_fmt  = baseconv.frombytes(d.salt,'b58',pad='seed',tostr=True)
-		es_fmt = baseconv.frombytes(d.enc_seed,'b58',pad='seed',tostr=True)
+		bc = baseconv('b58')
+		slt_fmt  = bc.frombytes(d.salt,pad='seed',tostr=True)
+		es_fmt = bc.frombytes(d.enc_seed,pad='seed',tostr=True)
 		lines = (
 		lines = (
 			d.label,
 			d.label,
 			'{} {} {} {} {}'.format( s.sid.lower(), d.key_id.lower(), s.bitlen, d.pw_status, d.timestamp ),
 			'{} {} {} {} {}'.format( s.sid.lower(), d.key_id.lower(), s.bitlen, d.pw_status, d.timestamp ),
@@ -852,7 +854,7 @@ class MMGenWallet(WalletEnc):
 					make_chksum_6(b58_val),'computed checksum',verbose=True):
 					make_chksum_6(b58_val),'computed checksum',verbose=True):
 				return False
 				return False
 
 
-			val = baseconv.tobytes(b58_val,'b58',pad='seed')
+			val = baseconv('b58').tobytes(b58_val,pad='seed')
 			if val == False:
 			if val == False:
 				msg(f'Invalid base 58 number: {b58_val}')
 				msg(f'Invalid base 58 number: {b58_val}')
 				return False
 				return False

+ 1 - 1
mmgen/xmrwallet.py

@@ -584,7 +584,7 @@ class MoneroWalletOps:
 				'restore_deterministic_wallet',
 				'restore_deterministic_wallet',
 				filename       = os.path.basename(fn),
 				filename       = os.path.basename(fn),
 				password       = d.wallet_passwd,
 				password       = d.wallet_passwd,
-				seed           = baseconv.fromhex(d.sec.wif,'xmrseed',tostr=True),
+				seed           = baseconv('xmrseed').fromhex(d.sec.wif,tostr=True),
 				restore_height = uopt.restore_height,
 				restore_height = uopt.restore_height,
 				language       = 'English' )
 				language       = 'English' )
 
 

+ 31 - 23
test/unit_tests_d/ut_baseconv.py

@@ -162,7 +162,7 @@ class unit_test(object):
 			vmsg(f'\nBase: {base}')
 			vmsg(f'\nBase: {base}')
 			vmsg(fs.format(h='Input',p='Pad',r='Output'))
 			vmsg(fs.format(h='Input',p='Pad',r='Output'))
 			for (hexstr,pad),ret_chk in data:
 			for (hexstr,pad),ret_chk in data:
-				ret = baseconv.fromhex(hexstr,wl_id=base,pad=pad,tostr=True)
+				ret = baseconv(base).fromhex(hexstr,pad=pad,tostr=True)
 				if pad != 'seed':
 				if pad != 'seed':
 					assert len(ret) >= (pad or 0), perr.format(ret,pad or 0)
 					assert len(ret) >= (pad or 0), perr.format(ret,pad or 0)
 				assert ret == ret_chk, rerr.format(ret,ret_chk)
 				assert ret == ret_chk, rerr.format(ret,ret_chk)
@@ -180,9 +180,8 @@ class unit_test(object):
 			for (hexstr,pad),ret_chk in data:
 			for (hexstr,pad),ret_chk in data:
 				if type(pad) == int:
 				if type(pad) == int:
 					pad = len(hexstr)
 					pad = len(hexstr)
-				ret = baseconv.tohex(
+				ret = baseconv(base).tohex(
 					ret_chk.split() if base == 'xmrseed' else ret_chk,
 					ret_chk.split() if base == 'xmrseed' else ret_chk,
-					wl_id=base,
 					pad=pad)
 					pad=pad)
 				if pad == None:
 				if pad == None:
 					assert int(ret,16) == int(hexstr,16), rerr.format(int(ret,16),int(hexstr,16))
 					assert int(ret,16) == int(hexstr,16), rerr.format(int(ret,16),int(hexstr,16))
@@ -191,34 +190,43 @@ class unit_test(object):
 				vmsg(fs.format(h=ret_chk,r=ret,p=str(pad)))
 				vmsg(fs.format(h=ret_chk,r=ret,p=str(pad)))
 #				msg("(('{h}',{p}),'{r}'),".format(h=hexstr,r=ret_chk,c=ret_chk,p=pad))
 #				msg("(('{h}',{p}),'{r}'),".format(h=hexstr,r=ret_chk,c=ret_chk,p=pad))
 
 
+		qmsg_r('\nChecking wordlist checksums:')
+		vmsg('')
+
+		for wl_id in baseconv.wl_chksums:
+			vmsg_r(f'  {wl_id+":":9}')
+			baseconv(wl_id).check_wordlist()
+
 		qmsg('')
 		qmsg('')
 
 
-		vmsg('')
 		qmsg('Checking error handling:')
 		qmsg('Checking error handling:')
 
 
 		bad_b58 = 'I'*22
 		bad_b58 = 'I'*22
 		bad_b58len = 'a'*23
 		bad_b58len = 'a'*23
 
 
-		th = baseconv.tohex
-		fh = baseconv.fromhex
+		fr58 = baseconv('b58').fromhex
+		to58 = baseconv('b58').tohex
+		to32 = baseconv('b32').tohex
+		to8  = baseconv('b8').tohex
+
 		bad_data = (
 		bad_data = (
-('hexstr',          'HexadecimalStringError', ': not a hexadecimal str', lambda:fh('x','b58')),
-('hexstr (seed)',   'HexadecimalStringError', 'seed data not a hexadec', lambda:fh('x','b58',pad='seed')),
-('hexstr (empty)',  'BaseConversionError',    'empty data not allowed',  lambda:fh('','b58')),
-('b58 data',        'BaseConversionError',    ': not in base58',         lambda:th('IfFzZ','b58')),
-('b58 data (seed)', 'BaseConversionError',    'seed data not in base58', lambda:th(bad_b58,'b58',pad='seed')),
-('b58 len (seed)',  'BaseConversionError',    'invalid length for',      lambda:th(bad_b58len,'b58',pad='seed')),
-('b58 data (empty)','BaseConversionError',    'empty base58 data',       lambda:th('','b58')),
-('b8 data (empty)' ,'BaseConversionError',    'empty base8 string data', lambda:th('','b8')),
-('b32 data',        'BaseConversionError',    'not in MMGen base32',     lambda:th('1az','b32')),
-('pad arg (in)',    'BaseConversionPadError', "illegal value for 'pad'", lambda:fh('ff','b58',pad='foo')),
-('pad arg (in)',    'BaseConversionPadError', "illegal value for 'pad'", lambda:fh('ff','b58',pad=False)),
-('pad arg (in)',    'BaseConversionPadError', "illegal value for 'pad'", lambda:fh('ff','b58',pad=True)),
-('seedlen (in)',    'SeedLengthError',        'invalid byte length',     lambda:fh('ff','b58',pad='seed')),
-('pad arg (out)',   'BaseConversionPadError', "illegal value for 'pad'", lambda:th('Z','b58',pad='foo')),
-('pad arg (out)',   'BaseConversionPadError', "illegal value for 'pad'", lambda:th('Z','b58',pad=False)),
-('pad arg (out)',   'BaseConversionPadError', "illegal value for 'pad'", lambda:th('Z','b58',pad=True)),
-('seedlen (out)',   'BaseConversionError',    'invalid length for seed', lambda:th('Z','b58',pad='seed')),
+('hexstr',          'HexadecimalStringError', ': not a hexadecimal str', lambda:fr58('x')),
+('hexstr (seed)',   'HexadecimalStringError', 'seed data not a hexadec', lambda:fr58('x',pad='seed')),
+('hexstr (empty)',  'BaseConversionError',    'empty data not allowed',  lambda:fr58('')),
+('b58 data',        'BaseConversionError',    ': not in base58',         lambda:to58('IfFzZ')),
+('b58 data (seed)', 'BaseConversionError',    'seed data not in base58', lambda:to58(bad_b58,pad='seed')),
+('b58 len (seed)',  'BaseConversionError',    'invalid length for',      lambda:to58(bad_b58len,pad='seed')),
+('b58 data (empty)','BaseConversionError',    'empty base58 data',       lambda:to58('')),
+('b8 data (empty)' ,'BaseConversionError',    'empty base8 string data', lambda:to8('')),
+('b32 data',        'BaseConversionError',    'not in MMGen base32',     lambda:to32('1az')),
+('pad arg (in)',    'BaseConversionPadError', "illegal value for 'pad'", lambda:fr58('ff',pad='foo')),
+('pad arg (in)',    'BaseConversionPadError', "illegal value for 'pad'", lambda:fr58('ff',pad=False)),
+('pad arg (in)',    'BaseConversionPadError', "illegal value for 'pad'", lambda:fr58('ff',pad=True)),
+('seedlen (in)',    'SeedLengthError',        'invalid byte length',     lambda:fr58('ff',pad='seed')),
+('pad arg (out)',   'BaseConversionPadError', "illegal value for 'pad'", lambda:to58('Z',pad='foo')),
+('pad arg (out)',   'BaseConversionPadError', "illegal value for 'pad'", lambda:to58('Z',pad=False)),
+('pad arg (out)',   'BaseConversionPadError', "illegal value for 'pad'", lambda:to58('Z',pad=True)),
+('seedlen (out)',   'BaseConversionError',    'invalid length for seed', lambda:to58('Z',pad='seed')),
 		)
 		)
 
 
 		ut.process_bad_data(bad_data)
 		ut.process_bad_data(bad_data)

+ 15 - 17
test/unit_tests_d/ut_bip39.py

@@ -90,15 +90,15 @@ class unit_test(object):
 
 
 		from mmgen.bip39 import bip39
 		from mmgen.bip39 import bip39
 
 
-		bip39.check_wordlists()
-		bip39.check_wordlist('bip39')
+		b = bip39()
+		b.check_wordlist()
 
 
 		vmsg('')
 		vmsg('')
 		qmsg('Checking seed to mnemonic conversion:')
 		qmsg('Checking seed to mnemonic conversion:')
 		for v in self.vectors:
 		for v in self.vectors:
 			chk = tuple(v[1].split())
 			chk = tuple(v[1].split())
 			vmsg('    '+v[1])
 			vmsg('    '+v[1])
-			res = bip39.fromhex(v[0],'bip39')
+			res = b.fromhex( v[0] )
 			assert res == chk, f'mismatch:\nres: {res}\nchk: {chk}'
 			assert res == chk, f'mismatch:\nres: {res}\nchk: {chk}'
 
 
 		vmsg('')
 		vmsg('')
@@ -106,7 +106,7 @@ class unit_test(object):
 		for v in self.vectors:
 		for v in self.vectors:
 			chk = v[0]
 			chk = v[0]
 			vmsg('    '+chk)
 			vmsg('    '+chk)
-			res = bip39.tohex(v[1].split(),'bip39')
+			res = b.tohex( v[1].split() )
 			assert res == chk, f'mismatch:\nres: {res}\nchk: {chk}'
 			assert res == chk, f'mismatch:\nres: {res}\nchk: {chk}'
 
 
 		vmsg('')
 		vmsg('')
@@ -119,20 +119,18 @@ class unit_test(object):
 		bad_seed = 'deadbeef'
 		bad_seed = 'deadbeef'
 		good_seed = 'deadbeef' * 4
 		good_seed = 'deadbeef' * 4
 
 
-		th = bip39.tohex
-		fh = bip39.fromhex
+		th = b.tohex
+		fh = b.fromhex
 		bad_data = (
 		bad_data = (
-('hex',              'AssertionError', 'not a hexadecimal',lambda:fh('xx','bip39')),
-('id (tohex)',       'AssertionError', "must be 'bip39'",  lambda:fh(good_seed,'foo')),
-('seed len',         'AssertionError', 'invalid seed bit', lambda:fh(bad_seed,'bip39')),
-('mnemonic type',    'AssertionError', 'must be list',     lambda:th('string','bip39')),
-('id (fromhex)',     'AssertionError', "must be 'bip39'",  lambda:th(good_mn,'foo')),
-('arg (tostr=True)', 'AssertionError', "'tostr' must be",  lambda:fh(good_seed,'bip39',tostr=True)),
-('pad len (fromhex)','AssertionError', "invalid 'pad' arg",lambda:fh(good_seed,'bip39',pad=23)),
-('pad len (tohex)',  'AssertionError', "invalid 'pad' arg",lambda:th(good_mn,'bip39',pad=23)),
-('word',             'MnemonicError',  "not in the BIP39", lambda:th(bad_word_mn,'bip39')),
-('checksum',         'MnemonicError',  "checksum",         lambda:th(bad_chksum_mn,'bip39')),
-('seed phrase len',  'MnemonicError',  "phrase len",       lambda:th(bad_len_mn,'bip39')),
+('hex',              'AssertionError', 'not a hexadecimal',lambda:fh('xx')),
+('seed len',         'AssertionError', 'invalid seed bit', lambda:fh(bad_seed)),
+('mnemonic type',    'AssertionError', 'must be list',     lambda:th('string')),
+('arg (tostr=True)', 'AssertionError', "'tostr' must be",  lambda:fh(good_seed,tostr=True)),
+('pad len (fromhex)','AssertionError', "invalid 'pad' arg",lambda:fh(good_seed,pad=23)),
+('pad len (tohex)',  'AssertionError', "invalid 'pad' arg",lambda:th(good_mn,pad=23)),
+('word',             'MnemonicError',  "not in the BIP39", lambda:th(bad_word_mn)),
+('checksum',         'MnemonicError',  "checksum",         lambda:th(bad_chksum_mn)),
+('seed phrase len',  'MnemonicError',  "phrase len",       lambda:th(bad_len_mn)),
 		)
 		)
 
 
 		ut.process_bad_data(bad_data)
 		ut.process_bad_data(bad_data)

+ 1 - 1
test/unit_tests_d/ut_rpc.py

@@ -139,7 +139,7 @@ class unit_tests:
 					'restore_deterministic_wallet',
 					'restore_deterministic_wallet',
 					filename = fn,
 					filename = fn,
 					password = 'foo',
 					password = 'foo',
-					seed     = baseconv.fromhex('beadface'*8,'xmrseed',tostr=True) )
+					seed     = baseconv('xmrseed').fromhex('beadface'*8,tostr=True) )
 				qmsg(f'Opening {wd.network} wallet')
 				qmsg(f'Opening {wd.network} wallet')
 				await c.call( 'open_wallet', filename=fn, password='foo' )
 				await c.call( 'open_wallet', filename=fn, password='foo' )