minisketch.cpp
1 // Copyright (c) 2021-present The Bitcoin Core 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 <minisketch.h> 6 #include <node/minisketchwrapper.h> 7 #include <test/fuzz/FuzzedDataProvider.h> 8 #include <test/fuzz/fuzz.h> 9 #include <test/fuzz/util.h> 10 #include <util/check.h> 11 12 #include <map> 13 #include <numeric> 14 15 namespace { 16 17 Minisketch MakeFuzzMinisketch32(size_t capacity, uint32_t impl) 18 { 19 return Assert(Minisketch(32, impl, capacity)); 20 } 21 22 } // namespace 23 24 FUZZ_TARGET(minisketch) 25 { 26 FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; 27 28 const auto capacity{fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 200)}; 29 const uint32_t impl{fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, Minisketch::MaxImplementation())}; 30 if (!Minisketch::ImplementationSupported(32, impl)) return; 31 32 Minisketch sketch_a{MakeFuzzMinisketch32(capacity, impl)}; 33 Minisketch sketch_b{MakeFuzzMinisketch32(capacity, impl)}; 34 sketch_a.SetSeed(fuzzed_data_provider.ConsumeIntegral<uint64_t>()); 35 sketch_b.SetSeed(fuzzed_data_provider.ConsumeIntegral<uint64_t>()); 36 37 // Fill two sets and keep the difference in a map 38 std::map<uint32_t, bool> diff; 39 LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) 40 { 41 const auto entry{fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(1, std::numeric_limits<uint32_t>::max() - 1)}; 42 const auto KeepDiff{[&] { 43 bool& mut{diff[entry]}; 44 mut = !mut; 45 }}; 46 CallOneOf( 47 fuzzed_data_provider, 48 [&] { 49 sketch_a.Add(entry); 50 KeepDiff(); 51 }, 52 [&] { 53 sketch_b.Add(entry); 54 KeepDiff(); 55 }, 56 [&] { 57 sketch_a.Add(entry); 58 sketch_b.Add(entry); 59 }); 60 } 61 const auto num_diff{std::accumulate(diff.begin(), diff.end(), size_t{0}, [](auto n, const auto& e) { return n + e.second; })}; 62 63 Minisketch sketch_ar{MakeFuzzMinisketch32(capacity, impl)}; 64 Minisketch sketch_br{MakeFuzzMinisketch32(capacity, impl)}; 65 sketch_ar.SetSeed(fuzzed_data_provider.ConsumeIntegral<uint64_t>()); 66 sketch_br.SetSeed(fuzzed_data_provider.ConsumeIntegral<uint64_t>()); 67 68 sketch_ar.Deserialize(sketch_a.Serialize()); 69 sketch_br.Deserialize(sketch_b.Serialize()); 70 71 Minisketch sketch_diff{std::move(fuzzed_data_provider.ConsumeBool() ? sketch_a : sketch_ar)}; 72 sketch_diff.Merge(fuzzed_data_provider.ConsumeBool() ? sketch_b : sketch_br); 73 74 if (capacity >= num_diff) { 75 const auto max_elements{fuzzed_data_provider.ConsumeIntegralInRange<size_t>(num_diff, capacity)}; 76 const auto dec{*Assert(sketch_diff.Decode(max_elements))}; 77 Assert(dec.size() == num_diff); 78 for (auto d : dec) { 79 Assert(diff.at(d)); 80 } 81 } 82 }