Clone of Bael'Zharon's Respite @ https://github.com/boardwalk/bzr

ChecksumXorGenerator.cpp 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /*
  2. * Bael'Zharon's Respite
  3. * Copyright (C) 2014 Daniel Skorupski
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. */
  18. #include "net/ChecksumXorGenerator.h"
  19. static const uint32_t kMaxCacheSize = 100;
  20. ChecksumXorGenerator::ChecksumXorGenerator() : cacheBegin_(0)
  21. {}
  22. void ChecksumXorGenerator::init(uint32_t seed)
  23. {
  24. memset(xorTable_, 0, sizeof(xorTable_));
  25. value0_ = seed;
  26. value1_ = seed;
  27. value2_ = seed;
  28. initTables();
  29. cache_.clear();
  30. cacheBegin_ = 2; // there is no sequence 0 or 1
  31. }
  32. uint32_t ChecksumXorGenerator::get(uint32_t sequence)
  33. {
  34. if(cacheBegin_ == 0)
  35. {
  36. // not initialized
  37. return 0;
  38. }
  39. if(sequence < cacheBegin_)
  40. {
  41. // sequence already purged
  42. return 0;
  43. }
  44. if(sequence >= cacheBegin_ + kMaxCacheSize)
  45. {
  46. // sequence too far in future
  47. return 0;
  48. }
  49. while(sequence >= cacheBegin_ + cache_.size())
  50. {
  51. cache_.push_back(generate());
  52. }
  53. return cache_[sequence - cacheBegin_];
  54. }
  55. void ChecksumXorGenerator::purge(uint32_t sequence)
  56. {
  57. if(cacheBegin_ == 0)
  58. {
  59. // not initialized
  60. return;
  61. }
  62. if(sequence >= cacheBegin_ + cache_.size())
  63. {
  64. // get not successful for sequence yet
  65. return;
  66. }
  67. while(sequence >= cacheBegin_)
  68. {
  69. cache_.pop_front();
  70. cacheBegin_++;
  71. }
  72. }
  73. uint32_t ChecksumXorGenerator::generate()
  74. {
  75. uint32_t value = xorTable_[counter_];
  76. if(counter_ > 0)
  77. {
  78. counter_--;
  79. }
  80. else
  81. {
  82. scramble();
  83. counter_ = 255;
  84. }
  85. return value;
  86. }
  87. void ChecksumXorGenerator::initTables()
  88. {
  89. uint32_t xorvals[8];
  90. for(int i = 0; i < 8; i++)
  91. {
  92. xorvals[i] = 0x9E3779B9;
  93. }
  94. for(int i = 0; i < 4; i++)
  95. {
  96. initMix(xorvals);
  97. }
  98. for(int i = 0; i < 256; i += 8)
  99. {
  100. for(int j = 0; j < 8; j++)
  101. {
  102. xorvals[j] += xorTable_[i + j];
  103. }
  104. initMix(xorvals);
  105. for(int j = 0; j < 8; j++)
  106. {
  107. unkTable_[i + j] = xorvals[j];
  108. }
  109. }
  110. for(int i = 0; i < 256; i += 8)
  111. {
  112. for(int j = 0; j < 8; j++)
  113. {
  114. xorvals[j] += unkTable_[i + j];
  115. }
  116. initMix(xorvals);
  117. for(int j = 0; j < 8; j++)
  118. {
  119. unkTable_[i + j] = xorvals[j];
  120. }
  121. }
  122. scramble();
  123. counter_ = 255;
  124. }
  125. void ChecksumXorGenerator::initMix(uint32_t* xorvals)
  126. {
  127. #define ROUND(base, shift) \
  128. xorvals[base] ^= xorvals[(base + 1) & 7] shift; \
  129. xorvals[(base + 3) & 7] += xorvals[base]; \
  130. xorvals[(base + 1) & 7] += xorvals[(base + 2) & 7];
  131. ROUND(0, << 0x0B);
  132. ROUND(1, >> 0x02);
  133. ROUND(2, << 0x08);
  134. ROUND(3, >> 0x10);
  135. ROUND(4, << 0x0A);
  136. ROUND(5, >> 0x04);
  137. ROUND(6, << 0x08);
  138. ROUND(7, >> 0x09);
  139. #undef ROUND
  140. }
  141. void ChecksumXorGenerator::scramble()
  142. {
  143. uint32_t* local_unk = unkTable_;
  144. uint32_t* local_xor = xorTable_;
  145. uint32_t key0 = value0_;
  146. value2_++;
  147. uint32_t key2 = value1_ + value2_;
  148. uint32_t* lc_unk0 = local_unk;
  149. uint32_t* lc_unk200 = lc_unk0 + 128;
  150. uint32_t* lc_unk0_stop_point = lc_unk200;
  151. uint32_t var_18;
  152. uint32_t var_1c;
  153. while(lc_unk0 < lc_unk0_stop_point)
  154. {
  155. scrambleRound(key0 << 0x0D, &key0, &key2, &local_unk, &lc_unk0, &lc_unk200, &local_xor, &var_18, &var_1c);
  156. scrambleRound(key0 >> 0x06, &key0, &key2, &local_unk, &lc_unk0, &lc_unk200, &local_xor, &var_18, &var_1c);
  157. scrambleRound(key0 << 0x02, &key0, &key2, &local_unk, &lc_unk0, &lc_unk200, &local_xor, &var_18, &var_1c);
  158. scrambleRound(key0 >> 0x10, &key0, &key2, &local_unk, &lc_unk0, &lc_unk200, &local_xor, &var_18, &var_1c);
  159. }
  160. lc_unk200 = local_unk;
  161. while(lc_unk200 < lc_unk0_stop_point)
  162. {
  163. scrambleRound(key0 << 0x0D, &key0, &key2, &local_unk, &lc_unk0, &lc_unk200, &local_xor, &var_18, &var_1c);
  164. scrambleRound(key0 >> 0x06, &key0, &key2, &local_unk, &lc_unk0, &lc_unk200, &local_xor, &var_18, &var_1c);
  165. scrambleRound(key0 << 0x02, &key0, &key2, &local_unk, &lc_unk0, &lc_unk200, &local_xor, &var_18, &var_1c);
  166. scrambleRound(key0 >> 0x10, &key0, &key2, &local_unk, &lc_unk0, &lc_unk200, &local_xor, &var_18, &var_1c);
  167. }
  168. value1_ = key2;
  169. value0_ = key0;
  170. }
  171. void ChecksumXorGenerator::scrambleRound(
  172. uint32_t shiftedVal,
  173. uint32_t* key0_ptr,
  174. uint32_t* key2_ptr,
  175. uint32_t** localunk_ptr,
  176. uint32_t** lc_unk0_ptr,
  177. uint32_t** lc_unk200_ptr,
  178. uint32_t** localxor_ptr,
  179. uint32_t* var_18_ptr,
  180. uint32_t* var_1c_ptr)
  181. {
  182. *var_18_ptr = **lc_unk0_ptr;
  183. *key0_ptr = (*key0_ptr ^ shiftedVal) + **lc_unk200_ptr;
  184. *lc_unk200_ptr = *lc_unk200_ptr + 1;
  185. uint32_t res = Crazy_XOR_01(*localunk_ptr, *var_18_ptr);
  186. *var_1c_ptr = res + *key0_ptr + *key2_ptr;
  187. **lc_unk0_ptr = *var_1c_ptr;
  188. *lc_unk0_ptr = *lc_unk0_ptr + 1;
  189. res = Crazy_XOR_01(*localunk_ptr, *var_1c_ptr >> 8);
  190. *key2_ptr = res + *var_18_ptr;
  191. **localxor_ptr = *key2_ptr;
  192. *localxor_ptr = *localxor_ptr + 1;
  193. }
  194. uint32_t ChecksumXorGenerator::Crazy_XOR_01(const uint32_t* data, uint32_t index)
  195. {
  196. return *(const uint32_t*)((const uint8_t*)data + (index & 0x3FC));
  197. }