seedsplit.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. #!/usr/bin/env python3
  2. """
  3. test.modtest_d.seedsplit: seed splitting unit tests for the MMGen suite
  4. """
  5. from mmgen.util import msg, msg_r
  6. from mmgen.color import pink
  7. from mmgen.seed import Seed
  8. from mmgen.seedsplit import SeedShareList, SeedShareIdx
  9. from ..include.common import cfg, vmsg, vmsg_r
  10. cfg.debug_subseed = bool(cfg.verbose)
  11. def basic_ops(master_idx):
  12. test_data = {
  13. 'default': (
  14. (8, '4710FBF0', 'B3D9411B', '2670E83D', 'D1FC57ED', 'AE49CABE', '63FFBA62', 0, 0),
  15. (6, '9D07ABBD', 'AF5DC2F6', '1A3BBDAC', '2548AEE9', 'B94F7450', '1F4E5A12', 0, 0),
  16. (4, '43670520', '1F72C066', 'E5AA8DA1', 'A33966A0', 'D2BCE0A5', 'A568C315', 0, 0),
  17. ),
  18. 'φυβαρ': (
  19. (8, '4710FBF0', '269D658C', '9D25889E', '6D730ECB', 'C61A963F', '9FE99C05', 0, 0),
  20. (6, '9D07ABBD', '4998B33E', 'F00CE041', 'C612BEE5', '35CD3675', '41B3BE61', 0, 0),
  21. (4, '43670520', '77140076', 'EA82CB30', '80F7AEDE', 'D168D768', '77BE57AA', 0, 0),
  22. )
  23. }
  24. test_data_master = {
  25. '1': {
  26. 'default': (
  27. (8, '4710FBF0', '6AE6177F', 'AC12090C', '6AE6177F',
  28. '3E87A907', '7D1FEA56', 'BFEBFFFF', '629A9808'),
  29. (4, '43670520', '6739535C', 'ABF4DD38', '6739535C',
  30. '778E9C60', '89CBCFD2', '689FABF5', '70BED76B'),
  31. ),
  32. 'φυβαρ': (
  33. (8, '4710FBF0', '6AE6177F', 'AC5FA32E', '6AE6177F',
  34. '9777A750', 'C7CF2AFC', '035AAACB', 'C777FBE4'),
  35. (4, '43670520', '6739535C', '37EBA2F5', '6739535C',
  36. '927549D2', '29BADEE7', '9CA73A03', '313F5528'))
  37. },
  38. '5': {
  39. 'default': (
  40. (8, '4710FBF0', '5EFAC3D6', 'B489167D', '5EFAC3D6',
  41. 'BB004DC5', '1A0381C0', '4EA182E3', '547FB2DC'),
  42. (4, '43670520', 'EE93DB0E', '44962A7D', 'EE93DB0E',
  43. '07339882', '376A05B1', 'CE51D022', '00149CA3'),
  44. ),
  45. 'φυβαρ': (
  46. (8, '4710FBF0', '5EFAC3D6', 'A6E27EE3', '5EFAC3D6',
  47. '32C24668', 'B4C54297', '1EC9B71B', '8C5C6B1C'),
  48. (4, '43670520', 'EE93DB0E', 'B584E963', 'EE93DB0E',
  49. '4BEA2AB2', '4BEA65C7', '140FC43F', 'BBD19461'))
  50. }
  51. }
  52. if master_idx:
  53. test_data = test_data_master[str(master_idx)]
  54. for id_str in (None, 'default', 'φυβαρ'):
  55. vmsg(f'Testing ID str: {pink(str(id_str))}')
  56. for a, b, c, d, e, f, h, i, p in test_data[id_str if id_str is not None else 'default']:
  57. seed_bin = bytes.fromhex('deadbeef' * a)
  58. seed = Seed(cfg, seed_bin=seed_bin)
  59. assert seed.sid == b, seed.sid
  60. for share_count, j, k, l, m in (
  61. (2, c, c, d, i),
  62. (5, e, f, h, p)):
  63. shares = seed.split(share_count, id_str=id_str, master_idx=master_idx)
  64. A = len(shares)
  65. assert A == share_count, A
  66. s = shares.format()
  67. vmsg_r(f'\n{s}')
  68. assert len(s.strip().split('\n')) == share_count+6, s
  69. if master_idx:
  70. A = shares.get_share_by_idx(1, base_seed=False).sid
  71. B = shares.get_share_by_seed_id(j, base_seed=False).sid
  72. assert A == B == m, A
  73. A = shares.get_share_by_idx(1, base_seed=True).sid
  74. B = shares.get_share_by_seed_id(j, base_seed=True).sid
  75. assert A == B == j, A
  76. A = shares.get_share_by_idx(share_count-1, base_seed=True).sid
  77. B = shares.get_share_by_seed_id(k, base_seed=True).sid
  78. assert A == B == k, A
  79. A = shares.get_share_by_idx(share_count).sid
  80. B = shares.get_share_by_seed_id(l).sid
  81. assert A == B == l, A
  82. A = shares.join().sid
  83. assert A == b, A
  84. if master_idx:
  85. slist = [shares.get_share_by_idx(i+1, base_seed=True) for i in range(len(shares))]
  86. A = Seed.join_shares(cfg, slist, master_idx=master_idx, id_str=id_str).sid
  87. assert A == b, A
  88. return True
  89. def collisions(seed_hex, ss_count, last_sid, collisions_chk, master_idx):
  90. seed_bin = bytes.fromhex(seed_hex)
  91. seed = Seed(cfg, seed_bin=seed_bin)
  92. SeedShareIdx.max_val = ss_count
  93. shares = seed.split(ss_count, master_idx=master_idx)
  94. A = shares.get_share_by_idx(ss_count).sid
  95. B = shares.get_share_by_seed_id(last_sid).sid
  96. assert A == last_sid, A
  97. assert B == last_sid, B
  98. assert shares.nonce_start == 0, shares.nonce_start
  99. collisions = 0
  100. for sid in shares.data['long']:
  101. collisions += shares.data['long'][sid][1]
  102. assert collisions == collisions_chk, collisions
  103. vmsg(f'{collisions} collisions, last_sid {last_sid}')
  104. return True
  105. class unit_tests:
  106. def ops1(self, name, ut, desc='basic ops (master_idx=None)'):
  107. return basic_ops(master_idx=None)
  108. def ops2(self, name, ut, desc='basic ops (master_idx=1)'):
  109. return basic_ops(master_idx=1)
  110. def ops3(self, name, ut, desc='basic ops (master_idx=5)'):
  111. return basic_ops(master_idx=5)
  112. def limits(self, name, ut, desc='defaults and limits...'):
  113. seed_bin = bytes.fromhex('deadbeef' * 8)
  114. seed = Seed(cfg, seed_bin=seed_bin)
  115. shares = seed.split(SeedShareIdx.max_val)
  116. s = shares.format()
  117. assert len(s.strip().split('\n')) == 1030, s
  118. A = shares.get_share_by_idx(1024).sid
  119. B = shares.get_share_by_seed_id('4BA23728').sid
  120. assert A == '4BA23728', A
  121. assert B == '4BA23728', B
  122. A = shares.join().sid
  123. B = seed.sid
  124. assert A == B, A
  125. return True
  126. def collisions1(self, name, ut, desc='last share collisions with shortened Seed IDs'):
  127. seed_bin = bytes.fromhex('2eadbeef'*8)
  128. seed = Seed(cfg, seed_bin=seed_bin)
  129. ssm_save = SeedShareIdx.max_val
  130. ssm = SeedShareIdx.max_val = 2048
  131. shares = SeedShareList(seed, count=ssm, id_str='foo', master_idx=1, debug_last_share=True)
  132. lsid = shares.last_share.sid
  133. collisions = shares.data['long'][lsid][1]
  134. assert collisions == 2, collisions
  135. assert lsid == 'B5B8AD09', lsid
  136. SeedShareIdx.max_val = ssm_save
  137. vmsg(f'{collisions} collisions, last_share sid {lsid}')
  138. return True
  139. def collisions2(self, name, ut, desc='Seed ID collisions (65535 seed shares, master_idx=None)'):
  140. return collisions('1dabcdef'*4, 65535, 'B5CBCE0A', 3, master_idx=None)
  141. def collisions3(self, name, ut, desc='Seed ID collisions (65535 seed shares, master_idx=1)'):
  142. return collisions('18abcdef'*4, 65535, 'FF03CE82', 3, master_idx=1)