EncodingScheme_test.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. #include "benc/String.h"
  16. #include "crypto/random/Random.h"
  17. #include "switch/EncodingScheme.h"
  18. #define NumberCompress_OLD_CODE
  19. #include "switch/NumberCompress.h"
  20. #include "memory/Allocator.h"
  21. #include "memory/MallocAllocator.h"
  22. #include "util/Bits.h"
  23. #define Order_TYPE struct EncodingScheme_Form
  24. #define Order_NAME OfEncodingForms
  25. #define Order_COMPARE compareEncodingForms
  26. #include "util/Order.h"
  27. static inline int compareEncodingForms(const struct EncodingScheme_Form* a,
  28. const struct EncodingScheme_Form* b)
  29. {
  30. int diff = a->bitCount;
  31. diff -= b->bitCount;
  32. return diff == 0 ? 0 : diff > 0 ? 1 : -1;
  33. }
  34. static void randomForm(struct EncodingScheme_Form* form, struct Random* rand)
  35. {
  36. for (;;) {
  37. Random_bytes(rand, (uint8_t*)form, sizeof(struct EncodingScheme_Form));
  38. //Bits_memset(form, 0xff, sizeof(struct EncodingScheme_Form));
  39. form->bitCount &= ((1<<5)-1);
  40. if (!form->bitCount) {
  41. form->bitCount++;
  42. }
  43. form->prefixLen &= ((1<<5)-1);
  44. if (!form->prefixLen) {
  45. form->prefixLen++;
  46. }
  47. if (EncodingScheme_formSize(form) > 59) { continue; }
  48. if (form->prefixLen > 3 && (form->prefix & 0xf) == 1) { continue; }
  49. break;
  50. }
  51. form->prefix &= ((((uint64_t)1)<<form->prefixLen)-1);
  52. }
  53. static struct EncodingScheme* randomScheme(struct Random* rand, struct Allocator* alloc)
  54. {
  55. struct EncodingScheme* out =
  56. Allocator_malloc(alloc, sizeof(struct EncodingScheme));
  57. do {
  58. out->count = Random_uint32(rand) % 32;
  59. } while (out->count < 2);
  60. out->forms = Allocator_malloc(alloc, sizeof(struct EncodingScheme_Form) * out->count);
  61. for (int i = 0; i < (int)out->count; i++) {
  62. randomForm(&out->forms[i], rand);
  63. for (int j = 0; j < i; j++) {
  64. if (out->forms[i].bitCount == out->forms[j].bitCount) {
  65. i--;
  66. break;
  67. }
  68. int minPfx = (out->forms[i].prefixLen < out->forms[j].prefixLen)
  69. ? out->forms[i].prefixLen : out->forms[j].prefixLen;
  70. if (((out->forms[j].prefix ^ out->forms[i].prefix) & ((1<<minPfx)-1)) == 0) {
  71. // collision, destroy both entries and try again.
  72. if (j != i-1) {
  73. Bits_memcpy(&out->forms[j],
  74. &out->forms[i-1],
  75. sizeof(struct EncodingScheme_Form));
  76. }
  77. i -= 2;
  78. break;
  79. }
  80. }
  81. }
  82. Order_OfEncodingForms_qsort(out->forms, out->count);
  83. return out;
  84. }
  85. static void assertEqual(struct EncodingScheme* a,
  86. struct EncodingScheme* b)
  87. {
  88. Assert_true(b);
  89. Assert_true(a->count == b->count);
  90. Assert_true(
  91. !Bits_memcmp(a->forms, b->forms, sizeof(struct EncodingScheme_Form) * a->count));
  92. }
  93. static void randomTest(struct Allocator* parent, struct Random* rand)
  94. {
  95. struct Allocator* alloc = Allocator_child(parent);
  96. struct EncodingScheme* control = randomScheme(rand, alloc);
  97. String* data = EncodingScheme_serialize(control, alloc);
  98. struct EncodingScheme* test = EncodingScheme_deserialize(data, alloc);
  99. assertEqual(control, test);
  100. Allocator_free(alloc);
  101. }
  102. // Just make sure random crap doesn't crash it.
  103. static void fuzzTest(struct Allocator* parent, struct Random* rand)
  104. {
  105. struct Allocator* alloc = Allocator_child(parent);
  106. String* data = String_newBinary(NULL, Random_uint32(rand) % 1024, alloc);
  107. Random_bytes(rand, (uint8_t*)data->bytes, data->len);
  108. EncodingScheme_deserialize(data, alloc);
  109. Allocator_free(alloc);
  110. }
  111. /** Greatest possible number using x bits, all are set. */
  112. #define Bits_maxBits64(x) ((((uint64_t)1)<<(x))-1)
  113. static void encoding(struct Allocator* parent)
  114. {
  115. struct EncodingScheme_Form forms[3] = {
  116. {
  117. .prefixLen = 15,
  118. .bitCount = 2,
  119. .prefix = ((1<<15)-1) ^ (1<<1),
  120. }, {
  121. .prefixLen = 20,
  122. .bitCount = 4,
  123. .prefix = ((1<<20)-1) ^ (1<<2),
  124. }, {
  125. .prefixLen = 18,
  126. .bitCount = 8,
  127. .prefix = ((1<<18)-1) ^ (1<<3),
  128. }
  129. };
  130. // should encode as prefixLen, bitCount, prefix
  131. // 111111111111101 00010 01111 15/2/~0 -> 01001111 11110100 11111111 remainder 1
  132. // 11111111111111111011 00100 10100 20/4/~0 -> 00101001 11011001 11111111 remainder 7f
  133. // 111111111111110111 01000 10010 18/8/~0 -> 01111111 10001001 11101110 11111111 remainder 7
  134. // 00000111 <-- appliation of remainder
  135. //
  136. // In bytes:
  137. // 01001111 11110100 11111111 00101001 11011001 11111111
  138. // 01111111 10001001 11101110 11111111 00000111
  139. //
  140. // or \x4f\xf4\xff\x29\xd9\xff\x7f\x89\xee\xff\x07
  141. struct EncodingScheme list = {
  142. .count = 3,
  143. .forms = forms
  144. };
  145. struct Allocator* alloc = Allocator_child(parent);
  146. String* data = EncodingScheme_serialize(&list, alloc);
  147. Assert_true(data->len == 11);
  148. Assert_true(!Bits_memcmp(data->bytes, "\x4f\xf4\xff\x29\xd9\xff\x7f\x89\xee\xff\x07", 11));
  149. Allocator_free(alloc);
  150. }
  151. #define convertLabel_SELF_ROUTE 1
  152. #define convertLabel_TOO_BIG 2
  153. static int convertLabel(struct EncodingScheme_Form* iform,
  154. struct EncodingScheme_Form* oform,
  155. uint64_t label)
  156. {
  157. struct {
  158. struct EncodingScheme scheme;
  159. struct EncodingScheme_Form forms[2];
  160. } s;
  161. s.scheme.count = 2;
  162. s.scheme.forms = s.forms;
  163. Bits_memcpy(&s.forms[0], iform, sizeof(struct EncodingScheme_Form));
  164. Bits_memcpy(&s.forms[1], oform, sizeof(struct EncodingScheme_Form));
  165. int iformNum = 0;
  166. int oformNum = 1;
  167. struct EncodingScheme* scheme = &s.scheme;
  168. Assert_true(EncodingScheme_getFormNum(scheme, label) == iformNum);
  169. uint64_t label2 = EncodingScheme_convertLabel(scheme, label, oformNum);
  170. if ((label & Bits_maxBits64(s.forms[0].prefixLen + s.forms[0].bitCount)) == 1) {
  171. Assert_true(label2 == EncodingScheme_convertLabel_INVALID);
  172. return convertLabel_SELF_ROUTE;
  173. }
  174. if (Bits_log2x64(label) + EncodingScheme_formSize(oform) -
  175. EncodingScheme_formSize(iform) > 59)
  176. {
  177. Assert_true(label2 == EncodingScheme_convertLabel_INVALID);
  178. return convertLabel_TOO_BIG;
  179. }
  180. uint64_t additional = label >> s.forms[0].prefixLen;
  181. uint64_t director = additional & Bits_maxBits64(s.forms[0].bitCount);
  182. if (!EncodingScheme_is358(&s.scheme)) {
  183. } else if (1 == (s.forms[0].prefix & Bits_maxBits64(s.forms[0].prefixLen))) {
  184. director = director - (director == 1) + (director == 0);
  185. } else {
  186. director += (director > 0);
  187. }
  188. // here is where the director is actually correct
  189. if (!EncodingScheme_is358(&s.scheme)) {
  190. } else if (1 == (s.forms[1].prefix & Bits_maxBits64(s.forms[1].prefixLen))) {
  191. director = director - (director == 1) + (director == 0);
  192. } else {
  193. director -= (director > 0);
  194. }
  195. additional = additional >> s.forms[0].bitCount;
  196. uint64_t converted = (additional << s.forms[1].bitCount) | director;
  197. converted = (converted << s.forms[1].prefixLen) | s.forms[1].prefix;
  198. if ((converted & Bits_maxBits64(s.forms[1].prefixLen + s.forms[1].bitCount)) == 1) {
  199. // looks like a self-route
  200. Assert_true(label2 == EncodingScheme_convertLabel_INVALID);
  201. return convertLabel_SELF_ROUTE;
  202. }
  203. //printf("%lx == %lx", label2, converted);
  204. Assert_true(label2 == converted);
  205. uint64_t label3 = EncodingScheme_convertLabel(scheme, label2, iformNum);
  206. Assert_true(label3 == label);
  207. return 0;
  208. }
  209. static void convertLabelRand(struct Random* rand, struct EncodingScheme* scheme)
  210. {
  211. for (int i = 0; i < 100; i++) {
  212. int oformNum;
  213. do {
  214. oformNum = Random_uint8(rand) % scheme->count;
  215. } while (!oformNum);
  216. int iformNum = Random_uint8(rand) % oformNum;
  217. uint64_t label = Random_uint64(rand);
  218. label &= (UINT64_MAX >> (Random_uint8(rand) % 63));
  219. for (;;) {
  220. // make sure the label has the right prefix
  221. label <<= scheme->forms[iformNum].prefixLen;
  222. label |= scheme->forms[iformNum].prefix;
  223. Assert_true(EncodingScheme_getFormNum(scheme, label) == iformNum);
  224. if (Bits_log2x64(label) > 59) {
  225. // fall through
  226. } else {
  227. int ret = convertLabel(&scheme->forms[iformNum], &scheme->forms[oformNum], label);
  228. if (ret == convertLabel_SELF_ROUTE) {
  229. i--;
  230. break;
  231. } else if (ret == convertLabel_TOO_BIG) {
  232. // fall through
  233. } else if (!ret) {
  234. // success
  235. break;
  236. } else {
  237. Assert_true(0);
  238. }
  239. }
  240. label >>= scheme->forms[iformNum].prefixLen + 1;
  241. }
  242. }
  243. }
  244. static void isOneHopScheme(struct Allocator* allocator)
  245. {
  246. struct Allocator* alloc = Allocator_child(allocator);
  247. struct EncodingScheme* s4x8 = NumberCompress_v4x8_defineScheme(alloc);
  248. Assert_true(!EncodingScheme_isOneHop(s4x8, 1));
  249. Assert_true(EncodingScheme_isOneHop(s4x8, 0x21));
  250. Assert_true(EncodingScheme_isOneHop(s4x8, 0x23));
  251. Assert_true(!EncodingScheme_isOneHop(s4x8, 0x12));
  252. Assert_true(EncodingScheme_isOneHop(s4x8, 0x220));
  253. Assert_true(EncodingScheme_isOneHop(s4x8, 0x210));
  254. Assert_true(!EncodingScheme_isOneHop(s4x8, 0x110));
  255. struct EncodingScheme* s3x5x8 = NumberCompress_v3x5x8_defineScheme(alloc);
  256. Assert_true(!EncodingScheme_isOneHop(s3x5x8, 1));
  257. Assert_true(EncodingScheme_isOneHop(s3x5x8, 0x13));
  258. Assert_true(EncodingScheme_isOneHop(s3x5x8, 0x15));
  259. Assert_true(EncodingScheme_isOneHop(s3x5x8, 0x96));
  260. Assert_true(EncodingScheme_isOneHop(s3x5x8, 0x400));
  261. Assert_true(!EncodingScheme_isOneHop(s3x5x8, 0x115));
  262. Assert_true(!EncodingScheme_isOneHop(s3x5x8, 0x166));
  263. Assert_true(!EncodingScheme_isOneHop(s3x5x8, 0x1400));
  264. Allocator_free(alloc);
  265. }
  266. typedef uint64_t (* EncodeNum)(uint32_t num);
  267. typedef uint32_t (* DecodeNum)(uint64_t label);
  268. static uint64_t encode358(uint32_t num)
  269. {
  270. uint32_t bits = NumberCompress_v3x5x8_bitsUsedForNumber(num);
  271. return NumberCompress_v3x5x8_getCompressed(num, bits);
  272. }
  273. static uint32_t decode358(uint64_t label)
  274. {
  275. uint32_t bits = NumberCompress_v3x5x8_bitsUsedForLabel(label);
  276. return NumberCompress_v3x5x8_getDecompressed(label, bits);
  277. }
  278. static uint64_t encode48(uint32_t num)
  279. {
  280. uint32_t bits = NumberCompress_v4x8_bitsUsedForNumber(num);
  281. return NumberCompress_v4x8_getCompressed(num, bits);
  282. }
  283. static uint32_t decode48(uint64_t label)
  284. {
  285. uint32_t bits = NumberCompress_v4x8_bitsUsedForLabel(label);
  286. return NumberCompress_v4x8_getDecompressed(label, bits);
  287. }
  288. static uint64_t encodef4(uint32_t num)
  289. {
  290. uint32_t bits = NumberCompress_f4_bitsUsedForNumber(num);
  291. return NumberCompress_f4_getCompressed(num, bits);
  292. }
  293. static uint32_t decodef4(uint64_t label)
  294. {
  295. uint32_t bits = NumberCompress_f4_bitsUsedForLabel(label);
  296. return NumberCompress_f4_getDecompressed(label, bits);
  297. }
  298. static void parseSerializeDir(struct EncodingScheme* scheme, EncodeNum en, DecodeNum dn)
  299. {
  300. int max = Bits_maxBits64(scheme->forms[scheme->count - 1].bitCount);
  301. for (int i = 0; i <= max; i++) {
  302. //printf("\nTest [%d]\n", i);
  303. uint64_t dir = EncodingScheme_serializeDirector(scheme, i, -1);
  304. //printf("[%lu] == [%lu] (%d)\n", dir, en(i), i);
  305. Assert_true(dir == en(i));
  306. if (dir < ~0ull) {
  307. int out = EncodingScheme_parseDirector(scheme, dir);
  308. //printf("Test [%d] == [%u] decode(%lu)\n", i, (uint32_t)dn(dir), dir);
  309. Assert_true((uint32_t)i == dn(dir));
  310. //printf("[%d] == [%d]\n", i, out);
  311. Assert_true(i == out);
  312. }
  313. for (int j = 0; j < scheme->count; j++) {
  314. if (i >> scheme->forms[j].bitCount) { continue; }
  315. //printf(" With form [%d]\n", j);
  316. dir = scheme->forms[j].prefix | ( i << scheme->forms[j].prefixLen );
  317. int out = EncodingScheme_parseDirector(scheme, dir);
  318. Assert_true(out >= 0);
  319. uint64_t dir2 = EncodingScheme_serializeDirector(scheme, out, j);
  320. //printf(" [%lu] == [%lu] encode(%d)\n", dir2, dir, out);
  321. Assert_true(dir2 == dir);
  322. }
  323. }
  324. }
  325. static void bitsUsed(struct EncodingScheme* es, DecodeNum getBits, struct Random* rand)
  326. {
  327. uint64_t label = Random_uint64(rand);
  328. int fn = EncodingScheme_getFormNum(es, label);
  329. Assert_true(fn > -1);
  330. uint32_t bits = getBits(label);
  331. uint32_t esbits = es->forms[fn].bitCount + es->forms[fn].prefixLen;
  332. //printf("%lx %u %u\n", label, bits, esbits);
  333. Assert_true(bits == esbits);
  334. }
  335. int main()
  336. {
  337. struct Allocator* alloc = MallocAllocator_new(20000000);
  338. struct Random* rand = Random_new(alloc, NULL, NULL);
  339. encoding(alloc);
  340. isOneHopScheme(alloc);
  341. for (int i = 0; i < 1000; i++) {
  342. randomTest(alloc, rand);
  343. }
  344. for (int i = 0; i < 1000; i++) {
  345. fuzzTest(alloc, rand);
  346. }
  347. struct EncodingScheme* es48 = NumberCompress_v4x8_defineScheme(alloc);
  348. struct EncodingScheme* es358 = NumberCompress_v3x5x8_defineScheme(alloc);
  349. struct EncodingScheme* esf4 = NumberCompress_f4_defineScheme(alloc);
  350. for (int i = 0; i < 1000; i++) {
  351. bitsUsed(es48, NumberCompress_v4x8_bitsUsedForLabel, rand);
  352. }
  353. for (int i = 0; i < 1000; i++) {
  354. bitsUsed(es358, NumberCompress_v3x5x8_bitsUsedForLabel, rand);
  355. }
  356. parseSerializeDir(es358, encode358, decode358);
  357. parseSerializeDir(es48, encode48, decode48);
  358. parseSerializeDir(esf4, encodef4, decodef4);
  359. // for testing individual conversions in isolation.
  360. /*convertLabel(
  361. &(struct EncodingScheme_Form){.bitCount = 15, .prefixLen = 20, .prefix = 792003},
  362. &(struct EncodingScheme_Form){.bitCount = 31, .prefixLen = 30, .prefix = 385462496},
  363. 11331704259
  364. );*/
  365. for (int i = 0; i < 10; i++) {
  366. struct Allocator* tempAlloc = Allocator_child(alloc);
  367. struct EncodingScheme* scheme = randomScheme(rand, tempAlloc);
  368. convertLabelRand(rand, scheme);
  369. convertLabelRand(rand, es48);
  370. convertLabelRand(rand, es358);
  371. Allocator_free(tempAlloc);
  372. }
  373. struct Allocator* tempAlloc = Allocator_child(alloc);
  374. struct EncodingScheme* scheme = NumberCompress_v3x5x8_defineScheme(alloc);
  375. for (int i = 0; i < NumberCompress_v3x5x8_INTERFACES; i++) {
  376. int bits = NumberCompress_bitsUsedForNumber(i);
  377. uint64_t expected = NumberCompress_getCompressed(i, bits);
  378. Assert_true(expected == EncodingScheme_convertLabel(scheme, expected,
  379. EncodingScheme_convertLabel_convertTo_CANNONICAL));
  380. }
  381. Allocator_free(tempAlloc);
  382. Allocator_free(alloc);
  383. return 0;
  384. }