codex32_tests.cpp raw

   1  // Copyright (c) 2023 The Limenka developers
   2  // Distributed under the MIT software license, see the accompanying
   3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   4  
   5  #include <bech32.h>
   6  #include <codex32.h>
   7  #include <test/util/str.h>
   8  
   9  #include <boost/test/unit_test.hpp>
  10  
  11  #include <array>
  12  #include <string>
  13  
  14  BOOST_AUTO_TEST_SUITE(codex32_tests)
  15  
  16  BOOST_AUTO_TEST_CASE(codex32_bip93_misc_invalid)
  17  {
  18      // This example uses a "0" threshold with a non-"s" index
  19      const std::string input1 = "ms10fauxxxxxxxxxxxxxxxxxxxxxxxxxxxx0z26tfn0ulw3p";
  20      const auto dec1 = codex32::Result{input1};
  21      BOOST_CHECK_EQUAL(dec1.error(), codex32::INVALID_SHARE_IDX);
  22  
  23      // This example has a threshold that is not a digit.
  24      const std::string input2 = "ms1fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxda3kr3s0s2swg";
  25      const auto dec2 = codex32::Result{input2};
  26      BOOST_CHECK_EQUAL(dec2.error(), codex32::INVALID_K);
  27  }
  28  
  29  BOOST_AUTO_TEST_CASE(codex32_bip93_vector_1)
  30  {
  31      const std::string input = "ms10testsxxxxxxxxxxxxxxxxxxxxxxxxxx4nzvca9cmczlw";
  32  
  33      const auto dec = codex32::Result{input};
  34      BOOST_CHECK(dec.IsValid());
  35      BOOST_CHECK_EQUAL(dec.error(), codex32::OK);
  36      BOOST_CHECK_EQUAL(dec.GetHrp(), "ms");
  37      BOOST_CHECK_EQUAL(dec.GetK(), 0);
  38      BOOST_CHECK_EQUAL(dec.GetIdString(), "test");
  39      BOOST_CHECK_EQUAL(dec.GetShareIndex(), 's');
  40  
  41      const auto payload = dec.GetPayload();
  42      BOOST_CHECK_EQUAL(payload.size(), 16);
  43      BOOST_CHECK_EQUAL(HexStr(payload), "318c6318c6318c6318c6318c6318c631");
  44  
  45      // Try re-encoding
  46      BOOST_CHECK_EQUAL(input, dec.Encode());
  47  
  48      // Try directly constructing the share
  49      const auto direct = codex32::Result("ms", 0, "test", 's', payload);
  50      BOOST_CHECK(direct.IsValid());
  51      BOOST_CHECK_EQUAL(direct.error(), codex32::OK);
  52      BOOST_CHECK_EQUAL(direct.GetIdString(), "test");
  53      BOOST_CHECK_EQUAL(direct.GetShareIndex(), 's');
  54  
  55      // We cannot check that the codex32 string is exactly the same as the
  56      // input, since it will not be -- the test vector has nonzero trailing
  57      // bits while our code will always choose zero trailing bits. But we
  58      // can at least check that the payloads are identical.
  59      const auto payload_direct = direct.GetPayload();
  60      BOOST_CHECK_EQUAL(HexStr(payload), HexStr(payload_direct));
  61  }
  62  
  63  BOOST_AUTO_TEST_CASE(codex32_bip93_vector_2)
  64  {
  65      const std::string input_a = "MS12NAMEA320ZYXWVUTSRQPNMLKJHGFEDCAXRPP870HKKQRM";
  66      const auto dec_a = codex32::Result{input_a};
  67      BOOST_CHECK(dec_a.IsValid());
  68      BOOST_CHECK_EQUAL(dec_a.GetHrp(), "ms");
  69      BOOST_CHECK_EQUAL(dec_a.GetK(), 2);
  70      BOOST_CHECK_EQUAL(dec_a.GetIdString(), "name");
  71      BOOST_CHECK_EQUAL(dec_a.GetShareIndex(), 'a');
  72      BOOST_CHECK(CaseInsensitiveEqual(input_a, dec_a.Encode()));
  73  
  74      const std::string input_c = "MS12NAMECACDEFGHJKLMNPQRSTUVWXYZ023FTR2GDZMPY6PN";
  75      const auto dec_c = codex32::Result{input_c};
  76      BOOST_CHECK(dec_c.IsValid());
  77      BOOST_CHECK_EQUAL(dec_c.GetHrp(), "ms");
  78      BOOST_CHECK_EQUAL(dec_c.GetK(), 2);
  79      BOOST_CHECK_EQUAL(dec_c.GetIdString(), "name");
  80      BOOST_CHECK_EQUAL(dec_c.GetShareIndex(), 'c');
  81      BOOST_CHECK(CaseInsensitiveEqual(input_c, dec_c.Encode()));
  82  
  83      const auto d = codex32::Result{{input_a, input_c}, 'd'};
  84      BOOST_CHECK(d.IsValid());
  85      BOOST_CHECK_EQUAL(d.GetHrp(), "ms");
  86      BOOST_CHECK_EQUAL(d.GetK(), 2);
  87      BOOST_CHECK_EQUAL(d.GetIdString(), "name");
  88      BOOST_CHECK_EQUAL(d.GetShareIndex(), 'd');
  89      BOOST_CHECK(CaseInsensitiveEqual("MS12NAMEDLL4F8JLH4E5VDVULDLFXU2JHDNLSM97XVENRXEG", d.Encode()));
  90  
  91      const auto err1 = codex32::Result{{}, 's'};
  92      BOOST_CHECK_EQUAL(err1.error(), codex32::TOO_FEW_SHARES);
  93      const auto err2 = codex32::Result{{input_c}, 's'};
  94      BOOST_CHECK_EQUAL(err2.error(), codex32::TOO_FEW_SHARES);
  95      const auto err3 = codex32::Result{{input_a, input_c}, 'b'};
  96      BOOST_CHECK_EQUAL(err3.error(), codex32::INVALID_SHARE_IDX);
  97  
  98      const auto s = codex32::Result{{input_a, input_c}, 's'};
  99      BOOST_CHECK(s.IsValid());
 100      BOOST_CHECK_EQUAL(s.GetHrp(), "ms");
 101      BOOST_CHECK_EQUAL(s.GetK(), 2);
 102      BOOST_CHECK_EQUAL(s.GetIdString(), "name");
 103      BOOST_CHECK_EQUAL(s.GetShareIndex(), 's');
 104      BOOST_CHECK(CaseInsensitiveEqual("MS12NAMES6XQGUZTTXKEQNJSJZV4JV3NZ5K3KWGSPHUH6EVW", s.Encode()));
 105  
 106      const auto seed = s.GetPayload();
 107      BOOST_CHECK_EQUAL(seed.size(), 16);
 108      BOOST_CHECK_EQUAL(HexStr(seed), "d1808e096b35b209ca12132b264662a5");
 109  }
 110  
 111  BOOST_AUTO_TEST_CASE(codex32_bip93_vector_3)
 112  {
 113      const auto s = codex32::Result("ms", 3, "Cash", 's', ParseHex("ffeeddccbbaa99887766554433221100"));
 114      BOOST_CHECK(s.IsValid());
 115      BOOST_CHECK_EQUAL(s.GetIdString(), "cash");
 116      BOOST_CHECK_EQUAL(s.GetShareIndex(), 's');
 117      BOOST_CHECK_EQUAL(s.GetK(), 3);
 118      BOOST_CHECK_EQUAL(s.Encode(), "ms13cashsllhdmn9m42vcsamx24zrxgs3qqjzqud4m0d6nln");
 119  
 120      const auto a = codex32::Result{"ms13casha320zyxwvutsrqpnmlkjhgfedca2a8d0zehn8a0t"};
 121      BOOST_CHECK(a.IsValid());
 122      BOOST_CHECK_EQUAL(a.GetIdString(), "cash");
 123      BOOST_CHECK_EQUAL(a.GetShareIndex(), 'a');
 124      BOOST_CHECK_EQUAL(a.GetK(), 3);
 125  
 126      const auto c = codex32::Result{"ms13cashcacdefghjklmnpqrstuvwxyz023949xq35my48dr"};
 127      BOOST_CHECK(c.IsValid());
 128      BOOST_CHECK_EQUAL(c.GetIdString(), "cash");
 129      BOOST_CHECK_EQUAL(c.GetShareIndex(), 'c');
 130      BOOST_CHECK_EQUAL(c.GetK(), 3);
 131  
 132      const auto err1 = codex32::Result{{}, 'd'};
 133      BOOST_CHECK_EQUAL(err1.error(), codex32::TOO_FEW_SHARES);
 134      const auto err2 = codex32::Result{{a, c}, 'd'};
 135      BOOST_CHECK_EQUAL(err2.error(), codex32::TOO_FEW_SHARES);
 136      const auto err3 = codex32::Result{{s, a}, 'd'};
 137      BOOST_CHECK_EQUAL(err3.error(), codex32::TOO_FEW_SHARES);
 138      const auto err4 = codex32::Result{{s, s, a}, 'd'};
 139      BOOST_CHECK_EQUAL(err4.error(), codex32::DUPLICATE_SHARE);
 140  
 141      const auto d = codex32::Result{{s, a, c}, 'd'};
 142      BOOST_CHECK(d.IsValid());
 143      BOOST_CHECK_EQUAL(d.GetIdString(), "cash");
 144      BOOST_CHECK_EQUAL(d.GetShareIndex(), 'd');
 145      BOOST_CHECK_EQUAL(d.GetK(), 3);
 146      BOOST_CHECK_EQUAL(d.Encode(), "ms13cashd0wsedstcdcts64cd7wvy4m90lm28w4ffupqs7rm");
 147  
 148      const auto e = codex32::Result{{a, c, d}, 'e'};
 149      BOOST_CHECK(e.IsValid());
 150      BOOST_CHECK_EQUAL(e.GetIdString(), "cash");
 151      BOOST_CHECK_EQUAL(e.GetShareIndex(), 'e');
 152      BOOST_CHECK_EQUAL(e.GetK(), 3);
 153      BOOST_CHECK_EQUAL(e.Encode(), "ms13casheekgpemxzshcrmqhaydlp6yhms3ws7320xyxsar9");
 154  
 155      const auto f = codex32::Result{{a, s, d}, 'f'};
 156      BOOST_CHECK(f.IsValid());
 157      BOOST_CHECK_EQUAL(f.GetIdString(), "cash");
 158      BOOST_CHECK_EQUAL(f.GetShareIndex(), 'f');
 159      BOOST_CHECK_EQUAL(f.GetK(), 3);
 160      BOOST_CHECK_EQUAL(f.Encode(), "ms13cashf8jh6sdrkpyrsp5ut94pj8ktehhw2hfvyrj48704");
 161  
 162      // Mismatched data
 163      const auto g1 = codex32::Result{"ms", 2, "cash", 'g', ParseHex("ffeeddccbbaa99887766554433221100")};
 164      BOOST_CHECK(g1.IsValid());
 165      const auto err_s1 = codex32::Result{{a, c, g1}, 's'};
 166      BOOST_CHECK_EQUAL(err_s1.error(), codex32::MISMATCH_K);
 167  
 168      const auto g2 = codex32::Result{"ms", 3, "leet", 'g', ParseHex("ffeeddccbbaa99887766554433221100")};
 169      BOOST_CHECK(g2.IsValid());
 170      const auto err_s2 = codex32::Result{{a, c, g2}, 's'};
 171      BOOST_CHECK_EQUAL(err_s2.error(), codex32::MISMATCH_ID);
 172  
 173      const auto g3 = codex32::Result{"ms", 3, "cash", 'g', ParseHex("ffeeddccbbaa99887766554433221100ab")};
 174      BOOST_CHECK(g3.IsValid());
 175      const auto err_s3 = codex32::Result{{a, c, g3}, 's'};
 176      BOOST_CHECK_EQUAL(err_s3.error(), codex32::MISMATCH_LENGTH);
 177  }
 178  
 179  BOOST_AUTO_TEST_CASE(codex32_bip93_vector_4)
 180  {
 181      const std::string seed = "ffeeddccbbaa99887766554433221100ffeeddccbbaa99887766554433221100";
 182      const auto s = codex32::Result{"ms", 0, "leet", 's', ParseHex(seed)};
 183      BOOST_CHECK(s.IsValid());
 184      BOOST_CHECK_EQUAL(s.GetIdString(), "leet");
 185      BOOST_CHECK_EQUAL(s.GetShareIndex(), 's');
 186      BOOST_CHECK_EQUAL(s.GetK(), 0);
 187      BOOST_CHECK_EQUAL(HexStr(s.GetPayload()), seed);
 188      BOOST_CHECK_EQUAL(s.Encode(), "ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqqtum9pgv99ycma");
 189  
 190      std::vector<std::string> alternates = {
 191          "ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqqtum9pgv99ycma",
 192          "ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqpj82dp34u6lqtd",
 193          "ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqzsrs4pnh7jmpj5",
 194          "ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqrfcpap2w8dqezy",
 195          "ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqy5tdvphn6znrf0",
 196          "ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyq9dsuypw2ragmel",
 197          "ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqx05xupvgp4v6qx",
 198          "ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyq8k0h5p43c2hzsk",
 199          "ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqgum7hplmjtr8ks",
 200          "ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqf9q0lpxzt5clxq",
 201          "ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyq28y48pyqfuu7le",
 202          "ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqt7ly0paesr8x0f",
 203          "ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqvrvg7pqydv5uyz",
 204          "ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqd6hekpea5n0y5j",
 205          "ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqwcnrwpmlkmt9dt",
 206          "ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyq0pgjxpzx0ysaam",
 207      };
 208      for (const auto& alt : alternates) {
 209          const auto s_alt = codex32::Result{alt};
 210          BOOST_CHECK(s_alt.IsValid());
 211          BOOST_CHECK_EQUAL(HexStr(s_alt.GetPayload()), seed);
 212      }
 213  }
 214  
 215  BOOST_AUTO_TEST_CASE(codex32_bip93_vector_5)
 216  {
 217      const auto s = codex32::Result{"MS100C8VSM32ZXFGUHPCHTLUPZRY9X8GF2TVDW0S3JN54KHCE6MUA7LQPZYGSFJD6AN074RXVCEMLH8WU3TK925ACDEFGHJKLMNPQRSTUVWXY06FHPV80UNDVARHRAK"};
 218      BOOST_CHECK(s.IsValid());
 219      BOOST_CHECK_EQUAL(s.error(), codex32::OK);
 220      BOOST_CHECK_EQUAL(s.GetIdString(), "0c8v");
 221      BOOST_CHECK_EQUAL(s.GetShareIndex(), 's');
 222      BOOST_CHECK_EQUAL(s.GetK(), 0);
 223      BOOST_CHECK_EQUAL(HexStr(s.GetPayload()), "dc5423251cb87175ff8110c8531d0952d8d73e1194e95b5f19d6f9df7c01111104c9baecdfea8cccc677fb9ddc8aec5553b86e528bcadfdcc201c17c638c47e9");
 224  }
 225  
 226  BOOST_AUTO_TEST_CASE(codex32_errors)
 227  {
 228      const std::vector<codex32::Result> errs = {
 229          codex32::Result("ms", 3, "cash", 's', ParseHex("ffeeddccbbaa99887766554433221100")),
 230          // bad hrp
 231          codex32::Result("bc", 3, "cash", 's', ParseHex("ffeeddccbbaa99887766554433221100")),
 232          // bad ID len
 233          codex32::Result("ms", 3, "cas", 's', ParseHex("ffeeddccbbaa99887766554433221100")),
 234          codex32::Result("ms", 3, "cashcashcash", 's', ParseHex("ffeeddccbbaa99887766554433221100")),
 235          codex32::Result("ms", 3, "", 's', ParseHex("ffeeddccbbaa99887766554433221100")),
 236          // bad id char
 237          codex32::Result("ms", 3, "bash", 's', ParseHex("ffeeddccbbaa99887766554433221100")),
 238          // bad k
 239          codex32::Result("ms", 1, "cash", 's', ParseHex("ffeeddccbbaa99887766554433221100")),
 240          codex32::Result("ms", 10, "cash", 's', ParseHex("ffeeddccbbaa99887766554433221100")),
 241          codex32::Result("ms", 100000, "cash", 's', ParseHex("ffeeddccbbaa99887766554433221100")),
 242          // bad share idx
 243          codex32::Result("ms", 100000, "cash", 'b', ParseHex("ffeeddccbbaa99887766554433221100")),
 244          codex32::Result("ms", 100000, "cash", 'i', ParseHex("ffeeddccbbaa99887766554433221100")),
 245          codex32::Result("ms", 100000, "cash", '1', ParseHex("ffeeddccbbaa99887766554433221100")),
 246          codex32::Result("ms", 100000, "cash", 'o', ParseHex("ffeeddccbbaa99887766554433221100")),
 247          codex32::Result("ms", 100000, "cash", ' ', ParseHex("ffeeddccbbaa99887766554433221100")),
 248      };
 249  
 250      BOOST_CHECK_EQUAL(errs[0].error(), codex32::OK);
 251      BOOST_CHECK_EQUAL(errs[1].error(), codex32::INVALID_HRP);
 252      BOOST_CHECK_EQUAL(errs[2].error(), codex32::INVALID_ID_LEN);
 253      BOOST_CHECK_EQUAL(errs[3].error(), codex32::INVALID_ID_LEN);
 254      BOOST_CHECK_EQUAL(errs[4].error(), codex32::INVALID_ID_LEN);
 255      BOOST_CHECK_EQUAL(errs[5].error(), codex32::INVALID_ID_CHAR);
 256      BOOST_CHECK_EQUAL(errs[6].error(), codex32::INVALID_K);
 257      BOOST_CHECK_EQUAL(errs[7].error(), codex32::INVALID_K);
 258      BOOST_CHECK_EQUAL(errs[8].error(), codex32::INVALID_K);
 259      BOOST_CHECK_EQUAL(errs[9].error(), codex32::INVALID_SHARE_IDX);
 260      BOOST_CHECK_EQUAL(errs[10].error(), codex32::INVALID_SHARE_IDX);
 261      BOOST_CHECK_EQUAL(errs[11].error(), codex32::INVALID_SHARE_IDX);
 262      BOOST_CHECK_EQUAL(errs[12].error(), codex32::INVALID_SHARE_IDX);
 263      BOOST_CHECK_EQUAL(errs[13].error(), codex32::INVALID_SHARE_IDX);
 264  
 265  }
 266  
 267  BOOST_AUTO_TEST_CASE(codex32_bip93_invalid_1)
 268  {
 269      std::vector<std::string> bad_checksum = {
 270          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxve740yyge2ghq",
 271          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxve740yyge2ghp",
 272          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxlk3yepcstwr",
 273          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxx6pgnv7jnpcsp",
 274          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxx0cpvr7n4geq",
 275          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxm5252y7d3lr",
 276          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxrd9sukzl05ej",
 277          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxc55srw5jrm0",
 278          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxgc7rwhtudwc",
 279          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxx4gy22afwghvs",
 280          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxme084q0vpht7pe0",
 281          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxme084q0vpht7pew",
 282          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxqyadsp3nywm8a",
 283          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzvg7ar4hgaejk",
 284          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcznau0advgxqe",
 285          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxch3jrc6j5040j",
 286          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx52gxl6ppv40mcv",
 287          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7g4g2nhhle8fk",
 288          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx63m45uj8ss4x8",
 289          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxy4r708q7kg65x",
 290      };
 291      for (const auto& bad : bad_checksum) {
 292          auto res = codex32::Result{bad};
 293          BOOST_CHECK_EQUAL(res.error(), codex32::BAD_CHECKSUM);
 294      }
 295  }
 296  
 297  BOOST_AUTO_TEST_CASE(codex32_bip93_invalid_2)
 298  {
 299      std::vector<std::string> bad_checksum = {
 300          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxurfvwmdcmymdufv",
 301          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxcsyppjkd8lz4hx3",
 302          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxu6hwvl5p0l9xf3c",
 303          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwqey9rfs6smenxa",
 304          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxv70wkzrjr4ntqet",
 305          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx3hmlrmpa4zl0v",
 306          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxrfggf88znkaup",
 307          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxpt7l4aycv9qzj",
 308          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxus27z9xtyxyw3",
 309          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcwm4re8fs78vn",
 310      };
 311      for (const auto& bad : bad_checksum) {
 312          auto res = codex32::Result{bad};
 313          BOOST_CHECK(res.error() == codex32::BAD_CHECKSUM || res.error() == codex32::INVALID_LENGTH);
 314      }
 315  }
 316  
 317  BOOST_AUTO_TEST_CASE(codex32_bip93_invalid_3)
 318  {
 319      std::vector<std::string> bad_checksum = {
 320          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxw0a4c70rfefn4",
 321          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxk4pavy5n46nea",
 322          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxx9lrwar5zwng4w",
 323          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxr335l5tv88js3",
 324          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxvu7q9nz8p7dj68v",
 325          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxpq6k542scdxndq3",
 326          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkmfw6jm270mz6ej",
 327          "ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxzhddxw99w7xws",
 328          "ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxx42cux6um92rz",
 329          "ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxarja5kqukdhy9",
 330          "ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxky0ua3ha84qk8",
 331          "ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx9eheesxadh2n2n9",
 332          "ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx9llwmgesfulcj2z",
 333          "ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx02ev7caq6n9fgkf",
 334      };
 335      for (const auto& bad : bad_checksum) {
 336          auto res = codex32::Result{bad};
 337          BOOST_CHECK_EQUAL(res.error(), codex32::INVALID_LENGTH);
 338      }
 339  }
 340  
 341  BOOST_AUTO_TEST_CASE(codex32_bip93_invalid_hrp)
 342  {
 343      std::vector<std::string> bad_checksum = {
 344          "0fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2",
 345          "10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2",
 346          "ms0fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2",
 347          "m10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2",
 348          "s10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2",
 349          "0fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxhkd4f70m8lgws",
 350          "10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxhkd4f70m8lgws",
 351          "m10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxx8t28z74x8hs4l",
 352          "s10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxh9d0fhnvfyx3x",
 353      };
 354      for (const auto& bad : bad_checksum) {
 355          auto res = codex32::Result{bad};
 356          BOOST_CHECK(res.error() == codex32::INVALID_HRP || res.error() == codex32::BECH32_DECODE);
 357      }
 358  }
 359  
 360  BOOST_AUTO_TEST_CASE(codex32_bip93_invalid_case)
 361  {
 362      std::vector<std::string> bad_checksum = {
 363          "Ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2",
 364          "mS10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2",
 365          "MS10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2",
 366          "ms10FAUXsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2",
 367          "ms10fauxSxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2",
 368          "ms10fauxsXXXXXXXXXXXXXXXXXXXXXXXXXXuqxkk05lyf3x2",
 369          "ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxUQXKK05LYF3X2",
 370      };
 371      for (const auto& bad : bad_checksum) {
 372          auto res = codex32::Result{bad};
 373          BOOST_CHECK_EQUAL(res.error(), codex32::BECH32_DECODE);
 374      }
 375  }
 376  
 377  BOOST_AUTO_TEST_SUITE_END()
 378