EncodingScheme_test.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  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 <http://www.gnu.org/licenses/>.
  14. */
  15. #include "benc/String.h"
  16. #include "crypto/random/Random.h"
  17. #include "switch/EncodingScheme.h"
  18. #include "switch/NumberCompress.h"
  19. #include "memory/Allocator.h"
  20. #include "memory/MallocAllocator.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_memcpyConst(&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_memcpyConst(&s.forms[0], iform, sizeof(struct EncodingScheme_Form));
  163. Bits_memcpyConst(&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. additional = additional >> s.forms[0].bitCount;
  182. // Conversions are necessary for two reasons.
  183. // #1 ensure 0001 always references interface 1, the self interface.
  184. // #2 reuse interface the binary encoding for interface 1 in other EncodingForms
  185. // because interface 1 cannot be expressed as anything other than 0001
  186. if ((s.forms[0].prefix & Bits_maxBits64(s.forms[0].prefixLen)) == 1) {
  187. // Swap 0 and 1 because zero is represented as 1 and 1 is handled specially
  188. if (director == 1) { director--; }
  189. } else if (director) {
  190. // Reuse the number 1 for 2 and 2 for 3 etc. to gain an extra slot in all other encodings.
  191. director++;
  192. }
  193. if ((s.forms[1].prefix & Bits_maxBits64(s.forms[1].prefixLen)) == 1) {
  194. // Swap 1 and 0 back if necessary.
  195. if (director == 0) { director++; }
  196. } else if (director) {
  197. // Or move the numbers down by one.
  198. director--;
  199. }
  200. uint64_t converted = (additional << s.forms[1].bitCount) | director;
  201. converted = (converted << s.forms[1].prefixLen) | s.forms[1].prefix;
  202. if ((converted & Bits_maxBits64(s.forms[1].prefixLen + s.forms[1].bitCount)) == 1) {
  203. // looks like a self-route
  204. Assert_true(label2 == EncodingScheme_convertLabel_INVALID);
  205. return convertLabel_SELF_ROUTE;
  206. }
  207. Assert_true(label2 == converted);
  208. uint64_t label3 = EncodingScheme_convertLabel(scheme, label2, iformNum);
  209. Assert_true(label3 == label);
  210. return 0;
  211. }
  212. static void convertLabelRand(struct Random* rand, struct EncodingScheme* scheme)
  213. {
  214. for (int i = 0; i < 100; i++) {
  215. int oformNum;
  216. do {
  217. oformNum = Random_uint8(rand) % scheme->count;
  218. } while (!oformNum);
  219. int iformNum = Random_uint8(rand) % oformNum;
  220. uint64_t label = Random_uint64(rand);
  221. label &= (UINT64_MAX >> (Random_uint8(rand) % 63));
  222. for (;;) {
  223. // make sure the label has the right prefix
  224. label <<= scheme->forms[iformNum].prefixLen;
  225. label |= scheme->forms[iformNum].prefix;
  226. Assert_true(EncodingScheme_getFormNum(scheme, label) == iformNum);
  227. if (Bits_log2x64(label) > 59) {
  228. // fall through
  229. } else {
  230. int ret = convertLabel(&scheme->forms[iformNum], &scheme->forms[oformNum], label);
  231. if (ret == convertLabel_SELF_ROUTE) {
  232. i--;
  233. break;
  234. } else if (ret == convertLabel_TOO_BIG) {
  235. // fall through
  236. } else if (!ret) {
  237. // success
  238. break;
  239. } else {
  240. Assert_true(0);
  241. }
  242. }
  243. label >>= scheme->forms[iformNum].prefixLen + 1;
  244. }
  245. }
  246. }
  247. static void isOneHopScheme(struct Allocator* allocator)
  248. {
  249. struct Allocator* alloc = Allocator_child(allocator);
  250. struct EncodingScheme* s4x8 = NumberCompress_v4x8_defineScheme(alloc);
  251. Assert_true(!EncodingScheme_isOneHop(s4x8, 1));
  252. Assert_true(EncodingScheme_isOneHop(s4x8, 0x21));
  253. Assert_true(EncodingScheme_isOneHop(s4x8, 0x23));
  254. Assert_true(!EncodingScheme_isOneHop(s4x8, 0x12));
  255. Assert_true(EncodingScheme_isOneHop(s4x8, 0x220));
  256. Assert_true(EncodingScheme_isOneHop(s4x8, 0x210));
  257. Assert_true(!EncodingScheme_isOneHop(s4x8, 0x110));
  258. struct EncodingScheme* s3x5x8 = NumberCompress_v3x5x8_defineScheme(alloc);
  259. Assert_true(!EncodingScheme_isOneHop(s3x5x8, 1));
  260. Assert_true(EncodingScheme_isOneHop(s3x5x8, 0x13));
  261. Assert_true(EncodingScheme_isOneHop(s3x5x8, 0x15));
  262. Assert_true(EncodingScheme_isOneHop(s3x5x8, 0x96));
  263. Assert_true(EncodingScheme_isOneHop(s3x5x8, 0x400));
  264. Assert_true(!EncodingScheme_isOneHop(s3x5x8, 0x115));
  265. Assert_true(!EncodingScheme_isOneHop(s3x5x8, 0x166));
  266. Assert_true(!EncodingScheme_isOneHop(s3x5x8, 0x1400));
  267. Allocator_free(alloc);
  268. }
  269. int main()
  270. {
  271. struct Allocator* alloc = MallocAllocator_new(20000000);
  272. struct Random* rand = Random_new(alloc, NULL, NULL);
  273. encoding(alloc);
  274. isOneHopScheme(alloc);
  275. for (int i = 0; i < 1000; i++) {
  276. randomTest(alloc, rand);
  277. }
  278. for (int i = 0; i < 1000; i++) {
  279. fuzzTest(alloc, rand);
  280. }
  281. // for testing individual conversions in isolation.
  282. /*convertLabel(
  283. &(struct EncodingScheme_Form){.bitCount = 15, .prefixLen = 20, .prefix = 792003},
  284. &(struct EncodingScheme_Form){.bitCount = 31, .prefixLen = 30, .prefix = 385462496},
  285. 11331704259
  286. );*/
  287. for (int i = 0; i < 10; i++) {
  288. struct Allocator* tempAlloc = Allocator_child(alloc);
  289. struct EncodingScheme* scheme = randomScheme(rand, tempAlloc);
  290. convertLabelRand(rand, scheme);
  291. Allocator_free(tempAlloc);
  292. }
  293. struct Allocator* tempAlloc = Allocator_child(alloc);
  294. struct EncodingScheme* scheme = NumberCompress_v3x5x8_defineScheme(alloc);
  295. for (int i = 0; i < NumberCompress_v3x5x8_INTERFACES; i++) {
  296. int bits = NumberCompress_bitsUsedForNumber(i);
  297. uint64_t expected = NumberCompress_getCompressed(i, bits);
  298. Assert_true(expected == EncodingScheme_convertLabel(scheme, expected,
  299. EncodingScheme_convertLabel_convertTo_CANNONICAL));
  300. }
  301. Allocator_free(tempAlloc);
  302. return 0;
  303. }