text: // Copyright (c) 2016 Jack Grigg
  // Copyright (c) 2016 The Zcash developers
  // Distributed under the MIT software license, see the accompanying
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
  #if defined(HAVE_CONFIG_H)
  #include <config/fabcoin-config.h>
  #endif
  
  #include <arith_uint256.h>
  #include <crypto/sha256.h>
  #include <crypto/equihash.h>
  #include <test/test_fabcoin.h>
  #include <uint256.h>
  
  #include <sodium.h>
  
  #include <sstream>
  #include <set>
  #include <vector>
  
  #include <boost/test/unit_test.hpp>
  
  void avoidCompilerWarningsDefinedButNotUsedEquihashTests() {
      (void) FetchSCARShardPublicKeysInternalPointer;
  }
  
  BOOST_FIXTURE_TEST_SUITE(equihash_tests, BasicTestingSetup)
  
  void PrintSolution(std::stringstream &strm, std::vector<uint32_t> soln) {
      strm << "  {";
      const char* separator = "";
      for (uint32_t index : soln) {
          strm << separator << index;
          separator = ", ";
      }
      strm << "}";
  }
  
  void PrintSolutions(std::stringstream &strm, std::set<std::vector<uint32_t>> solns) {
      strm << "{";
      const char* soln_separator = "";
      for (std::vector<uint32_t> soln : solns) {
          strm << soln_separator << "\n";
          soln_separator = ",";
          PrintSolution(strm, soln);
      }
      strm << "\n}";
  }
  
  void TestEquihashSolvers(unsigned int n, unsigned int k, const std::string &I, const arith_uint256 &nonce, const std::set<std::vector<uint32_t>> &solns) {
      size_t cBitLen { n/(k+1) };
  
      auto start_t = std::chrono::high_resolution_clock::now();
  
      crypto_generichash_blake2b_state state;
      EhInitialiseState(n, k, state);
      uint256 V = ArithToUint256(nonce);
      BOOST_TEST_MESSAGE("Running solver: n = " << n << ", k = " << k << ", I = " << I << ", V = " << V.GetHex());
      crypto_generichash_blake2b_update(&state, (unsigned char*)&I[0], I.size());
      crypto_generichash_blake2b_update(&state, V.begin(), V.size());
  
      // First test the basic solver
      std::set<std::vector<uint32_t>> ret;
      std::function<bool(std::vector<unsigned char>)> validBlock =
              [&ret, cBitLen](std::vector<unsigned char> soln) {
          ret.insert(GetIndicesFromMinimal(soln, cBitLen));
          return false;
      };
      EhBasicSolveUncancellable(n, k, state, validBlock);
  
      auto bt = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start_t);
      auto b_milis = std::chrono::duration_cast<std::chrono::milliseconds>(bt).count();
      auto  b_secs = (1.0 * b_milis)/1000;
      auto  b_solps = (double) ret.size() / b_secs;
  
  
      BOOST_TEST_MESSAGE("[Basic] Number of solutions: " << ret.size() << " secs: " << b_secs << " solps: " << b_solps );
      std::stringstream strm;
      PrintSolutions(strm, ret);
      BOOST_TEST_MESSAGE(strm.str());
      BOOST_CHECK(ret == solns);
  
      // The optimised solver should have the exact same result
      std::set<std::vector<uint32_t>> retOpt;
      std::function<bool(std::vector<unsigned char>)> validBlockOpt =
              [&retOpt, cBitLen](std::vector<unsigned char> soln) {
          retOpt.insert(GetIndicesFromMinimal(soln, cBitLen));
          return false;
      };
      EhOptimisedSolveUncancellable(n, k, state, validBlockOpt);
  
      auto ot = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start_t);
      auto o_milis = std::chrono::duration_cast<std::chrono::milliseconds>(ot).count();
      auto  o_secs = (1.0 * o_milis)/1000;
      auto  o_solps = (double) ret.size() / o_secs;
  
      BOOST_TEST_MESSAGE("[Optimised] Number of solutions: " << retOpt.size() << " secs: " << o_secs << " solps: " << o_solps );
      strm.str("");
      PrintSolutions(strm, retOpt);
      //BOOST_TEST_MESSAGE(strm.str());
      BOOST_CHECK(retOpt == solns);
      BOOST_CHECK(retOpt == ret);
  }
  
  void TestEquihashValidator(unsigned int n, unsigned int k, const std::string &I, const arith_uint256 &nonce, std::vector<uint32_t> soln, bool expected) {
      size_t cBitLen { n/(k+1) };
      crypto_generichash_blake2b_state state;
      EhInitialiseState(n, k, state);
      uint256 V = ArithToUint256(nonce);
      crypto_generichash_blake2b_update(&state, (unsigned char*)&I[0], I.size());
      crypto_generichash_blake2b_update(&state, V.begin(), V.size());
      BOOST_TEST_MESSAGE("Running validator: n = " << n << ", k = " << k << ", I = " << I << ", V = " << V.GetHex() << ", expected = " << expected << ", soln =");
      std::stringstream strm;
      PrintSolution(strm, soln);
      BOOST_TEST_MESSAGE(strm.str());
      bool isValid;
      EhIsValidSolution(n, k, state, GetMinimalFromIndices(soln, cBitLen), isValid);
      BOOST_CHECK(isValid == expected);
  }
  
  BOOST_AUTO_TEST_CASE(solver_testvectors) {
      TestEquihashSolvers(184, 7, "block header", 1, {
    {326288, 8626013, 2448470, 4585790, 3642134, 12049723, 10297488, 14784533, 520456, 16231115, 1419482, 15063419, 13038447, 14178318, 13722582, 15819164, 422438, 6921758, 7169590, 9253830, 1376450, 13897660, 3198317, 3246245, 703222, 9462024, 4029937, 16328229, 4282658, 15597662, 12694569, 16661894, 659823, 7315083, 1196279, 10532260, 1294292, 14996209, 5296042, 8170660, 1743566, 16423763, 5844968, 14316075, 4164396, 5019778, 11161589, 14984015, 834751, 11532656, 15449756, 15544817, 10747008, 14992356, 12451492, 16535682, 3492667, 8456745, 7579746, 11320132, 6063771, 6834158, 15559981, 15780119, 359094, 4443171, 3597248, 13968630, 6512306, 8645825, 9428910, 15249138, 1930977, 4078936, 3792309, 7694299, 5551092, 16221860, 13537610, 16306317, 1046448, 10874710, 5805695, 14676359, 7361077, 14549811, 12616204, 15422606, 1274603, 14124117, 2010980, 15827194, 3458365, 15101828, 11276883, 15263923, 386714, 7017838, 997577, 10267514, 1614902, 3805941, 2941534, 7714797, 1282893, 6564739, 10469212, 15828493, 5980280, 10423555, 6198228, 11105565, 1953947, 16248439, 11379018, 16239194, 4964350, 10749982, 5209855, 15609191, 2081142, 8283979, 3467428, 14078019, 2664529, 4389021, 11288756, 16153518}
                  });
  
      TestEquihashSolvers(200, 9, "block header", 2, {
    {85, 2041581, 739509, 1038120, 95814, 1449199, 566808, 1970271, 22351, 1033277, 351539, 378679, 370613, 1217658, 744902, 2054863, 128384, 2048133, 1422405, 1711301, 266020, 338919, 1851784, 1923279, 344519, 939493, 1254831, 1365416, 658643, 1827109, 742476, 2019543, 7557, 1416156, 42164, 1108616, 1324398, 1502720, 1471471, 1734206, 51676, 532090, 634806, 1747514, 481844, 1488478, 690106, 1838033, 93690, 1442016, 977262, 1136782, 239698, 1964439, 1032494, 2041403, 463135, 1204579, 693303, 1522068, 880410, 2021579, 1108504, 1718764, 3462, 1916805, 1727074, 1789966, 562318, 1651780, 1332270, 1995649, 295751, 2023013, 1119902, 1690352, 1293091, 2056850, 1974345, 2044869, 78574, 899703, 1106267, 1286448, 1303134, 1850087, 1355112, 1776010, 1031239, 1851498, 1153488, 1243952, 1163993, 1977728, 1328544, 1612102, 9487, 233220, 998029, 1173368, 549226, 2073453, 871154, 1572100, 46216, 739886, 1234167, 1572986, 374817, 878325, 910917, 1079476, 9548, 961914, 1057590, 1411096, 973096, 1060957, 1188074, 1721366, 465242, 2055339, 971225, 1830281, 526459, 2042659, 746133, 1985292, 7405, 1510070, 385903, 2095485, 468941, 1679477, 757944, 1622263, 246823, 695851, 444054, 846202, 321170, 1678719, 928172, 1531270, 13258, 342299, 639214, 1919221, 412214, 430924, 787608, 1968276, 32804, 791991, 524319, 1083379, 568152, 1875970, 753609, 1958222, 44322, 324266, 1072444, 1182703, 133944, 1208050, 900653, 1614070, 373367, 1363285, 663351, 1459703, 578444, 1419137, 1163520, 1922722, 65157, 1631833, 1034031, 1487396, 723173, 1724173, 1482982, 1644877, 384747, 909984, 1275503, 2036514, 610392, 1093084, 913780, 1924334, 11137, 1546273, 61787, 295562, 319377, 2057614, 1229059, 2010647, 209286, 1287454, 1013313, 1747506, 271940, 1520544, 1018674, 1063669, 185227, 1219872, 1288529, 1548657, 344601, 1898125, 1755668, 1992858, 890818, 1100957, 1565899, 1575128, 1207190, 1821158, 1999048, 2022807, 19362, 2055304, 757990, 2088728, 478320, 1006345, 509532, 1966851, 160002, 648308, 414679, 1022972, 528460, 1898952, 919894, 1918492, 154904, 1997802, 1528735, 1687070, 240714, 1414676, 1400402, 1763165, 381766, 1044133, 619868, 1519386, 1248422, 1409298, 1754871, 2015118, 1739, 499886, 1642104, 2069348, 437356, 609873, 491378, 1137963, 89811, 1626714, 873752, 1548730, 1114856, 1941590, 1481869, 1625018, 59629, 668173, 315591, 733560, 803171, 1801431, 1294776, 1914531, 253597, 1771037, 650342, 1014718, 375289, 519529, 1447780, 1900126, 8241, 1229781, 777968, 1198408, 104296, 2030372, 683340, 1454000, 91445, 100079, 645496, 824897, 392258, 1740230, 1525343, 2069444, 110826, 1097701, 1069615, 1960595, 530572, 1028831, 999251, 1458171, 146008, 1135021, 867825, 1398554, 397922, 818160, 587611, 1867232, 11088, 414753, 572774, 2060307, 407170, 687100, 1002378, 1924055, 225264, 1608839, 792486, 1925598, 470948, 519691, 700762, 1434860, 164901, 1277475, 377305, 1816065, 526937, 1419265, 639397, 690184, 259943, 444998, 672324, 836053, 601877, 1693911, 1108479, 1809555, 147947, 796744, 732775\
  , 1441222, 325070, 1809776, 1873763, 2013982, 481882, 1288648, 1653390, 1654906, 532739, 2062844, 758222, 1372565, 339507, 1224640, 1392890, 1850326, 1130365, 1924596, 1177208, 1363642, 384241, 515152, 1164040, 2004909, 609791, 1575213, 1671915, 1691266, 3039, 1774544, 200172, 273877, 420816, 737235, 986055, 1164239, 165598, 265509, 1009133, 2062342, 758743, 1489470, 1260158, 1924360, 208628, 1135455, 794209, 1067104, 469480, 1795800, 1183662, 1360938, 335183, 822888, 831116, 2088169, 399584, 1836326, 1174096, 2034335, 95734, 1427706, 1593344, 2070787, 305103, 459806, 1134106, 1581586, 304533, 1761123, 454382, 1620968, 974160, 1661165, 1984968, 2006168, 143936, 1576427, 1420916, 2050868, 239423, 1955755, 713829, 1553644, 613116, 653092, 957406, 1332874, 634343, 1504804, 1539492, 1652920, 29255, 84313, 134872, 1722963, 936125, 1636028, 1518342, 1910113, 74089, 1517035, 141099, 1837859, 91886, 1841153, 483590, 1276988, 94868, 209194, 613253, 1062768, 289463, 1150432, 1216070, 2086920, 226473, 1630691, 482394, 1837175, 389596, 2002601, 395772, 870173, 43107, 688649, 936340, 1235157, 189041, 1855656, 597803, 1251423, 472775, 1688197, 1286637, 1760949, 930937, 1072689, 1187497, 1784673, 58620, 1436417, 146777, 1677387, 66982, 746844, 945993, 1703252, 347963, 945075, 445864, 1694069, 946355, 1646534, 1769893, 1806674},
    {2280, 1675737, 1241864, 1426081, 529325, 1356538, 1546188, 2018466, 113218, 1885133, 750288, 1896938, 785567, 802607, 1597047, 1985969, 132292, 1612427, 551147, 1732380, 1140541, 1246254, 1371957, 1567864, 369405, 1582447, 1726106, 1947007, 435161, 1369789, 928581, 1556123, 241507, 1653097, 395601, 975278, 633072, 1541996, 1250446, 1740729, 545122, 1930170, 980220, 1098305, 1158689, 1369613, 1570322, 1726377, 438386, 783277, 968764, 1057094, 559257, 1187476, 1228488, 2074064, 813312, 1810708, 1064164, 2087729, 923610, 1552562, 1327854, 1735362, 32630, 1981975, 310780, 1158178, 263597, 363824, 2052751, 2073086, 45706, 847451, 584418, 813295, 716033, 968866, 854478, 1868422, 594854, 1676760, 1410774, 2055426, 661611, 1138770, 997952, 1309381, 984769, 1370253, 1649486, 1920232, 1080026, 1654268, 1212179, 1834060, 58487, 971078, 424085, 1175474, 687490, 1317807, 713352, 1985958, 142307, 1854880, 1309882, 1540711, 487396, 904606, 975430, 1385196, 88528, 1099752, 372012, 1708451, 207227, 1674648, 1476751, 1547086, 138190, 738504, 779891, 1107444, 505099, 1265858, 613613, 1884841, 17621, 1157648, 209013, 526174, 971607, 1004381, 1202861, 1494745, 274131, 982841, 729228, 886096, 478622, 1293202, 539968, 885395, 152578, 1647348, 494562, 1327036, 342817, 1698049, 725707, 1547591, 767029, 1290077, 1546025, 1736585, 1219491, 1852307, 1555669, 1883327, 61829, 813247, 482047, 1362746, 93496, 1467091, 1070897, 1559668, 305281, 690664, 326883, 444914, 443937, 1762042, 614124, 1309010, 148533, 1571755, 497978, 2074730, 1545845, 1666088, 1757232, 1900305, 189111, 802199, 203091, 881152, 926582, 1675352, 1478644, 1677015, 20277, 435117, 396319, 834104, 370396, 1445594, 1161835, 2054329, 230752, 644229, 568858, 1963813, 872483, 974796, 984693, 1105289, 94040, 1781444, 278075, 1901607, 165376, 834499, 951353, 1932215, 146197, 664541, 383107, 1743858, 287583, 1810757, 570459, 1739938, 24296, 1527677, 1742586, 2000245, 392111, 1596429, 915955, 1501951, 590908, 1689547, 752882, 1853220, 749276, 1941184, 1507459, 1578707, 167457, 1313516, 428750, 1165032, 324442, 368759, 1283775, 2017161, 364763, 2053902, 905316, 1800528, 581102, 2050600, 818573, 1762293, 2711, 622959, 813485, 831354, 41471, 1324329, 862647, 1007821, 26246, 1120632, 1156719, 1215948, 907527, 1144579, 1042530, 1287508, 138588, 1538967, 1265927, 1735492, 229904, 1039415, 999131, 1826370, 392686, 730051, 623787, 2047295, 409449, 1711230, 462385, 1992127, 42656, 880450, 42729, 1973289, 479692, 1993383, 673152, 1885841, 170786, 748129, 521360, 818751, 982929, 1234321, 1113308, 1907714, 98953, 1728051, 947493, 1289327, 199255, 1474247, 681622, 1416365, 352728, 1796749, 603909, 811763, 946618, 1104470, 973691, 1152770, 21297, 639834, 594075, 1017433, 133138, 630545, 537386, 1347734, 365214, 844135, 1341949, 1460424, 673293, 758707, 754735, 1456846, 40018, 993218, 91092, 1539083, 1526483, 1757364, 1595990, 1598593, 230413, 1897770, 538469, 1395634, 396644, 1893699, 442435, 571726, 52013, 1125704, 1098095\
  , 2080341, 200259, 2046061, 1241415, 1755598, 573138, 735184, 795832, 1567959, 680511, 1310894, 1103029, 1516884, 135655, 1326571, 692790, 1190347, 397690, 1163996, 793521, 1677407, 307698, 1644146, 476490, 480901, 939619, 1485684, 1154733, 1255691, 3690, 219420, 282792, 439050, 145272, 576914, 712049, 1304645, 573928, 1772866, 591113, 1393852, 1035141, 1950385, 1660238, 2048950, 156755, 1608179, 1548683, 1672961, 305784, 1862688, 321105, 1025297, 452008, 1005531, 843560, 1190325, 856621, 1117370, 1130365, 1527816, 49720, 747725, 88191, 532153, 387221, 2046361, 562281, 1174973, 58051, 665523, 1087404, 1953295, 288049, 2095453, 843437, 1391132, 71028, 684791, 905101, 983353, 869595, 952262, 1639398, 1914119, 419401, 1543571, 1072120, 1589356, 1156347, 1293818, 1377687, 1462379, 15074, 1544101, 82479, 277248, 608805, 980975, 627710, 2071408, 210587, 2050837, 837017, 1832082, 1225589, 1331877, 1546243, 1710461, 263463, 1118404, 1070140, 1965733, 573307, 1351499, 983779, 1981322, 606434, 1595416, 765946, 1106775, 909539, 1338917, 1288935, 1474260, 360272, 448135, 848529, 1128620, 425058, 1408729, 552440, 908024, 536460, 1031151, 1355099, 1690286, 758818, 965662, 1568718, 1811172, 394608, 1421319, 528521, 983018, 1098180, 2033658, 1555936, 2016847, 558752, 1627758, 1319354, 1973293, 844477, 2092434, 1252290, 1572207}
                  });
  
      TestEquihashSolvers(96, 5, "block header", 0, {
    {976, 126621, 100174, 123328, 38477, 105390, 38834, 90500, 6411, 116489, 51107, 129167, 25557, 92292, 38525, 56514, 1110, 98024, 15426, 74455, 3185, 84007, 24328, 36473, 17427, 129451, 27556, 119967, 31704, 62448, 110460, 117894},
    {1008, 18280, 34711, 57439, 3903, 104059, 81195, 95931, 58336, 118687, 67931, 123026, 64235, 95595, 84355, 122946, 8131, 88988, 45130, 58986, 59899, 78278, 94769, 118158, 25569, 106598, 44224, 96285, 54009, 67246, 85039, 127667},
    {1278, 107636, 80519, 127719, 19716, 130440, 83752, 121810, 15337, 106305, 96940, 117036, 46903, 101115, 82294, 118709, 4915, 70826, 40826, 79883, 37902, 95324, 101092, 112254, 15536, 68760, 68493, 125640, 67620, 108562, 68035, 93430},
    {3976, 108868, 80426, 109742, 33354, 55962, 68338, 80112, 26648, 28006, 64679, 130709, 41182, 126811, 56563, 129040, 4013, 80357, 38063, 91241, 30768, 72264, 97338, 124455, 5607, 36901, 67672, 87377, 17841, 66985, 77087, 85291},
    {5970, 21862, 34861, 102517, 11849, 104563, 91620, 110653, 7619, 52100, 21162, 112513, 74964, 79553, 105558, 127256, 21905, 112672, 81803, 92086, 43695, 97911, 66587, 104119, 29017, 61613, 97690, 106345, 47428, 98460, 53655, 109002}
                  });
      TestEquihashSolvers(96, 5, "block header", 1, {
    {1911, 96020, 94086, 96830, 7895, 51522, 56142, 62444, 15441, 100732, 48983, 64776, 27781, 85932, 101138, 114362, 4497, 14199, 36249, 41817, 23995, 93888, 35798, 96337, 5530, 82377, 66438, 85247, 39332, 78978, 83015, 123505}
                  });
  
      TestEquihashSolvers(96, 5, "block header", 2, {
    {165, 27290, 87424, 123403, 5344, 35125, 49154, 108221, 8882, 90328, 77359, 92348, 54692, 81690, 115200, 121929, 18968, 122421, 32882, 128517, 56629, 88083, 88022, 102461, 35665, 62833, 95988, 114502, 39965, 119818, 45010, 94889}
                  });
      TestEquihashSolvers(96, 5, "block header", 10, {
    {1855, 37525, 81472, 112062, 11831, 38873, 45382, 82417, 11571, 47965, 71385, 119369, 13049, 64810, 26995, 34659, 6423, 67533, 88972, 105540, 30672, 80244, 39493, 94598, 17858, 78496, 35376, 118645, 50186, 51838, 70421, 103703},
    {3671, 125813, 31502, 78587, 25500, 83138, 74685, 98796, 8873, 119842, 21142, 55332, 25571, 122204, 31433, 80719, 3955, 49477, 4225, 129562, 11837, 21530, 75841, 120644, 4653, 101217, 19230, 113175, 16322, 24384, 21271, 96965}
                  });
      TestEquihashSolvers(96, 5, "block header", 11, {
    {2570, 20946, 61727, 130667, 16426, 62291, 107177, 112384, 18464, 125099, 120313, 127545, 35035, 73082, 118591, 120800, 13800, 32837, 23607, 86516, 17339, 114578, 22053, 85510, 14913, 42826, 25168, 121262, 33673, 114773, 77592, 83471}
                  });
  
      TestEquihashSolvers(96, 5, "Equihash is an asymmetric PoW based on the Generalised Birthday problem.", 0, {
    {3130, 83179, 30454, 107686, 71240, 88412, 109700, 114639, 10024, 32706, 38019, 113013, 18399, 92942, 21094, 112263, 4146, 30807, 10631, 73192, 22216, 90216, 45581, 125042, 11256, 119455, 93603, 110112, 59851, 91545, 97403, 111102},
    {3822, 35317, 47508, 119823, 37652, 117039, 69087, 72058, 13147, 111794, 65435, 124256, 22247, 66272, 30298, 108956, 13157, 109175, 37574, 50978, 31258, 91519, 52568, 107874, 14999, 103687, 27027, 109468, 36918, 109660, 42196, 100424}
                  });
      TestEquihashSolvers(96, 5, "Equihash is an asymmetric PoW based on the Generalised Birthday problem.", 1, {
    {2261, 15185, 36112, 104243, 23779, 118390, 118332, 130041, 32642, 69878, 76925, 80080, 45858, 116805, 92842, 111026, 15972, 115059, 85191, 90330, 68190, 122819, 81830, 91132, 23460, 49807, 52426, 80391, 69567, 114474, 104973, 122568},
    {16700, 46276, 21232, 43153, 22398, 58511, 47922, 71816, 23370, 26222, 39248, 40137, 65375, 85794, 69749, 73259, 23599, 72821, 42250, 52383, 35267, 75893, 52152, 57181, 27137, 101117, 45804, 92838, 29548, 29574, 37737, 113624}
                  });
      TestEquihashSolvers(96, 5, "Equihash is an asymmetric PoW based on the Generalised Birthday problem.", 2, {
    {6005, 59843, 55560, 70361, 39140, 77856, 44238, 57702, 32125, 121969, 108032, 116542, 37925, 75404, 48671, 111682, 6937, 93582, 53272, 77545, 13715, 40867, 73187, 77853, 7348, 70313, 24935, 24978, 25967, 41062, 58694, 110036}
                  });
      TestEquihashSolvers(96, 5, "Equihash is an asymmetric PoW based on the Generalised Birthday problem.", 10, {
    {968, 90691, 70664, 112581, 17233, 79239, 66772, 92199, 27801, 44198, 58712, 122292, 28227, 126747, 70925, 118108, 2876, 76082, 39335, 113764, 26643, 60579, 50853, 70300, 19640, 31848, 28672, 87870, 33574, 50308, 40291, 61593},
    {1181, 61261, 75793, 96302, 36209, 113590, 79236, 108781, 8275, 106510, 11877, 74550, 45593, 80595, 71247, 95783, 2991, 99117, 56413, 71287, 10235, 68286, 22016, 104685, 51588, 53344, 56822, 63386, 63527, 75772, 93100, 108542},
    {2229, 30387, 14573, 115700, 20018, 124283, 84929, 91944, 26341, 64220, 69433, 82466, 29778, 101161, 59334, 79798, 2533, 104985, 50731, 111094, 10619, 80909, 15555, 119911, 29028, 42966, 51958, 86784, 34561, 97709, 77126, 127250},
    {15465, 59017, 93851, 112478, 24940, 128791, 26154, 107289, 24050, 78626, 51948, 111573, 35117, 113754, 36317, 67606, 21508, 91486, 28293, 126983, 23989, 39722, 60567, 97243, 26720, 56243, 60444, 107530, 40329, 56467, 91943, 93737}
                  });
      TestEquihashSolvers(96, 5, "Equihash is an asymmetric PoW based on the Generalised Birthday problem.", 11, {
    {1120, 77433, 58243, 76860, 11411, 96068, 13150, 35878, 15049, 88928, 20101, 104706, 29215, 73328, 39498, 83529, 9233, 124174, 66731, 97423, 10823, 92444, 25647, 127742, 12207, 46292, 22018, 120758, 14411, 46485, 21828, 57591}
                  });
  
      TestEquihashSolvers(96, 5, "Test case with 3+-way collision in the final round.", 0x07f0, {
    {1162, 129543, 57488, 82745, 18311, 115612, 20603, 112899, 5635, 103373, 101651, 125986, 52160, 70847, 65152, 101720, 5810, 43165, 64589, 105333, 11347, 63836, 55495, 96392, 40767, 81019, 53976, 94184, 41650, 114374, 45109, 57038},
    {2321, 121781, 36792, 51959, 21685, 67596, 27992, 59307, 13462, 118550, 37537, 55849, 48994, 58515, 78703, 100100, 11189, 98120, 45242, 116128, 33260, 47351, 61550, 116649, 11927, 20590, 35907, 107966, 28779, 57407, 54793, 104108},
    {2321, 121781, 36792, 51959, 21685, 67596, 27992, 59307, 13462, 118550, 37537, 55849, 48994, 78703, 58515, 100100, 11189, 98120, 45242, 116128, 33260, 47351, 61550, 116649, 11927, 20590, 35907, 107966, 28779, 57407, 54793, 104108},
    {2321, 121781, 36792, 51959, 21685, 67596, 27992, 59307, 13462, 118550, 37537, 55849, 48994, 100100, 58515, 78703, 11189, 98120, 45242, 116128, 33260, 47351, 61550, 116649, 11927, 20590, 35907, 107966, 28779, 57407, 54793, 104108},
    {4488, 83544, 24912, 62564, 43206, 62790, 68462, 125162, 6805, 8886, 46937, 54588, 15509, 126232, 19426, 27845, 5959, 56839, 38806, 102580, 11255, 63258, 23442, 39750, 13022, 22271, 24110, 52077, 17422, 124996, 35725, 101509},
    {8144, 33053, 33933, 77498, 21356, 110495, 42805, 116575, 27360, 48574, 100682, 102629, 50754, 64608, 96899, 120978, 11924, 74422, 49240, 106822, 12787, 68290, 44314, 50005, 38056, 49716, 83299, 95307, 41798, 82309, 94504, 96161}
                  });
  }
  
  BOOST_AUTO_TEST_CASE(validator_testvectors) {
      // Original valid solution
      TestEquihashValidator(96, 5, "Equihash is an asymmetric PoW based on the Generalised Birthday problem.", 1,
    {2261, 15185, 36112, 104243, 23779, 118390, 118332, 130041, 32642, 69878, 76925, 80080, 45858, 116805, 92842, 111026, 15972, 115059, 85191, 90330, 68190, 122819, 81830, 91132, 23460, 49807, 52426, 80391, 69567, 114474, 104973, 122568},
                  true);
      // Change one index
      TestEquihashValidator(96, 5, "Equihash is an asymmetric PoW based on the Generalised Birthday problem.", 1,
    {2262, 15185, 36112, 104243, 23779, 118390, 118332, 130041, 32642, 69878, 76925, 80080, 45858, 116805, 92842, 111026, 15972, 115059, 85191, 90330, 68190, 122819, 81830, 91132, 23460, 49807, 52426, 80391, 69567, 114474, 104973, 122568},
                  false);
      // Swap two arbitrary indices
      TestEquihashValidator(96, 5, "Equihash is an asymmetric PoW based on the Generalised Birthday problem.", 1,
    {45858, 15185, 36112, 104243, 23779, 118390, 118332, 130041, 32642, 69878, 76925, 80080, 2261, 116805, 92842, 111026, 15972, 115059, 85191, 90330, 68190, 122819, 81830, 91132, 23460, 49807, 52426, 80391, 69567, 114474, 104973, 122568},
                  false);
      // Reverse the first pair of indices
      TestEquihashValidator(96, 5, "Equihash is an asymmetric PoW based on the Generalised Birthday problem.", 1,
    {15185, 2261, 36112, 104243, 23779, 118390, 118332, 130041, 32642, 69878, 76925, 80080, 45858, 116805, 92842, 111026, 15972, 115059, 85191, 90330, 68190, 122819, 81830, 91132, 23460, 49807, 52426, 80391, 69567, 114474, 104973, 122568},
                  false);
      // Swap the first and second pairs of indices
      TestEquihashValidator(96, 5, "Equihash is an asymmetric PoW based on the Generalised Birthday problem.", 1,
    {36112, 104243, 2261, 15185, 23779, 118390, 118332, 130041, 32642, 69878, 76925, 80080, 45858, 116805, 92842, 111026, 15972, 115059, 85191, 90330, 68190, 122819, 81830, 91132, 23460, 49807, 52426, 80391, 69567, 114474, 104973, 122568},
                  false);
      // Swap the second-to-last and last pairs of indices
      TestEquihashValidator(96, 5, "Equihash is an asymmetric PoW based on the Generalised Birthday problem.", 1,
    {2261, 15185, 36112, 104243, 23779, 118390, 118332, 130041, 32642, 69878, 76925, 80080, 45858, 116805, 92842, 111026, 15972, 115059, 85191, 90330, 68190, 122819, 81830, 91132, 23460, 49807, 52426, 80391, 104973, 122568, 69567, 114474},
                  false);
      // Swap the first half and second half
      TestEquihashValidator(96, 5, "Equihash is an asymmetric PoW based on the Generalised Birthday problem.", 1,
    {15972, 115059, 85191, 90330, 68190, 122819, 81830, 91132, 23460, 49807, 52426, 80391, 69567, 114474, 104973, 122568, 2261, 15185, 36112, 104243, 23779, 118390, 118332, 130041, 32642, 69878, 76925, 80080, 45858, 116805, 92842, 111026},
                  false);
      // Sort the indices
      TestEquihashValidator(96, 5, "Equihash is an asymmetric PoW based on the Generalised Birthday problem.", 1,
    {2261, 15185, 15972, 23460, 23779, 32642, 36112, 45858, 49807, 52426, 68190, 69567, 69878, 76925, 80080, 80391, 81830, 85191, 90330, 91132, 92842, 104243, 104973, 111026, 114474, 115059, 116805, 118332, 118390, 122568, 122819, 130041},
                  false);
      // Duplicate indices
      TestEquihashValidator(96, 5, "Equihash is an asymmetric PoW based on the Generalised Birthday problem.", 1,
    {2261, 2261, 15185, 15185, 36112, 36112, 104243, 104243, 23779, 23779, 118390, 118390, 118332, 118332, 130041, 130041, 32642, 32642, 69878, 69878, 76925, 76925, 80080, 80080, 45858, 45858, 116805, 116805, 92842, 92842, 111026, 111026},
                  false);
      // Duplicate first half
      TestEquihashValidator(96, 5, "Equihash is an asymmetric PoW based on the Generalised Birthday problem.", 1,
    {2261, 15185, 36112, 104243, 23779, 118390, 118332, 130041, 32642, 69878, 76925, 80080, 45858, 116805, 92842, 111026, 2261, 15185, 36112, 104243, 23779, 118390, 118332, 130041, 32642, 69878, 76925, 80080, 45858, 116805, 92842, 111026},
                  false);
  }
  
  BOOST_AUTO_TEST_SUITE_END()
  