EncodingScheme_test.c 15 KB

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