Browse Source

baseconv: tohex() -> tobytes(), fromhex() -> frombytes()

The MMGen Project 5 years ago
parent
commit
bec3dfeed2
2 changed files with 25 additions and 17 deletions
  1. 24 16
      mmgen/util.py
  2. 1 1
      test/unit_tests_d/ut_baseconv.py

+ 24 - 16
mmgen/util.py

@@ -349,7 +349,7 @@ class baseconv(object):
 		'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 'seed', output length will be mapped from input length using data in seed_pad_lens.
-		If an integer, it refers to the minimum allowable *string length* of the output.
+		If an integer, the string, hex string or byte output will be padded to this length.
 		"""
 		if pad == None:
 			return 0
@@ -364,6 +364,11 @@ class baseconv(object):
 	@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()
+
+	@classmethod
+	def tobytes(cls,words_arg,wl_id,pad=None):
+		"convert string or list data of base 'wl_id' to byte string"
 
 		words = words_arg if isinstance(words_arg,(list,tuple)) else tuple(words_arg.strip())
 
@@ -376,9 +381,9 @@ class baseconv(object):
 			if not len(words) in d:
 				m = '{}: invalid length for seed-padded {} data in base conversion'
 				raise BaseConversionError(m.format(len(words),wl_id))
-			return d[len(words)] * 2
+			return d[len(words)]
 
-		pad_val = max(cls.get_pad(pad,get_seed_pad),2)
+		pad_val = max(cls.get_pad(pad,get_seed_pad),1)
 		wl = cls.digits[wl_id]
 		base = len(wl)
 
@@ -386,38 +391,41 @@ class baseconv(object):
 			m = ('{w!r}:','seed data')[pad=='seed'] + ' not in {i} (base{b}) format'
 			raise BaseConversionError(m.format(w=words_arg,i=wl_id,b=base))
 
-		deconv =  [wl.index(words[::-1][i])*(base**i) for i in range(len(words))]
-		ret = ('{:0{w}x}'.format(sum(deconv),w=pad_val))
-		return (('','0')[len(ret) % 2] + ret)
+		ret = sum([wl.index(words[::-1][i])*(base**i) for i in range(len(words))])
+		bl = ret.bit_length()
+		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'"
-		if wl_id in ('mmgen','tirosh','bip39'):
-			assert tostr == False,"'tostr' must be False for '{}'".format(wl_id)
 
 		if not is_hex_str(hexstr):
 			m = ('{h!r}:','seed data')[pad=='seed'] + ' not a hexadecimal string'
 			raise HexadecimalStringError(m.format(h=hexstr))
 
-		if not hexstr:
-			m = 'empty hex strings not allowed in base conversion'
-			raise HexadecimalStringError(m)
+		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'"
+
+		if not bytestr:
+			raise BaseConversionError('empty data not allowed in base conversion')
 
 		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]
-			slen = len(hexstr) // 2
-			if not slen in d:
+			if not len(bytestr) in d:
 				m = '{}: invalid seed byte length for seed-padded base conversion'
-				raise SeedLengthError(m.format(slen))
-			return d[slen]
+				raise SeedLengthError(m.format(len(bytestr)))
+			return d[len(bytestr)]
 
 		pad = max(cls.get_pad(pad,get_seed_pad),1)
 		wl = cls.digits[wl_id]
 		base = len(wl)
 
-		num,ret = int(hexstr,16),[]
+		num = int.from_bytes(bytestr,'big')
+		ret = []
 		while num:
 			ret.append(num % base)
 			num //= base

+ 1 - 1
test/unit_tests_d/ut_baseconv.py

@@ -156,7 +156,7 @@ class unit_test(object):
 		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)',  'HexadecimalStringError', 'empty hex strings not',   lambda:fh('','b58')),
+('hexstr (empty)',  'BaseConversionError',    'empty data not allowed',  lambda:fh('','b58')),
 ('b58 data',        'BaseConversionError',    ': not in b58',            lambda:th('IfFzZ','b58')),
 ('b58 data (seed)', 'BaseConversionError',    'seed data not in b58',    lambda:th(bad_b58,'b58',pad='seed')),
 ('b58 len (seed)',  'BaseConversionError',    'invalid length for',      lambda:th(bad_b58len,'b58',pad='seed')),