Browse Source

baseconv: minor cleanups & fixes (import, init_mn)

The MMGen Project 6 years ago
parent
commit
f1e7cbb7a0
6 changed files with 38 additions and 28 deletions
  1. 27 18
      mmgen/baseconv.py
  2. 4 1
      mmgen/bip39.py
  3. 2 1
      mmgen/protocol.py
  4. 3 5
      mmgen/seed.py
  5. 2 1
      mmgen/tx.py
  6. 0 2
      mmgen/util.py

+ 27 - 18
mmgen/baseconv.py

@@ -29,50 +29,53 @@ def is_b32_str(s): return set(list(s)) <= set(baseconv.digits['b32'])
 class baseconv(object):
 class baseconv(object):
 
 
 	desc = {
 	desc = {
-		'b58':   ('base58',               'base58-encoded data'),
-		'b32':   ('MMGen base32',         'MMGen base32-encoded data created using simple base conversion'),
-		'b16':   ('hexadecimal string',   'base16 (hexadecimal) string data'),
-		'b10':   ('base10 string',        'base10 (decimal) string data'),
-		'b8':    ('base8 string',         'base8 (octal) string data'),
-		'b6d':   ('base6d (die roll)',    'base6 data using the digits from one to six'),
+		'b58':   ('base58',            'base58-encoded data'),
+		'b32':   ('MMGen base32',      'MMGen base32-encoded data created using simple base conversion'),
+		'b16':   ('hexadecimal string','base16 (hexadecimal) string data'),
+		'b10':   ('base10 string',     'base10 (decimal) string data'),
+		'b8':    ('base8 string',      'base8 (octal) string data'),
+		'b6d':   ('base6d (die roll)', 'base6 data using the digits from one to six'),
+		'tirosh':('Tirosh mnemonic',   'base1626 mnemonic using truncated Tirosh wordlist'), # not used by wallet
 		'mmgen': ('MMGen native mnemonic',
 		'mmgen': ('MMGen native mnemonic',
 		'MMGen native mnemonic seed phrase data created using old Electrum wordlist and simple base conversion'),
 		'MMGen native mnemonic seed phrase data created using old Electrum wordlist and simple base conversion'),
 	}
 	}
+	# https://en.wikipedia.org/wiki/Base32#RFC_4648_Base32_alphabet
+	# https://tools.ietf.org/html/rfc4648
 	digits = {
 	digits = {
 		'b58': tuple('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'),
 		'b58': tuple('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'),
-		'b32': tuple('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'),
+		'b32': tuple('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'), # RFC 4648 alphabet
 		'b16': tuple('0123456789abcdef'),
 		'b16': tuple('0123456789abcdef'),
 		'b10': tuple('0123456789'),
 		'b10': tuple('0123456789'),
 		'b8':  tuple('01234567'),
 		'b8':  tuple('01234567'),
 		'b6d': tuple('123456'),
 		'b6d': tuple('123456'),
 	}
 	}
 	mn_base = 1626 # tirosh list is 1633 words long!
 	mn_base = 1626 # tirosh list is 1633 words long!
-	mn_ids = ('mmgen','tirosh')
 	wl_chksums = {
 	wl_chksums = {
 		'mmgen':  '5ca31424',
 		'mmgen':  '5ca31424',
 		'tirosh': '48f05e1f', # tirosh truncated to mn_base (1626)
 		'tirosh': '48f05e1f', # tirosh truncated to mn_base (1626)
 		# 'tirosh1633': '1a5faeff'
 		# 'tirosh1633': '1a5faeff'
 	}
 	}
-	seed_pad_lens = {
+	seedlen_map = {
 		'b58': { 16:22, 24:33, 32:44 },
 		'b58': { 16:22, 24:33, 32:44 },
 		'b6d': { 16:50, 24:75, 32:100 },
 		'b6d': { 16:50, 24:75, 32:100 },
 	}
 	}
