ts_ref.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. #!/usr/bin/env python3
  2. #
  3. # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
  4. # Copyright (C)2013-2019 The MMGen Project <mmgen@tuta.io>
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. """
  19. ts_ref.py: Reference file tests for the test.py test suite
  20. """
  21. import os
  22. from mmgen.globalvars import g
  23. from mmgen.opts import opt
  24. from test.common import *
  25. from test.test_py_d.common import *
  26. from test.test_py_d.ts_base import *
  27. from test.test_py_d.ts_shared import *
  28. wpasswd = 'reference password'
  29. class TestSuiteRef(TestSuiteBase,TestSuiteShared):
  30. 'saved reference files'
  31. tmpdir_nums = [8]
  32. networks = ('btc','btc_tn','ltc','ltc_tn')
  33. passthru_opts = ('coin','testnet')
  34. sources = {
  35. 'ref_addrfile': '98831F3A{}[1,31-33,500-501,1010-1011]{}.addrs',
  36. 'ref_segwitaddrfile':'98831F3A{}-S[1,31-33,500-501,1010-1011]{}.addrs',
  37. 'ref_bech32addrfile':'98831F3A{}-B[1,31-33,500-501,1010-1011]{}.addrs',
  38. 'ref_keyaddrfile': '98831F3A{}[1,31-33,500-501,1010-1011]{}.akeys.mmenc',
  39. 'ref_passwdfile': '98831F3A-фубар@crypto.org-b58-20[1,4,9-11,1100].pws',
  40. 'ref_tx_file': { # data shared with ref_altcoin, autosign
  41. 'btc': ('0B8D5A[15.31789,14,tl=1320969600].rawtx',
  42. '0C7115[15.86255,14,tl=1320969600].testnet.rawtx'),
  43. 'ltc': ('AF3CDF-LTC[620.76194,1453,tl=1320969600].rawtx',
  44. 'A5A1E0-LTC[1454.64322,1453,tl=1320969600].testnet.rawtx'),
  45. 'bch': ('460D4D-BCH[10.19764,tl=1320969600].rawtx',
  46. '359FD5-BCH[6.68868,tl=1320969600].testnet.rawtx'),
  47. 'eth': ('88FEFD-ETH[23.45495,40000].rawtx',
  48. 'B472BD-ETH[23.45495,40000].testnet.rawtx'),
  49. 'mm1': ('5881D2-MM1[1.23456,50000].rawtx',
  50. '6BDB25-MM1[1.23456,50000].testnet.rawtx'),
  51. 'etc': ('ED3848-ETC[1.2345,40000].rawtx','')
  52. },
  53. }
  54. chk_data = {
  55. 'ref_subwallet_sid': {
  56. '98831F3A:32L':'D66B4885',
  57. '98831F3A:1S':'20D95B09',
  58. },
  59. 'ref_addrfile_chksum': {
  60. 'btc': ('6FEF 6FB9 7B13 5D91','424E 4326 CFFE 5F51'),
  61. 'ltc': ('AD52 C3FE 8924 AAF0','4EBE 2E85 E969 1B30'),
  62. },
  63. 'ref_segwitaddrfile_chksum': {
  64. 'btc': ('06C1 9C87 F25C 4EE6','072C 8B07 2730 CB7A'),
  65. 'ltc': ('63DF E42A 0827 21C3','5DD1 D186 DBE1 59F2'),
  66. },
  67. 'ref_bech32addrfile_chksum': {
  68. 'btc': ('9D2A D4B6 5117 F02E','0527 9C39 6C1B E39A'),
  69. 'ltc': ('FF1C 7939 5967 AB82','ED3D 8AA4 BED4 0B40'),
  70. },
  71. 'ref_keyaddrfile_chksum': {
  72. 'btc': ('9F2D D781 1812 8BAD','88CC 5120 9A91 22C2'),
  73. 'ltc': ('B804 978A 8796 3ED4','98B5 AC35 F334 0398'),
  74. },
  75. 'ref_passwdfile_chksum': 'A983 DAB9 5514 27FB',
  76. }
  77. cmd_group = ( # TODO: move to tooltest2
  78. ('ref_words_to_subwallet_chk1','subwallet generation from reference words file (long subseed)'),
  79. ('ref_words_to_subwallet_chk2','subwallet generation from reference words file (short subseed)'),
  80. ('ref_subwallet_addrgen1','subwallet address file generation (long subseed)'),
  81. ('ref_subwallet_addrgen2','subwallet address file generation (short subseed)'),
  82. ('ref_subwallet_keygen1','subwallet key-address file generation (long subseed)'),
  83. ('ref_subwallet_keygen2','subwallet key-address file generation (short subseed)'),
  84. ('ref_addrfile_chk', 'saved reference address file'),
  85. ('ref_segwitaddrfile_chk','saved reference address file (segwit)'),
  86. ('ref_bech32addrfile_chk','saved reference address file (bech32)'),
  87. ('ref_keyaddrfile_chk','saved reference key-address file'),
  88. ('ref_passwdfile_chk', 'saved reference password file'),
  89. # Create the fake inputs:
  90. # ('txcreate8', 'transaction creation (8)'),
  91. ('ref_tx_chk', 'signing saved reference tx file'),
  92. ('ref_brain_chk_spc3', 'saved brainwallet (non-standard spacing)'),
  93. ('ref_tool_decrypt', 'decryption of saved MMGen-encrypted file'),
  94. )
  95. def _get_ref_subdir_by_coin(self,coin):
  96. return {'btc': '',
  97. 'bch': '',
  98. 'ltc': 'litecoin',
  99. 'eth': 'ethereum',
  100. 'etc': 'ethereum_classic',
  101. 'xmr': 'monero',
  102. 'zec': 'zcash',
  103. 'dash': 'dash' }[coin.lower()]
  104. @property
  105. def ref_subdir(self):
  106. return self._get_ref_subdir_by_coin(g.coin)
  107. def ref_words_to_subwallet_chk1(self):
  108. return self.ref_words_to_subwallet_chk('32L')
  109. def ref_words_to_subwallet_chk2(self):
  110. return self.ref_words_to_subwallet_chk('1S')
  111. def ref_words_to_subwallet_chk(self,ss_idx):
  112. wf = dfl_words_file
  113. args = ['-d',self.tr.trash_dir,'-o','words',wf,ss_idx]
  114. t = self.spawn('mmgen-subwalletgen',args,extra_desc='(generate subwallet)')
  115. t.expect('Generating subseed {}'.format(ss_idx))
  116. chk_sid = self.chk_data['ref_subwallet_sid']['98831F3A:{}'.format(ss_idx)]
  117. fn = t.written_to_file('Mnemonic data')
  118. assert chk_sid in fn,'incorrect filename: {} (does not contain {})'.format(fn,chk_sid)
  119. ok()
  120. t = self.spawn('mmgen-walletchk',[fn],extra_desc='(check subwallet)')
  121. t.expect(r'Valid mnemonic data for Seed ID ([0-9A-F]*)\b',regex=True)
  122. sid = t.p.match.group(1)
  123. assert sid == chk_sid,'subseed ID {} does not match expected value {}'.format(sid,chk_sid)
  124. t.read()
  125. return t
  126. def ref_subwallet_addrgen(self,ss_idx,target='addr'):
  127. wf = dfl_words_file
  128. args = ['-d',self.tr.trash_dir,'--subwallet='+ss_idx,wf,'1-10']
  129. t = self.spawn('mmgen-{}gen'.format(target),args)
  130. t.expect('Generating subseed {}'.format(ss_idx))
  131. chk_sid = self.chk_data['ref_subwallet_sid']['98831F3A:{}'.format(ss_idx)]
  132. assert chk_sid == t.expect_getend('Checksum for .* data ',regex=True)[:8]
  133. if target == 'key':
  134. t.expect('Encrypt key list? (y/N): ','n')
  135. fn = t.written_to_file(('Addresses','Secret keys')[target=='key'])
  136. assert chk_sid in fn,'incorrect filename: {} (does not contain {})'.format(fn,chk_sid)
  137. return t
  138. def ref_subwallet_addrgen1(self):
  139. return self.ref_subwallet_addrgen('32L')
  140. def ref_subwallet_addrgen2(self):
  141. return self.ref_subwallet_addrgen('1S')
  142. def ref_subwallet_keygen1(self):
  143. return self.ref_subwallet_addrgen('32L',target='key')
  144. def ref_subwallet_keygen2(self):
  145. return self.ref_subwallet_addrgen('1S',target='key')
  146. def ref_addrfile_chk(self,ftype='addr',coin=None,subdir=None,pfx=None,mmtype=None,add_args=[]):
  147. af_key = 'ref_{}file'.format(ftype)
  148. af_fn = TestSuiteRef.sources[af_key].format(pfx or self.altcoin_pfx,'' if coin else self.tn_ext)
  149. af = joinpath(ref_dir,(subdir or self.ref_subdir,'')[ftype=='passwd'],af_fn)
  150. coin_arg = [] if coin == None else ['--coin='+coin]
  151. tool_cmd = ftype.replace('segwit','').replace('bech32','')+'file_chksum'
  152. t = self.spawn('mmgen-tool',coin_arg+['-p1',tool_cmd,af]+add_args)
  153. if ftype == 'keyaddr':
  154. t.do_decrypt_ka_data(hp=ref_kafile_hash_preset,pw=ref_kafile_pass,have_yes_opt=True)
  155. rc = self.chk_data[ 'ref_' + ftype + 'file_chksum' +
  156. ('_'+coin.lower() if coin else '') +
  157. ('_'+mmtype if mmtype else '')]
  158. ref_chksum = rc if (ftype == 'passwd' or coin) else rc[g.proto.base_coin.lower()][g.testnet]
  159. t.expect(chksum_pat,regex=True)
  160. m = t.p.match.group(0)
  161. t.read()
  162. cmp_or_die(ref_chksum,m)
  163. return t
  164. def ref_segwitaddrfile_chk(self):
  165. if not 'S' in g.proto.mmtypes:
  166. return skip('not supported')
  167. else:
  168. return self.ref_addrfile_chk(ftype='segwitaddr')
  169. def ref_bech32addrfile_chk(self):
  170. if not 'B' in g.proto.mmtypes:
  171. return skip('not supported')
  172. else:
  173. return self.ref_addrfile_chk(ftype='bech32addr')
  174. def ref_keyaddrfile_chk(self):
  175. return self.ref_addrfile_chk(ftype='keyaddr')
  176. def ref_passwdfile_chk(self):
  177. return self.ref_addrfile_chk(ftype='passwd')
  178. def ref_tx_chk(self):
  179. fn = self.sources['ref_tx_file'][g.coin.lower()][bool(self.tn_ext)]
  180. if not fn: return
  181. tf = joinpath(ref_dir,self.ref_subdir,fn)
  182. wf = dfl_words_file
  183. self.write_to_tmpfile(pwfile,wpasswd)
  184. pf = joinpath(self.tmpdir,pwfile)
  185. return self.txsign(tf,wf,pf,save=False,has_label=True,do_passwd=False)
  186. def ref_brain_chk_spc3(self):
  187. return self.ref_brain_chk(bw_file=ref_bw_file_spc)
  188. def ref_tool_decrypt(self):
  189. f = joinpath(ref_dir,ref_enc_fn)
  190. disable_debug()
  191. dec_file = joinpath(self.tmpdir,'famous.txt')
  192. t = self.spawn('mmgen-tool', ['-q','decrypt',f,'outfile='+dec_file,'hash_preset=1'])
  193. restore_debug()
  194. t.passphrase('user data',tool_enc_passwd)
  195. t.written_to_file('Decrypted data')
  196. dec_txt = read_from_file(dec_file)
  197. imsg_r(dec_txt)
  198. cmp_or_die(sample_text+'\n',dec_txt) # file adds a newline to sample_text
  199. return t