44
55#include < bech32.h>
66#include < test/fuzz/fuzz.h>
7+ #include < test/fuzz/FuzzedDataProvider.h>
78#include < test/util/str.h>
89#include < util/strencodings.h>
910
1011#include < cassert>
1112#include < cstdint>
1213#include < string>
13- #include < utility>
1414#include < vector>
1515
16- FUZZ_TARGET (bech32 )
16+ FUZZ_TARGET (bech32_random_decode )
1717{
18- const std::string random_string (buffer.begin (), buffer.end ());
19- const auto r1 = bech32::Decode (random_string);
20- if (r1.hrp .empty ()) {
21- assert (r1.encoding == bech32::Encoding::INVALID);
22- assert (r1.data .empty ());
18+ auto limit = bech32::CharLimit::BECH32;
19+ FuzzedDataProvider fdp (buffer.data (), buffer.size ());
20+ auto random_string = fdp.ConsumeRandomLengthString (limit + 1 );
21+ auto decoded = bech32::Decode (random_string, limit);
22+
23+ if (decoded.hrp .empty ()) {
24+ assert (decoded.encoding == bech32::Encoding::INVALID);
25+ assert (decoded.data .empty ());
2326 } else {
24- assert (r1 .encoding != bech32::Encoding::INVALID);
25- const std::string reencoded = bech32::Encode (r1 .encoding , r1 .hrp , r1 .data );
27+ assert (decoded .encoding != bech32::Encoding::INVALID);
28+ auto reencoded = bech32::Encode (decoded .encoding , decoded .hrp , decoded .data );
2629 assert (CaseInsensitiveEqual (random_string, reencoded));
2730 }
31+ }
32+
33+ // https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki and https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki
34+ std::string GenerateRandomHRP (FuzzedDataProvider& fdp)
35+ {
36+ std::string hrp;
37+ size_t length = fdp.ConsumeIntegralInRange <size_t >(1 , 83 );
38+ for (size_t i = 0 ; i < length; ++i) {
39+ // Generate lowercase ASCII characters in ([33-126] - ['A'-'Z']) range
40+ char c = fdp.ConsumeBool ()
41+ ? fdp.ConsumeIntegralInRange <char >(33 , ' A' - 1 )
42+ : fdp.ConsumeIntegralInRange <char >(' Z' + 1 , 126 );
43+ hrp += c;
44+ }
45+ return hrp;
46+ }
47+
48+ FUZZ_TARGET (bech32_roundtrip)
49+ {
50+ FuzzedDataProvider fdp (buffer.data (), buffer.size ());
51+ auto hrp = GenerateRandomHRP (fdp);
2852
29- std::vector<unsigned char > input;
30- ConvertBits<8 , 5 , true >([&](unsigned char c) { input.push_back (c); }, buffer.begin (), buffer.end ());
53+ auto input_chars = fdp.ConsumeBytes <unsigned char >(fdp.ConsumeIntegralInRange <size_t >(0 , 82 ));
54+ std::vector<uint8_t > converted_input;
55+ ConvertBits<8 , 5 , true >([&](auto c) { converted_input.push_back (c); }, input_chars.begin (), input_chars.end ());
3156
32- // Input data part + 3 characters for the HRP and separator (bc1) + the checksum characters
33- if (input.size () + 3 + bech32::CHECKSUM_SIZE <= bech32::CharLimit::BECH32) {
34- // If it's possible to encode input in Bech32(m) without exceeding the bech32-character limit:
35- for (auto encoding : {bech32::Encoding::BECH32, bech32::Encoding::BECH32M}) {
36- const std::string encoded = bech32::Encode (encoding, " bc" , input);
57+ auto size = converted_input.size () + hrp.length () + std::string ({bech32::SEPARATOR}).size () + bech32::CHECKSUM_SIZE;
58+ if (size <= bech32::CharLimit::BECH32) {
59+ for (auto encoding: {bech32::Encoding::BECH32, bech32::Encoding::BECH32M}) {
60+ auto encoded = bech32::Encode (encoding, hrp, converted_input);
3761 assert (!encoded.empty ());
38- const auto r2 = bech32::Decode (encoded);
39- assert (r2.encoding == encoding);
40- assert (r2.hrp == " bc" );
41- assert (r2.data == input);
62+
63+ const auto decoded = bech32::Decode (encoded);
64+ assert (decoded.encoding == encoding);
65+ assert (decoded.hrp == hrp);
66+ assert (decoded.data == converted_input);
4267 }
4368 }
44- }
69+ }
0 commit comments