-	seed_pad_lens_rev = {
+	seedlen_map_rev = {
 		'b58': { 22:16, 33:24, 44:32 },
 		'b58': { 22:16, 33:24, 44:32 },
 		'b6d': { 50:16, 75:24, 100:32 },
 		'b6d': { 50:16, 75:24, 100:32 },
 	}
 	}
 
 
 	@classmethod
 	@classmethod
 	def init_mn(cls,mn_id):
 	def init_mn(cls,mn_id):
-		assert mn_id in cls.mn_ids
+		if mn_id in cls.digits:
+			return
 		if mn_id == 'mmgen':
 		if mn_id == 'mmgen':
 			from mmgen.mn_electrum import words
 			from mmgen.mn_electrum import words
 			cls.digits[mn_id] = words
 			cls.digits[mn_id] = words
 		elif mn_id == 'tirosh':
 		elif mn_id == 'tirosh':
 			from mmgen.mn_tirosh import words
 			from mmgen.mn_tirosh import words
 			cls.digits[mn_id] = words[:cls.mn_base]
 			cls.digits[mn_id] = words[:cls.mn_base]
-		else: # bip39
-			cls.digits[mn_id] = cls.words
+		else:
+			raise ValueError('{}: unrecognized mnemonic ID'.format(mn_id))
 
 
 	@classmethod
 	@classmethod
 	def get_wordlist(cls,wl_id):
 	def get_wordlist(cls,wl_id):
@@ -109,7 +112,7 @@ class baseconv(object):
 		"""
 		"""
 		'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.
-		If 'seed', output length will be mapped from input length using data in seed_pad_lens.
+		If 'seed', output length will be mapped from input length using data in seedlen_map.
 		If an integer, the string, hex string or byte output will be padded to this length.
 		If an integer, the string, hex string or byte output will be padded to this length.
 		"""
 		"""
 		if pad == None:
 		if pad == None:
@@ -131,6 +134,9 @@ class baseconv(object):
 	def tobytes(cls,words_arg,wl_id,pad=None):
 	def tobytes(cls,words_arg,wl_id,pad=None):
 		"convert string or list data of base 'wl_id' to byte string"
 		"convert string or list data of base 'wl_id' to byte string"
 
 
+		if wl_id not in cls.digits:
+			cls.init_mn(wl_id)
+
 		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 = cls.desc[wl_id][0]
 
 
@@ -138,8 +144,8 @@ class baseconv(object):
 			raise BaseConversionError('empty {} data'.format(desc))
 			raise BaseConversionError('empty {} data'.format(desc))
 
 
 		def get_seed_pad():
 		def get_seed_pad():
-			assert wl_id in cls.seed_pad_lens_rev,'seed padding not supported for base {!r}'.format(wl_id)
-			d = cls.seed_pad_lens_rev[wl_id]
+			assert wl_id in cls.seedlen_map_rev,'seed padding not supported for base {!r}'.format(wl_id)
+			d = cls.seedlen_map_rev[wl_id]
 			if not len(words) in d:
 			if not len(words) in d:
 				m = '{}: invalid length for seed-padded {} data in base conversion'
 				m = '{}: invalid length for seed-padded {} data in base conversion'
 				raise BaseConversionError(m.format(len(words),desc))
 				raise BaseConversionError(m.format(len(words),desc))
@@ -172,12 +178,15 @@ class baseconv(object):
 	def frombytes(cls,bytestr,wl_id,pad=None,tostr=False):
 	def frombytes(cls,bytestr,wl_id,pad=None,tostr=False):
 		"convert byte string to list or string data of base 'wl_id'"
 		"convert byte string to list or string data of base 'wl_id'"
 
 
+		if wl_id not in cls.digits:
+			cls.init_mn(wl_id)
+
 		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.seed_pad_lens,'seed padding not supported for base {!r}'.format(wl_id)
