ut_baseconv.py 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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. 'xmrseed': (
  10. # 42nsXK8WbVGTNayQ6Kjw5UdgqbQY5KCCufdxdCgF7NgTfjC69Mna7DJSYyie77hZTQ8H92G2HwgFhgEUYnDzrnLnQdF28r3
  11. (('0000000000000000000000000000000000000000000000000000000000000001','seed'), # 0x1
  12. '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'),
  13. # 49voQEbjouUQSDikRWKUt1PGbS47TBde4hiGyftN46CvTDd8LXCaimjHRGtofCJwY5Ed5QhYwc12P15AH5w7SxUAMCz1nr1
  14. (('1c95988d7431ecd670cf7d73f45befc6feffffffffffffffffffffffffffff0f','seed'), # 0xffffffff * 8
  15. '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'),
  16. # 41i7saPWA53EoHenmJVRt34dubPxsXwoWMnw8AdMyx4mTD1svf7qYzcVjxxRfteLNdYrAxWUMmiPegFW9EfoNgXx7vDMExv
  17. (('e8164dda6d42bd1e261a3406b2038dcbddadbeefdeadbeefdeadbeefdeadbe0f','seed'), # 0xdeadbeef * 8
  18. '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'),
  19. # 42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm
  20. (('148d78d2aba7dbca5cd8f6abcfb0b3c009ffbdbea1ff373d50ed94d78286640e','seed'), # Monero repo
  21. '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'),
  22. ),
  23. 'b58': (
  24. (('00',None),'1'),
  25. (('00',1),'1'),
  26. (('00',2),'11'),
  27. (('01',None),'2'),
  28. (('01',1),'2'),
  29. (('01',2),'12'),
  30. (('0f',None),'G'),
  31. (('0f',1),'G'),
  32. (('0f',2),'1G'),
  33. (('deadbeef',None),'6h8cQN'),
  34. (('deadbeef',20),'111111111111116h8cQN'),
  35. (('00000000',None),'1'),
  36. (('00000000',20),'11111111111111111111'),
  37. (('ffffffff',None),'7YXq9G'),
  38. (('ffffffff',20),'111111111111117YXq9G'),
  39. (('ff'*16,'seed'),'YcVfxkQb6JRzqk5kF2tNLv'),
  40. (('ff'*24,'seed'),'QLbz7JHiBTspS962RLKV8GndWFwiEaqKL'),
  41. (('ff'*32,'seed'),'JEKNVnkbo3jma5nREBBJCDoXFVeKkD56V3xKrvRmWxFG'),
  42. (('00'*16,'seed'),'1111111111111111111111'),
  43. (('00'*24,'seed'),'111111111111111111111111111111111'),
  44. (('00'*32,'seed'),'11111111111111111111111111111111111111111111'),
  45. ),
  46. # MMGen-flavored base32 using simple base conversion
  47. 'b32': (
  48. (('00',None),'A'),
  49. (('00',1),'A'),
  50. (('00',2),'AA'),
  51. (('01',None),'B'),
  52. (('01',1),'B'),
  53. (('01',2),'AB'),
  54. (('0f',None),'P'),
  55. (('0f',1),'P'),
  56. (('0f',2),'AP'),
  57. (('deadbeef',None),'DPK3PXP'),
  58. (('deadbeef',20),'AAAAAAAAAAAAADPK3PXP'),
  59. (('00000000',None),'A'),
  60. (('00000000',20),'AAAAAAAAAAAAAAAAAAAA'),
  61. (('ffffffff',None),'D777777'),
  62. (('ffffffff',20),'AAAAAAAAAAAAAD777777'),
  63. ),
  64. 'b16': (
  65. (('00',None),'0'),
  66. (('00',1),'0'),
  67. (('00',2),'00'),
  68. (('01',None),'1'),
  69. (('01',1),'1'),
  70. (('01',2),'01'),
  71. (('0f',None),'f'),
  72. (('0f',1),'f'),
  73. (('0f',2),'0f'),
  74. (('deadbeef',None),'deadbeef'),
  75. (('deadbeef',20),'000000000000deadbeef'),
  76. (('00000000',None),'0'),
  77. (('00000000',20),'00000000000000000000'),
  78. (('ffffffff',None),'ffffffff'),
  79. (('ffffffff',20),'000000000000ffffffff'),
  80. ),
  81. 'b10': (
  82. (('00',None),'0'),
  83. (('00',1),'0'),
  84. (('00',2),'00'),
  85. (('01',None),'1'),
  86. (('01',1),'1'),
  87. (('01',2),'01'),
  88. (('0f',None),'15'),
  89. (('0f',1),'15'),
  90. (('0f',2),'15'),
  91. (('deadbeef',None),'3735928559'),
  92. (('deadbeef',20),'00000000003735928559'),
  93. (('00000000',None),'0'),
  94. (('00000000',20),'00000000000000000000'),
  95. (('ffffffff',None),'4294967295'),
  96. (('ffffffff',20),'00000000004294967295'),
  97. ),
  98. 'b8': (
  99. (('00',None),'0'),
  100. (('00',1),'0'),
  101. (('00',2),'00'),
  102. (('01',None),'1'),
  103. (('01',1),'1'),
  104. (('01',2),'01'),
  105. (('0f',None),'17'),
  106. (('0f',1),'17'),
  107. (('0f',2),'17'),
  108. (('deadbeef',None),'33653337357'),
  109. (('deadbeef',20),'00000000033653337357'),
  110. (('00000000',None),'0'),
  111. (('00000000',20),'00000000000000000000'),
  112. (('ffffffff',None),'37777777777'),
  113. (('ffffffff',20),'00000000037777777777'),
  114. ),
  115. 'b6d': (
  116. (('00',None),'1'),
  117. (('00',1),'1'),
  118. (('00',2),'11'),
  119. (('01',None),'2'),
  120. (('01',1),'2'),
  121. (('01',2),'12'),
  122. (('0f',None),'34'),
  123. (('0f',1),'34'),
  124. (('0f',2),'34'),
  125. (('010f',None),'2242'),
  126. (('010f',20),'11111111111111112242'),
  127. (('deadbeef',None),'2525524636426'),
  128. (('deadbeef',20),'11111112525524636426'),
  129. (('00000000',None),'1'),
  130. (('00000000',20),'11111111111111111111'),
  131. (('ffffffff',None),'2661215126614'),
  132. (('ffffffff',20),'11111112661215126614'),
  133. (('ff'*16,'seed'),'34164464641266661652465154654653354436664555521414'),
  134. (('ff'*24,'seed'),'246111411433323364222465566552324652566121541623426135163525451613554313654'),
  135. (('ff'*32,'seed'),'2132521653312613134145131423465414636252114131225324246311141642456513416322412146151432142242565134'),
  136. (('00'*16,'seed'),'1'*50),
  137. (('00'*24,'seed'),'1'*75),
  138. (('00'*32,'seed'),'1'*100),
  139. ),
  140. }
  141. def run_test(self,name,ut):
  142. msg_r('Testing base conversion routines...')
  143. from mmgen.baseconv import baseconv
  144. perr = "length of {!r} less than pad length ({})"
  145. rerr = "return value ({!r}) does not match reference value ({!r})"
  146. qmsg_r('\nChecking hex-to-base conversion:')
  147. for base,data in self.vectors.items():
  148. fs = " {h:%s} {p:<6} {r}" % max(len(d[0][0]) for d in data)
  149. if not opt.verbose: qmsg_r(' {}'.format(base))
  150. vmsg('\nBase: {}'.format(base))
  151. vmsg(fs.format(h='Input',p='Pad',r='Output'))
  152. for (hexstr,pad),ret_chk in data:
  153. ret = baseconv.fromhex(hexstr,wl_id=base,pad=pad,tostr=True)
  154. if pad != 'seed':
  155. assert len(ret) >= (pad or 0), perr.format(ret,pad or 0)
  156. assert ret == ret_chk, rerr.format(ret,ret_chk)
  157. vmsg(fs.format(h=hexstr,r=ret,p=str(pad)))
  158. # msg("(('{h}',{p}),'{r}'),".format(h=hexstr,r=ret,c=ret_chk,p=pad))
  159. # msg('')
  160. # return True
  161. qmsg_r('\nChecking base-to-hex conversion:')
  162. for base,data in self.vectors.items():
  163. fs = " {h:%s} {p:<6} {r}" % max(len(d[1]) for d in data)
  164. if not opt.verbose: qmsg_r(' {}'.format(base))
  165. vmsg('\nBase: {}'.format(base))
  166. vmsg(fs.format(h='Input',p='Pad',r='Output'))
  167. for (hexstr,pad),ret_chk in data:
  168. if type(pad) == int:
  169. pad = len(hexstr)
  170. ret = baseconv.tohex(
  171. ret_chk.split() if base == 'xmrseed' else ret_chk,
  172. wl_id=base,
  173. pad=pad)
  174. if pad == None:
  175. assert int(ret,16) == int(hexstr,16), rerr.format(int(ret,16),int(hexstr,16))
  176. else:
  177. assert ret == hexstr, rerr.format(ret,hexstr)
  178. vmsg(fs.format(h=ret_chk,r=ret,p=str(pad)))
  179. # msg("(('{h}',{p}),'{r}'),".format(h=hexstr,r=ret_chk,c=ret_chk,p=pad))
  180. qmsg('')
  181. vmsg('')
  182. qmsg('Checking error handling:')
  183. bad_b58 = 'I'*22
  184. bad_b58len = 'a'*23
  185. th = baseconv.tohex
  186. fh = baseconv.fromhex
  187. bad_data = (
  188. ('hexstr', 'HexadecimalStringError', ': not a hexadecimal str', lambda:fh('x','b58')),
  189. ('hexstr (seed)', 'HexadecimalStringError', 'seed data not a hexadec', lambda:fh('x','b58',pad='seed')),
  190. ('hexstr (empty)', 'BaseConversionError', 'empty data not allowed', lambda:fh('','b58')),
  191. ('b58 data', 'BaseConversionError', ': not in base58', lambda:th('IfFzZ','b58')),
  192. ('b58 data (seed)', 'BaseConversionError', 'seed data not in base58', lambda:th(bad_b58,'b58',pad='seed')),
  193. ('b58 len (seed)', 'BaseConversionError', 'invalid length for', lambda:th(bad_b58len,'b58',pad='seed')),
  194. ('b58 data (empty)','BaseConversionError', 'empty base58 data', lambda:th('','b58')),
  195. ('b8 data (empty)' ,'BaseConversionError', 'empty base8 string data', lambda:th('','b8')),
  196. ('b32 data', 'BaseConversionError', 'not in MMGen base32', lambda:th('1az','b32')),
  197. ('pad arg (in)', 'BaseConversionPadError', "illegal value for 'pad'", lambda:fh('ff','b58',pad='foo')),
  198. ('pad arg (in)', 'BaseConversionPadError', "illegal value for 'pad'", lambda:fh('ff','b58',pad=False)),
  199. ('pad arg (in)', 'BaseConversionPadError', "illegal value for 'pad'", lambda:fh('ff','b58',pad=True)),
  200. ('seedlen (in)', 'SeedLengthError', 'invalid byte length', lambda:fh('ff','b58',pad='seed')),
  201. ('pad arg (out)', 'BaseConversionPadError', "illegal value for 'pad'", lambda:th('Z','b58',pad='foo')),
  202. ('pad arg (out)', 'BaseConversionPadError', "illegal value for 'pad'", lambda:th('Z','b58',pad=False)),
  203. ('pad arg (out)', 'BaseConversionPadError', "illegal value for 'pad'", lambda:th('Z','b58',pad=True)),
  204. ('seedlen (out)', 'BaseConversionError', 'invalid length for seed', lambda:th('Z','b58',pad='seed')),
  205. )
  206. ut.process_bad_data(bad_data)
  207. msg('OK')
  208. return True