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 <test/util/str.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()