-			d = cls.seed_pad_lens[wl_id]
+			assert wl_id in cls.seedlen_map,'seed padding not supported for base {!r}'.format(wl_id)
+			d = cls.seedlen_map[wl_id]
 			if not len(bytestr) in d:
 			if not len(bytestr) in d:
 				m = '{}: invalid byte length for seed data in seed-padded base conversion'
 				m = '{}: invalid byte length for seed data in seed-padded base conversion'
 				raise SeedLengthError(m.format(len(bytestr)))
 				raise SeedLengthError(m.format(len(bytestr)))

+ 4 - 1
mmgen/bip39.py

@@ -2081,7 +2081,6 @@ zoo
 """.split())
 """.split())
 
 
 	mn_base = 2048
 	mn_base = 2048
-	mn_ids = ('bip39',)
 	wl_chksums = { 'bip39': 'f18b9a84' }
 	wl_chksums = { 'bip39': 'f18b9a84' }
 	#    ENT   CS  MS
 	#    ENT   CS  MS
 	constants = {
 	constants = {
@@ -2170,3 +2169,7 @@ zoo
 		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(mn_len))
 		return tuple(wl[int(res[i*11:(i+1)*11],2)] for i in range(mn_len))
+
+	@classmethod
+	def init_mn(cls,mn_id):
+		assert mn_id == 'bip39', "'mn_id' must be 'bip39'"

+ 2 - 1
mmgen/protocol.py

@@ -25,7 +25,6 @@ from mmgen.util import msg,ymsg,Msg,ydie
 from mmgen.obj import MMGenObject,BTCAmt,LTCAmt,BCHAmt,B2XAmt,ETHAmt
 from mmgen.obj import MMGenObject,BTCAmt,LTCAmt,BCHAmt,B2XAmt,ETHAmt
 from mmgen.globalvars import g
 from mmgen.globalvars import g
 import mmgen.bech32 as bech32
 import mmgen.bech32 as bech32
-from mmgen.baseconv import baseconv,is_b58_str
 
 
 def hash160(hexnum): # take hex, return hex - OP_HASH160
 def hash160(hexnum): # take hex, return hex - OP_HASH160
 	return hashlib.new('ripemd160',hashlib.sha256(bytes.fromhex(hexnum)).digest()).hexdigest()
 	return hashlib.new('ripemd160',hashlib.sha256(bytes.fromhex(hexnum)).digest()).hexdigest()
@@ -407,6 +406,8 @@ class MoneroProtocol(DummyWIF,BitcoinProtocolAddrgen):
 	@classmethod
 	@classmethod
 	def verify_addr(cls,addr,hex_width,return_dict=False):
 	def verify_addr(cls,addr,hex_width,return_dict=False):
 
 
+		from mmgen.baseconv import baseconv,is_b58_str
+
 		def b58dec(addr_str):
 		def b58dec(addr_str):
 			l = len(addr_str)
 			l = len(addr_str)
 			a = ''.join([baseconv.tohex(addr_str[i*11:i*11+11],'b58',pad=16) for i in range(l//11)])
 			a = ''.join([baseconv.tohex(addr_str[i*11:i*11+11],'b58',pad=16) for i in range(l//11)])

+ 3 - 5
mmgen/seed.py

@@ -825,10 +825,6 @@ class MMGenMnemonic(SeedSourceUnenc):
 	wl_id = 'mmgen'
 	wl_id = 'mmgen'
 	conv_cls = baseconv
 	conv_cls = baseconv
 
 
-	def __init__(self,*args,**kwargs):
-		self.conv_cls.init_mn(self.wl_id)
-		super().__init__(*args,**kwargs)
-
 	def _get_data_from_user(self,desc):
 	def _get_data_from_user(self,desc):
 
 
 		if not g.stdin_tty:
 		if not g.stdin_tty:
@@ -853,6 +849,7 @@ class MMGenMnemonic(SeedSourceUnenc):
 			if keypress_confirm(prompt,default_yes=True,no_nl=not g.test_suite):
 			if keypress_confirm(prompt,default_yes=True,no_nl=not g.test_suite):
 				break
 				break
 
 
+		self.conv_cls.init_mn(self.wl_id)
 		wl = self.conv_cls.digits[self.wl_id]
 		wl = self.conv_cls.digits[self.wl_id]
 		longest_word = max(len(w) for w in wl)
 		longest_word = max(len(w) for w in wl)
 		from string import ascii_lowercase
 		from string import ascii_lowercase
@@ -923,6 +920,7 @@ class MMGenMnemonic(SeedSourceUnenc):
 
 
 	def _deformat(self):
 	def _deformat(self):
 
 
+		self.conv_cls.init_mn(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:
@@ -1227,7 +1225,7 @@ class Wallet (SeedSourceEnc):
 			msg("Hash parameters '{}' don't match hash preset '{}'".format(' '.join(hash_params),d.hash_preset))
 			msg("Hash parameters '{}' don't match hash preset '{}'".format(' '.join(hash_params),d.hash_preset))
 			return False
 			return False
 
 
-		lmin,foo,lmax = sorted(baseconv.seed_pad_lens_rev['b58']) # 22,33,44
+		lmin,foo,lmax = sorted(baseconv.seedlen_map_rev['b58']) # 22,33,44
 		for i,key in (4,'salt'),(5,'enc_seed'):
 		for i,key in (4,'salt'),(5,'enc_seed'):
 			l = lines[i].split(' ')
 			l = lines[i].split(' ')
 			chk = l.pop(0)
 			chk = l.pop(0)

+ 2 - 1
mmgen/tx.py

@@ -24,7 +24,6 @@ import sys,os,json
 from stat import *
 from stat import *
 from mmgen.common import *
 from mmgen.common import *
 from mmgen.obj import *
 from mmgen.obj import *
-from mmgen.baseconv import *
 
 
 wmsg = lambda k: {
 wmsg = lambda k: {
 	'addr_in_addrfile_only': """
 	'addr_in_addrfile_only': """
@@ -699,6 +698,7 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
 			repr([amt_to_str(e.__dict__) for e in self.outputs])
 			repr([amt_to_str(e.__dict__) for e in self.outputs])
 		]
 		]
 		if self.label:
 		if self.label:
+			from mmgen.baseconv import baseconv
 			lines.append(baseconv.frombytes(self.label.encode(),'b58',tostr=True))
 			lines.append(baseconv.frombytes(self.label.encode(),'b58',tostr=True))
 		if self.coin_txid:
 		if self.coin_txid:
 			if not self.label: lines.append('-') # keep old tx files backwards compatible
 			if not self.label: lines.append('-') # keep old tx files backwards compatible
@@ -1215,6 +1215,7 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
 				c = tx_data.pop(-1)
 				c = tx_data.pop(-1)
 				if c != '-':
 				if c != '-':
 					desc = 'encoded comment (not base58)'
 					desc = 'encoded comment (not base58)'
+					from mmgen.baseconv import baseconv
 					comment = baseconv.tobytes(c,'b58').decode()
 					comment = baseconv.tobytes(c,'b58').decode()
 					assert comment != False,'invalid comment'
 					assert comment != False,'invalid comment'
 					desc = 'comment'
 					desc = 'comment'

+ 0 - 2
mmgen/util.py

@@ -264,8 +264,6 @@ def is_int(s):
 	except:
 	except:
 		return False
 		return False
 
 
-# https://en.wikipedia.org/wiki/Base32#RFC_4648_Base32_alphabet
-# https://tools.ietf.org/html/rfc4648
 def is_hex_str(s):    return set(list(s.lower())) <= set(list(hexdigits.lower()))
 def is_hex_str(s):    return set(list(s.lower())) <= set(list(hexdigits.lower()))
 def is_hex_str_lc(s): return set(list(s))         <= set(list(hexdigits.lower()))
 def is_hex_str_lc(s): return set(list(s))         <= set(list(hexdigits.lower()))
 def is_hex_str_uc(s): return set(list(s))         <= set(list(hexdigits.upper()))
 def is_hex_str_uc(s): return set(list(s))         <= set(list(hexdigits.upper()))