ut_baseconv.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #!/usr/bin/env python3
  2. """
  3. test/unit_tests_d/ut_baseconv.py: Base conversion unit test for the MMGen suite
  4. """
  5. from mmgen.common import *
  6. from mmgen.exception import *
  7. class unit_test(object):
  8. vectors = {
  9. 'b58': (
  10. (('00',None),'1'),
  11. (('00',1),'1'),
  12. (('00',2),'11'),
  13. (('01',None),'2'),
  14. (('01',1),'2'),
  15. (('01',2),'12'),
  16. (('0f',None),'G'),
  17. (('0f',1),'G'),
  18. (('0f',2),'1G'),
  19. (('deadbeef',None),'6h8cQN'),
  20. (('deadbeef',20),'111111111111116h8cQN'),
  21. (('00000000',None),'1'),
  22. (('00000000',20),'11111111111111111111'),
  23. (('ffffffff',None),'7YXq9G'),
  24. (('ffffffff',20),'111111111111117YXq9G'),
  25. (('ff'*16,'seed'),'YcVfxkQb6JRzqk5kF2tNLv'),
  26. (('ff'*24,'seed'),'QLbz7JHiBTspS962RLKV8GndWFwiEaqKL'),
  27. (('ff'*32,'seed'),'JEKNVnkbo3jma5nREBBJCDoXFVeKkD56V3xKrvRmWxFG'),
  28. (('00'*16,'seed'),'1111111111111111111111'),
  29. (('00'*24,'seed'),'111111111111111111111111111111111'),
  30. (('00'*32,'seed'),'11111111111111111111111111111111111111111111'),
  31. ),
  32. # MMGen-flavored base32 using simple base conversion
  33. 'b32': (
  34. (('00',None),'A'),
  35. (('00',1),'A'),
  36. (('00',2),'AA'),
  37. (('01',None),'B'),
  38. (('01',1),'B'),
  39. (('01',2),'AB'),
  40. (('0f',None),'P'),
  41. (('0f',1),'P'),
  42. (('0f',2),'AP'),
  43. (('deadbeef',None),'DPK3PXP'),
  44. (('deadbeef',20),'AAAAAAAAAAAAADPK3PXP'),
  45. (('00000000',None),'A'),
  46. (('00000000',20),'AAAAAAAAAAAAAAAAAAAA'),
  47. (('ffffffff',None),'D777777'),
  48. (('ffffffff',20),'AAAAAAAAAAAAAD777777'),
  49. ),
  50. 'b16': (
  51. (('00',None),'0'),
  52. (('00',1),'0'),
  53. (('00',2),'00'),
  54. (('01',None),'1'),
  55. (('01',1),'1'),
  56. (('01',2),'01'),
  57. (('0f',None),'f'),
  58. (('0f',1),'f'),
  59. (('0f',2),'0f'),
  60. (('deadbeef',None),'deadbeef'),
  61. (('deadbeef',20),'000000000000deadbeef'),
  62. (('00000000',None),'0'),
  63. (('00000000',20),'00000000000000000000'),
  64. (('ffffffff',None),'ffffffff'),
  65. (('ffffffff',20),'000000000000ffffffff'),
  66. ),
  67. 'b10': (
  68. (('00',None),'0'),
  69. (('00',1),'0'),
  70. (('00',2),'00'),
  71. (('01',None),'1'),
  72. (('01',1),'1'),
  73. (('01',2),'01'),
  74. (('0f',None),'15'),
  75. (('0f',1),'15'),
  76. (('0f',2),'15'),
  77. (('deadbeef',None),'3735928559'),
  78. (('deadbeef',20),'00000000003735928559'),
  79. (('00000000',None),'0'),
  80. (('00000000',20),'00000000000000000000'),
  81. (('ffffffff',None),'4294967295'),
  82. (('ffffffff',20),'00000000004294967295'),
  83. ),
  84. 'b8': (
  85. (('00',None),'0'),
  86. (('00',1),'0'),
  87. (('00',2),'00'),
  88. (('01',None),'1'),
  89. (('01',1),'1'),
  90. (('01',2),'01'),
  91. (('0f',None),'17'),
  92. (('0f',1),'17'),
  93. (('0f',2),'17'),
  94. (('deadbeef',None),'33653337357'),
  95. (('deadbeef',20),'00000000033653337357'),
  96. (('00000000',None),'0'),
  97. (('00000000',20),'00000000000000000000'),
  98. (('ffffffff',None),'37777777777'),
  99. (('ffffffff',20),'00000000037777777777'),
  100. ),
  101. }
  102. def run_test(self,name,ut):
  103. msg_r('Testing base conversion routines...')
  104. from mmgen.util import baseconv
  105. perr = "length of {!r} less than pad length ({})"
  106. rerr = "return value ({!r}) does not match reference value ({!r})"
  107. qmsg_r('\nChecking hex-to-base conversion:')
  108. for base,data in self.vectors.items():
  109. fs = " {h:%s} {p:<6} {r}" % max(len(d[0][0]) for d in data)
  110. if not opt.verbose: qmsg_r(' {}'.format(base))
  111. vmsg('\nBase: {}'.format(base))
  112. vmsg(fs.format(h='Input',p='Pad',r='Output'))
  113. for (hexstr,pad),ret_chk in data:
  114. ret = baseconv.fromhex(hexstr,wl_id=base,pad=pad,tostr=True)
  115. if pad != 'seed':
  116. assert len(ret) >= (pad or 0), perr.format(ret,pad or 0)
  117. assert ret == ret_chk, rerr.format(ret,ret_chk)
  118. vmsg(fs.format(h=hexstr,r=ret,p=str(pad)))
  119. # msg("(('{h}',{p}),'{r}'),".format(h=hexstr,r=ret,c=ret_chk,p=pad))
  120. # msg('')
  121. # return True
  122. qmsg_r('\nChecking base-to-hex conversion:')
  123. for base,data in self.vectors.items():
  124. fs = " {h:%s} {p:<6} {r}" % max(len(d[1]) for d in data)
  125. if not opt.verbose: qmsg_r(' {}'.format(base))
  126. vmsg('\nBase: {}'.format(base))
  127. vmsg(fs.format(h='Input',p='Pad',r='Output'))
  128. for (hexstr,pad),ret_chk in data:
  129. if type(pad) == int:
  130. pad = len(hexstr)
  131. ret = baseconv.tohex(ret_chk,wl_id=base,pad=pad)
  132. if pad == None:
  133. assert int(ret,16) == int(hexstr,16), rerr.format(int(ret,16),int(hexstr,16))
  134. else:
  135. assert ret == hexstr, rerr.format(ret,hexstr)
  136. vmsg(fs.format(h=ret_chk,r=ret,p=str(pad)))
  137. # msg("(('{h}',{p}),'{r}'),".format(h=hexstr,r=ret_chk,c=ret_chk,p=pad))
  138. qmsg('')
  139. vmsg('')
  140. qmsg('Checking error handling:')
  141. b = baseconv
  142. bad_data = (
  143. ('bad hexstr', 'HexadecimalStringError','not a hexadecimal str', lambda:b.fromhex('x','b58')),
  144. ('empty hexstr', 'HexadecimalStringError','empty hex strings not', lambda:b.fromhex('','b58')),
  145. ('bad b58 data', 'BaseConversionError', 'not in b58', lambda:b.tohex('IfFzZ','b58')),
  146. ('empty b58 data', 'BaseConversionError', 'empty b58 data', lambda:b.tohex('','b58')),
  147. ('empty b8 data' , 'BaseConversionError', 'empty b8 data', lambda:b.tohex('','b8')),
  148. ('bad b32 data', 'BaseConversionError', 'not in b32', lambda:b.tohex('1az','b32')),
  149. ('bad pad arg (in)', 'BaseConversionPadError',"illegal value for 'pad'", lambda:b.fromhex('ff','b58',pad='foo')),
  150. ('bad pad arg (in)', 'BaseConversionPadError',"illegal value for 'pad'", lambda:b.fromhex('ff','b58',pad=False)),
  151. ('bad pad arg (in)', 'BaseConversionPadError',"illegal value for 'pad'", lambda:b.fromhex('ff','b58',pad=True)),
  152. ('bad seedlen (in)', 'SeedLengthError', "invalid seed byte length",lambda:b.fromhex('ff','b58',pad='seed')),
  153. ('bad pad arg (out)','BaseConversionPadError',"illegal value for 'pad'", lambda:b.tohex('Z','b58',pad='foo')),
  154. ('bad pad arg (out)','BaseConversionPadError',"illegal value for 'pad'", lambda:b.tohex('Z','b58',pad=False)),
  155. ('bad pad arg (out)','BaseConversionPadError',"illegal value for 'pad'", lambda:b.tohex('Z','b58',pad=True)),
  156. ('bad seedlen (out)','BaseConversionError', "invalid length for seed", lambda:b.tohex('Z','b58',pad='seed')),
  157. )
  158. ut.process_bad_data(bad_data)
  159. msg('OK')
  160. return True