/ src / test / bech32_tests.cpp
bech32_tests.cpp
  1  // Copyright (c) 2017 Pieter Wuille
  2  // Copyright (c) 2021-present The Bitcoin Core developers
  3  // Distributed under the MIT software license, see the accompanying
  4  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  5  
  6  #include <bech32.h>
  7  #include <util/strencodings.h>
  8  
  9  #include <boost/test/unit_test.hpp>
 10  
 11  #include <string>
 12  
 13  BOOST_AUTO_TEST_SUITE(bech32_tests)
 14  
 15  BOOST_AUTO_TEST_CASE(bech32_testvectors_valid)
 16  {
 17      static const std::string CASES[] = {
 18          "A12UEL5L",
 19          "a12uel5l",
 20          "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs",
 21          "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
 22          "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j",
 23          "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
 24          "?1ezyfcl",
 25      };
 26      for (const std::string& str : CASES) {
 27          const auto dec = bech32::Decode(str);
 28          BOOST_CHECK(dec.encoding == bech32::Encoding::BECH32);
 29          std::string recode = bech32::Encode(bech32::Encoding::BECH32, dec.hrp, dec.data);
 30          BOOST_CHECK(!recode.empty());
 31          BOOST_CHECK(CaseInsensitiveEqual(str, recode));
 32      }
 33  }
 34  
 35  BOOST_AUTO_TEST_CASE(bech32m_testvectors_valid)
 36  {
 37      static const std::string CASES[] = {
 38          "A1LQFN3A",
 39          "a1lqfn3a",
 40          "an83characterlonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11sg7hg6",
 41          "abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx",
 42          "11llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllludsr8",
 43          "split1checkupstagehandshakeupstreamerranterredcaperredlc445v",
 44          "?1v759aa"
 45      };
 46      for (const std::string& str : CASES) {
 47          const auto dec = bech32::Decode(str);
 48          BOOST_CHECK(dec.encoding == bech32::Encoding::BECH32M);
 49          std::string recode = bech32::Encode(bech32::Encoding::BECH32M, dec.hrp, dec.data);
 50          BOOST_CHECK(!recode.empty());
 51          BOOST_CHECK(CaseInsensitiveEqual(str, recode));
 52      }
 53  }
 54  
 55  BOOST_AUTO_TEST_CASE(bech32_testvectors_invalid)
 56  {
 57      static const std::string CASES[] = {
 58          " 1nwldj5",
 59          "\x7f""1axkwrx",
 60          "\x80""1eym55h",
 61          "an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx",
 62          "pzry9x0s0muk",
 63          "1pzry9x0s0muk",
 64          "x1b4n0q5v",
 65          "li1dgmt3",
 66          "de1lg7wt\xff",
 67          "A1G7SGD8",
 68          "10a06t8",
 69          "1qzzfhee",
 70          "a12UEL5L",
 71          "A12uEL5L",
 72          "abcdef1qpzrz9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
 73          "test1zg69w7y6hn0aqy352euf40x77qddq3dc",
 74      };
 75      static const std::pair<std::string, std::vector<int>> ERRORS[] = {
 76          {"Invalid character or mixed case", {0}},
 77          {"Invalid character or mixed case", {0}},
 78          {"Invalid character or mixed case", {0}},
 79          {"Bech32 string too long", {90}},
 80          {"Missing separator", {}},
 81          {"Invalid separator position", {0}},
 82          {"Invalid Base 32 character", {2}},
 83          {"Invalid separator position", {2}},
 84          {"Invalid character or mixed case", {8}},
 85          {"Invalid checksum", {}}, // The checksum is calculated using the uppercase form so the entire string is invalid, not just a few characters
 86          {"Invalid separator position", {0}},
 87          {"Invalid separator position", {0}},
 88          {"Invalid character or mixed case", {3, 4, 5, 7}},
 89          {"Invalid character or mixed case", {3}},
 90          {"Invalid Bech32 checksum", {11}},
 91          {"Invalid Bech32 checksum", {9, 16}},
 92      };
 93      static_assert(std::size(CASES) == std::size(ERRORS), "Bech32 CASES and ERRORS should have the same length");
 94  
 95      int i = 0;
 96      for (const std::string& str : CASES) {
 97          const auto& err = ERRORS[i];
 98          const auto dec = bech32::Decode(str);
 99          BOOST_CHECK(dec.encoding == bech32::Encoding::INVALID);
100          auto [error, error_locations] = bech32::LocateErrors(str);
101          BOOST_CHECK_EQUAL(err.first, error);
102          BOOST_CHECK(err.second == error_locations);
103          i++;
104      }
105  }
106  
107  BOOST_AUTO_TEST_CASE(bech32m_testvectors_invalid)
108  {
109      static const std::string CASES[] = {
110          " 1xj0phk",
111          "\x7f""1g6xzxy",
112          "\x80""1vctc34",
113          "an84characterslonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11d6pts4",
114          "qyrz8wqd2c9m",
115          "1qyrz8wqd2c9m",
116          "y1b0jsk6g",
117          "lt1igcx5c0",
118          "in1muywd",
119          "mm1crxm3i",
120          "au1s5cgom",
121          "M1VUXWEZ",
122          "16plkw9",
123          "1p2gdwpf",
124          "abcdef1l7aum6echk45nj2s0wdvt2fg8x9yrzpqzd3ryx",
125          "test1zg69v7y60n00qy352euf40x77qcusag6",
126      };
127      static const std::pair<std::string, std::vector<int>> ERRORS[] = {
128          {"Invalid character or mixed case", {0}},
129          {"Invalid character or mixed case", {0}},
130          {"Invalid character or mixed case", {0}},
131          {"Bech32 string too long", {90}},
132          {"Missing separator", {}},
133          {"Invalid separator position", {0}},
134          {"Invalid Base 32 character", {2}},
135          {"Invalid Base 32 character", {3}},
136          {"Invalid separator position", {2}},
137          {"Invalid Base 32 character", {8}},
138          {"Invalid Base 32 character", {7}},
139          {"Invalid checksum", {}},
140          {"Invalid separator position", {0}},
141          {"Invalid separator position", {0}},
142          {"Invalid Bech32m checksum", {21}},
143          {"Invalid Bech32m checksum", {13, 32}},
144      };
145      static_assert(std::size(CASES) == std::size(ERRORS), "Bech32m CASES and ERRORS should have the same length");
146  
147      int i = 0;
148      for (const std::string& str : CASES) {
149          const auto& err = ERRORS[i];
150          const auto dec = bech32::Decode(str);
151          BOOST_CHECK(dec.encoding == bech32::Encoding::INVALID);
152          auto [error, error_locations] = bech32::LocateErrors(str);
153          BOOST_CHECK_EQUAL(err.first, error);
154          BOOST_CHECK(err.second == error_locations);
155          i++;
156      }
157  }
158  
159  BOOST_AUTO_TEST_SUITE_END()