/root/bitcoin/src/test/fuzz/p2p_transport_serialization.cpp
| Line | Count | Source | 
| 1 |  | // Copyright (c) 2019-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 <chainparams.h> | 
| 6 |  | #include <hash.h> | 
| 7 |  | #include <net.h> | 
| 8 |  | #include <netmessagemaker.h> | 
| 9 |  | #include <protocol.h> | 
| 10 |  | #include <test/fuzz/FuzzedDataProvider.h> | 
| 11 |  | #include <test/fuzz/fuzz.h> | 
| 12 |  | #include <test/fuzz/util.h> | 
| 13 |  | #include <util/chaintype.h> | 
| 14 |  |  | 
| 15 |  | #include <algorithm> | 
| 16 |  | #include <cassert> | 
| 17 |  | #include <cstdint> | 
| 18 |  | #include <limits> | 
| 19 |  | #include <optional> | 
| 20 |  | #include <vector> | 
| 21 |  |  | 
| 22 |  | namespace { | 
| 23 |  |  | 
| 24 |  | auto g_all_messages = ALL_NET_MESSAGE_TYPES; | 
| 25 |  |  | 
| 26 |  | void initialize_p2p_transport_serialization() | 
| 27 | 0 | { | 
| 28 | 0 |     static ECC_Context ecc_context{}; | 
| 29 | 0 |     SelectParams(ChainType::REGTEST); | 
| 30 | 0 |     std::sort(g_all_messages.begin(), g_all_messages.end()); | 
| 31 | 0 | } | 
| 32 |  |  | 
| 33 |  | } // namespace | 
| 34 |  |  | 
| 35 |  | FUZZ_TARGET(p2p_transport_serialization, .init = initialize_p2p_transport_serialization) | 
| 36 | 0 | { | 
| 37 |  |     // Construct transports for both sides, with dummy NodeIds. | 
| 38 | 0 |     V1Transport recv_transport{NodeId{0}}; | 
| 39 | 0 |     V1Transport send_transport{NodeId{1}}; | 
| 40 |  | 
 | 
| 41 | 0 |     FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; | 
| 42 |  | 
 | 
| 43 | 0 |     auto checksum_assist = fuzzed_data_provider.ConsumeBool(); | 
| 44 | 0 |     auto magic_bytes_assist = fuzzed_data_provider.ConsumeBool(); | 
| 45 | 0 |     std::vector<uint8_t> mutable_msg_bytes; | 
| 46 |  | 
 | 
| 47 | 0 |     auto header_bytes_remaining = CMessageHeader::HEADER_SIZE; | 
| 48 | 0 |     if (magic_bytes_assist) { | 
| 49 | 0 |         auto msg_start = Params().MessageStart(); | 
| 50 | 0 |         for (size_t i = 0; i < CMessageHeader::MESSAGE_SIZE_SIZE; ++i) { | 
| 51 | 0 |             mutable_msg_bytes.push_back(msg_start[i]); | 
| 52 | 0 |         } | 
| 53 | 0 |         header_bytes_remaining -= CMessageHeader::MESSAGE_SIZE_SIZE; | 
| 54 | 0 |     } | 
| 55 |  | 
 | 
| 56 | 0 |     if (checksum_assist) { | 
| 57 | 0 |         header_bytes_remaining -= CMessageHeader::CHECKSUM_SIZE; | 
| 58 | 0 |     } | 
| 59 |  | 
 | 
| 60 | 0 |     auto header_random_bytes = fuzzed_data_provider.ConsumeBytes<uint8_t>(header_bytes_remaining); | 
| 61 | 0 |     mutable_msg_bytes.insert(mutable_msg_bytes.end(), header_random_bytes.begin(), header_random_bytes.end()); | 
| 62 | 0 |     auto payload_bytes = fuzzed_data_provider.ConsumeRemainingBytes<uint8_t>(); | 
| 63 |  | 
 | 
| 64 | 0 |     if (checksum_assist && mutable_msg_bytes.size() == CMessageHeader::CHECKSUM_OFFSET) { | 
| 65 | 0 |         CHash256 hasher; | 
| 66 | 0 |         unsigned char hsh[32]; | 
| 67 | 0 |         hasher.Write(payload_bytes); | 
| 68 | 0 |         hasher.Finalize(hsh); | 
| 69 | 0 |         for (size_t i = 0; i < CMessageHeader::CHECKSUM_SIZE; ++i) { | 
| 70 | 0 |            mutable_msg_bytes.push_back(hsh[i]); | 
| 71 | 0 |         } | 
| 72 | 0 |     } | 
| 73 |  | 
 | 
| 74 | 0 |     mutable_msg_bytes.insert(mutable_msg_bytes.end(), payload_bytes.begin(), payload_bytes.end()); | 
| 75 | 0 |     std::span<const uint8_t> msg_bytes{mutable_msg_bytes}; | 
| 76 | 0 |     while (msg_bytes.size() > 0) { | 
| 77 | 0 |         if (!recv_transport.ReceivedBytes(msg_bytes)) { | 
| 78 | 0 |             break; | 
| 79 | 0 |         } | 
| 80 | 0 |         if (recv_transport.ReceivedMessageComplete()) { | 
| 81 | 0 |             const std::chrono::microseconds m_time{std::numeric_limits<int64_t>::max()}; | 
| 82 | 0 |             bool reject_message{false}; | 
| 83 | 0 |             CNetMessage msg = recv_transport.GetReceivedMessage(m_time, reject_message); | 
| 84 | 0 |             assert(msg.m_type.size() <= CMessageHeader::MESSAGE_TYPE_SIZE); | 
| 85 | 0 |             assert(msg.m_raw_message_size <= mutable_msg_bytes.size()); | 
| 86 | 0 |             assert(msg.m_raw_message_size == CMessageHeader::HEADER_SIZE + msg.m_message_size); | 
| 87 | 0 |             assert(msg.m_time == m_time); | 
| 88 |  |  | 
| 89 | 0 |             std::vector<unsigned char> header; | 
| 90 | 0 |             auto msg2 = NetMsg::Make(msg.m_type, std::span{msg.m_recv}); | 
| 91 | 0 |             bool queued = send_transport.SetMessageToSend(msg2); | 
| 92 | 0 |             assert(queued); | 
| 93 | 0 |             std::optional<bool> known_more; | 
| 94 | 0 |             while (true) { | 
| 95 | 0 |                 const auto& [to_send, more, _msg_type] = send_transport.GetBytesToSend(false); | 
| 96 | 0 |                 if (known_more) assert(!to_send.empty() == *known_more); | 
| 97 | 0 |                 if (to_send.empty()) break; | 
| 98 | 0 |                 send_transport.MarkBytesSent(to_send.size()); | 
| 99 | 0 |                 known_more = more; | 
| 100 | 0 |             } | 
| 101 | 0 |         } | 
| 102 | 0 |     } | 
| 103 | 0 | } | 
| 104 |  |  | 
| 105 |  | namespace { | 
| 106 |  |  | 
| 107 |  | template<RandomNumberGenerator R> | 
| 108 |  | void SimulationTest(Transport& initiator, Transport& responder, R& rng, FuzzedDataProvider& provider) | 
| 109 | 0 | { | 
| 110 |  |     // Simulation test with two Transport objects, which send messages to each other, with | 
| 111 |  |     // sending and receiving fragmented into multiple pieces that may be interleaved. It primarily | 
| 112 |  |     // verifies that the sending and receiving side are compatible with each other, plus a few | 
| 113 |  |     // sanity checks. It does not attempt to introduce errors in the communicated data. | 
| 114 |  |  | 
| 115 |  |     // Put the transports in an array for by-index access. | 
| 116 | 0 |     const std::array<Transport*, 2> transports = {&initiator, &responder}; | 
| 117 |  |  | 
| 118 |  |     // Two vectors representing in-flight bytes. inflight[i] is from transport[i] to transport[!i]. | 
| 119 | 0 |     std::array<std::vector<uint8_t>, 2> in_flight; | 
| 120 |  |  | 
| 121 |  |     // Two queues with expected messages. expected[i] is expected to arrive in transport[!i]. | 
| 122 | 0 |     std::array<std::deque<CSerializedNetMsg>, 2> expected; | 
| 123 |  |  | 
| 124 |  |     // Vectors with bytes last returned by GetBytesToSend() on transport[i]. | 
| 125 | 0 |     std::array<std::vector<uint8_t>, 2> to_send; | 
| 126 |  |  | 
| 127 |  |     // Last returned 'more' values (if still relevant) by transport[i]->GetBytesToSend(), for | 
| 128 |  |     // both have_next_message false and true. | 
| 129 | 0 |     std::array<std::optional<bool>, 2> last_more, last_more_next; | 
| 130 |  |  | 
| 131 |  |     // Whether more bytes to be sent are expected on transport[i], before and after | 
| 132 |  |     // SetMessageToSend(). | 
| 133 | 0 |     std::array<std::optional<bool>, 2> expect_more, expect_more_next; | 
| 134 |  |  | 
| 135 |  |     // Function to consume a message type. | 
| 136 | 0 |     auto msg_type_fn = [&]() { | 
| 137 | 0 |         uint8_t v = provider.ConsumeIntegral<uint8_t>(); | 
| 138 | 0 |         if (v == 0xFF) { | 
| 139 |  |             // If v is 0xFF, construct a valid (but possibly unknown) message type from the fuzz | 
| 140 |  |             // data. | 
| 141 | 0 |             std::string ret; | 
| 142 | 0 |             while (ret.size() < CMessageHeader::MESSAGE_TYPE_SIZE) { | 
| 143 | 0 |                 char c = provider.ConsumeIntegral<char>(); | 
| 144 |  |                 // Match the allowed characters in CMessageHeader::IsMessageTypeValid(). Any other | 
| 145 |  |                 // character is interpreted as end. | 
| 146 | 0 |                 if (c < ' ' || c > 0x7E) break; | 
| 147 | 0 |                 ret += c; | 
| 148 | 0 |             } | 
| 149 | 0 |             return ret; | 
| 150 | 0 |         } else { | 
| 151 |  |             // Otherwise, use it as index into the list of known messages. | 
| 152 | 0 |             return g_all_messages[v % g_all_messages.size()]; | 
| 153 | 0 |         } | 
| 154 | 0 |     }; | 
| 155 |  |  | 
| 156 |  |     // Function to construct a CSerializedNetMsg to send. | 
| 157 | 0 |     auto make_msg_fn = [&](bool first) { | 
| 158 | 0 |         CSerializedNetMsg msg; | 
| 159 | 0 |         if (first) { | 
| 160 |  |             // Always send a "version" message as first one. | 
| 161 | 0 |             msg.m_type = "version"; | 
| 162 | 0 |         } else { | 
| 163 | 0 |             msg.m_type = msg_type_fn(); | 
| 164 | 0 |         } | 
| 165 |  |         // Determine size of message to send (limited to 75 kB for performance reasons). | 
| 166 | 0 |         size_t size = provider.ConsumeIntegralInRange<uint32_t>(0, 75000); | 
| 167 |  |         // Get payload of message from RNG. | 
| 168 | 0 |         msg.data = rng.randbytes(size); | 
| 169 |  |         // Return. | 
| 170 | 0 |         return msg; | 
| 171 | 0 |     }; | 
| 172 |  |  | 
| 173 |  |     // The next message to be sent (initially version messages, but will be replaced once sent). | 
| 174 | 0 |     std::array<CSerializedNetMsg, 2> next_msg = { | 
| 175 | 0 |         make_msg_fn(/*first=*/true), | 
| 176 | 0 |         make_msg_fn(/*first=*/true) | 
| 177 | 0 |     }; | 
| 178 |  |  | 
| 179 |  |     // Wrapper around transport[i]->GetBytesToSend() that performs sanity checks. | 
| 180 | 0 |     auto bytes_to_send_fn = [&](int side) -> Transport::BytesToSend { | 
| 181 |  |         // Invoke GetBytesToSend twice (for have_next_message = {false, true}). This function does | 
| 182 |  |         // not modify state (it's const), and only the "more" return value should differ between | 
| 183 |  |         // the calls. | 
| 184 | 0 |         const auto& [bytes, more_nonext, msg_type] = transports[side]->GetBytesToSend(false); | 
| 185 | 0 |         const auto& [bytes_next, more_next, msg_type_next] = transports[side]->GetBytesToSend(true); | 
| 186 |  |         // Compare with expected more. | 
| 187 | 0 |         if (expect_more[side].has_value()) assert(!bytes.empty() == *expect_more[side]); | 
| 188 |  |         // Verify consistency between the two results. | 
| 189 | 0 |         assert(std::ranges::equal(bytes, bytes_next)); | 
| 190 | 0 |         assert(msg_type == msg_type_next); | 
| 191 | 0 |         if (more_nonext) assert(more_next); | 
| 192 |  |         // Compare with previously reported output. | 
| 193 | 0 |         assert(to_send[side].size() <= bytes.size()); | 
| 194 | 0 |         assert(std::ranges::equal(to_send[side], std::span{bytes}.first(to_send[side].size()))); | 
| 195 | 0 |         to_send[side].resize(bytes.size()); | 
| 196 | 0 |         std::copy(bytes.begin(), bytes.end(), to_send[side].begin()); | 
| 197 |  |         // Remember 'more' results. | 
| 198 | 0 |         last_more[side] = {more_nonext}; | 
| 199 | 0 |         last_more_next[side] = {more_next}; | 
| 200 |  |         // Return. | 
| 201 | 0 |         return {bytes, more_nonext, msg_type}; | 
| 202 | 0 |     }; | 
| 203 |  |  | 
| 204 |  |     // Function to make side send a new message. | 
| 205 | 0 |     auto new_msg_fn = [&](int side) { | 
| 206 |  |         // Don't do anything if there are too many unreceived messages already. | 
| 207 | 0 |         if (expected[side].size() >= 16) return; | 
| 208 |  |         // Try to send (a copy of) the message in next_msg[side]. | 
| 209 | 0 |         CSerializedNetMsg msg = next_msg[side].Copy(); | 
| 210 | 0 |         bool queued = transports[side]->SetMessageToSend(msg); | 
| 211 |  |         // Update expected more data. | 
| 212 | 0 |         expect_more[side] = expect_more_next[side]; | 
| 213 | 0 |         expect_more_next[side] = std::nullopt; | 
| 214 |  |         // Verify consistency of GetBytesToSend after SetMessageToSend | 
| 215 | 0 |         bytes_to_send_fn(/*side=*/side); | 
| 216 | 0 |         if (queued) { | 
| 217 |  |             // Remember that this message is now expected by the receiver. | 
| 218 | 0 |             expected[side].emplace_back(std::move(next_msg[side])); | 
| 219 |  |             // Construct a new next message to send. | 
| 220 | 0 |             next_msg[side] = make_msg_fn(/*first=*/false); | 
| 221 | 0 |         } | 
| 222 | 0 |     }; | 
| 223 |  |  | 
| 224 |  |     // Function to make side send out bytes (if any). | 
| 225 | 0 |     auto send_fn = [&](int side, bool everything = false) { | 
| 226 | 0 |         const auto& [bytes, more, msg_type] = bytes_to_send_fn(/*side=*/side); | 
| 227 |  |         // Don't do anything if no bytes to send. | 
| 228 | 0 |         if (bytes.empty()) return false; | 
| 229 | 0 |         size_t send_now = everything ? bytes.size() : provider.ConsumeIntegralInRange<size_t>(0, bytes.size()); | 
| 230 | 0 |         if (send_now == 0) return false; | 
| 231 |  |         // Add bytes to the in-flight queue, and mark those bytes as consumed. | 
| 232 | 0 |         in_flight[side].insert(in_flight[side].end(), bytes.begin(), bytes.begin() + send_now); | 
| 233 | 0 |         transports[side]->MarkBytesSent(send_now); | 
| 234 |  |         // If all to-be-sent bytes were sent, move last_more data to expect_more data. | 
| 235 | 0 |         if (send_now == bytes.size()) { | 
| 236 | 0 |             expect_more[side] = last_more[side]; | 
| 237 | 0 |             expect_more_next[side] = last_more_next[side]; | 
| 238 | 0 |         } | 
| 239 |  |         // Remove the bytes from the last reported to-be-sent vector. | 
| 240 | 0 |         assert(to_send[side].size() >= send_now); | 
| 241 | 0 |         to_send[side].erase(to_send[side].begin(), to_send[side].begin() + send_now); | 
| 242 |  |         // Verify that GetBytesToSend gives a result consistent with earlier. | 
| 243 | 0 |         bytes_to_send_fn(/*side=*/side); | 
| 244 |  |         // Return whether anything was sent. | 
| 245 | 0 |         return send_now > 0; | 
| 246 | 0 |     }; | 
| 247 |  |  | 
| 248 |  |     // Function to make !side receive bytes (if any). | 
| 249 | 0 |     auto recv_fn = [&](int side, bool everything = false) { | 
| 250 |  |         // Don't do anything if no bytes in flight. | 
| 251 | 0 |         if (in_flight[side].empty()) return false; | 
| 252 |  |         // Decide span to receive | 
| 253 | 0 |         size_t to_recv_len = in_flight[side].size(); | 
| 254 | 0 |         if (!everything) to_recv_len = provider.ConsumeIntegralInRange<size_t>(0, to_recv_len); | 
| 255 | 0 |         std::span<const uint8_t> to_recv = std::span{in_flight[side]}.first(to_recv_len); | 
| 256 |  |         // Process those bytes | 
| 257 | 0 |         while (!to_recv.empty()) { | 
| 258 | 0 |             size_t old_len = to_recv.size(); | 
| 259 | 0 |             bool ret = transports[!side]->ReceivedBytes(to_recv); | 
| 260 |  |             // Bytes must always be accepted, as this test does not introduce any errors in | 
| 261 |  |             // communication. | 
| 262 | 0 |             assert(ret); | 
| 263 |  |             // Clear cached expected 'more' information: if certainly no more data was to be sent | 
| 264 |  |             // before, receiving bytes makes this uncertain. | 
| 265 | 0 |             if (expect_more[!side] == false) expect_more[!side] = std::nullopt; | 
| 266 | 0 |             if (expect_more_next[!side] == false) expect_more_next[!side] = std::nullopt; | 
| 267 |  |             // Verify consistency of GetBytesToSend after ReceivedBytes | 
| 268 | 0 |             bytes_to_send_fn(/*side=*/!side); | 
| 269 | 0 |             bool progress = to_recv.size() < old_len; | 
| 270 | 0 |             if (transports[!side]->ReceivedMessageComplete()) { | 
| 271 | 0 |                 bool reject{false}; | 
| 272 | 0 |                 auto received = transports[!side]->GetReceivedMessage({}, reject); | 
| 273 |  |                 // Receiving must succeed. | 
| 274 | 0 |                 assert(!reject); | 
| 275 |  |                 // There must be a corresponding expected message. | 
| 276 | 0 |                 assert(!expected[side].empty()); | 
| 277 |  |                 // The m_message_size field must be correct. | 
| 278 | 0 |                 assert(received.m_message_size == received.m_recv.size()); | 
| 279 |  |                 // The m_type must match what is expected. | 
| 280 | 0 |                 assert(received.m_type == expected[side].front().m_type); | 
| 281 |  |                 // The data must match what is expected. | 
| 282 | 0 |                 assert(std::ranges::equal(received.m_recv, MakeByteSpan(expected[side].front().data))); | 
| 283 | 0 |                 expected[side].pop_front(); | 
| 284 | 0 |                 progress = true; | 
| 285 | 0 |             } | 
| 286 |  |             // Progress must be made (by processing incoming bytes and/or returning complete | 
| 287 |  |             // messages) until all received bytes are processed. | 
| 288 | 0 |             assert(progress); | 
| 289 | 0 |         } | 
| 290 |  |         // Remove the processed bytes from the in_flight buffer. | 
| 291 | 0 |         in_flight[side].erase(in_flight[side].begin(), in_flight[side].begin() + to_recv_len); | 
| 292 |  |         // Return whether anything was received. | 
| 293 | 0 |         return to_recv_len > 0; | 
| 294 | 0 |     }; | 
| 295 |  |  | 
| 296 |  |     // Main loop, interleaving new messages, sends, and receives. | 
| 297 | 0 |     LIMITED_WHILE(provider.remaining_bytes(), 1000) { | 
| 298 | 0 |         CallOneOf(provider, | 
| 299 |  |             // (Try to) give the next message to the transport. | 
| 300 | 0 |             [&] { new_msg_fn(/*side=*/0); }, | 
| 301 | 0 |             [&] { new_msg_fn(/*side=*/1); }, | 
| 302 |  |             // (Try to) send some bytes from the transport to the network. | 
| 303 | 0 |             [&] { send_fn(/*side=*/0); }, | 
| 304 | 0 |             [&] { send_fn(/*side=*/1); }, | 
| 305 |  |             // (Try to) receive bytes from the network, converting to messages. | 
| 306 | 0 |             [&] { recv_fn(/*side=*/0); }, | 
| 307 | 0 |             [&] { recv_fn(/*side=*/1); } | 
| 308 | 0 |         ); | 
| 309 | 0 |     } | 
| 310 |  |  | 
| 311 |  |     // When we're done, perform sends and receives of existing messages to flush anything already | 
| 312 |  |     // in flight. | 
| 313 | 0 |     while (true) { | 
| 314 | 0 |         bool any = false; | 
| 315 | 0 |         if (send_fn(/*side=*/0, /*everything=*/true)) any = true; | 
| 316 | 0 |         if (send_fn(/*side=*/1, /*everything=*/true)) any = true; | 
| 317 | 0 |         if (recv_fn(/*side=*/0, /*everything=*/true)) any = true; | 
| 318 | 0 |         if (recv_fn(/*side=*/1, /*everything=*/true)) any = true; | 
| 319 | 0 |         if (!any) break; | 
| 320 | 0 |     } | 
| 321 |  |  | 
| 322 |  |     // Make sure nothing is left in flight. | 
| 323 | 0 |     assert(in_flight[0].empty()); | 
| 324 | 0 |     assert(in_flight[1].empty()); | 
| 325 |  |  | 
| 326 |  |     // Make sure all expected messages were received. | 
| 327 | 0 |     assert(expected[0].empty()); | 
| 328 | 0 |     assert(expected[1].empty()); | 
| 329 |  |  | 
| 330 |  |     // Compare session IDs. | 
| 331 | 0 |     assert(transports[0]->GetInfo().session_id == transports[1]->GetInfo().session_id); | 
| 332 | 0 | } | 
| 333 |  |  | 
| 334 |  | std::unique_ptr<Transport> MakeV1Transport(NodeId nodeid) noexcept | 
| 335 | 0 | { | 
| 336 | 0 |     return std::make_unique<V1Transport>(nodeid); | 
| 337 | 0 | } | 
| 338 |  |  | 
| 339 |  | template<RandomNumberGenerator RNG> | 
| 340 |  | std::unique_ptr<Transport> MakeV2Transport(NodeId nodeid, bool initiator, RNG& rng, FuzzedDataProvider& provider) | 
| 341 | 0 | { | 
| 342 |  |     // Retrieve key | 
| 343 | 0 |     auto key = ConsumePrivateKey(provider); | 
| 344 | 0 |     if (!key.IsValid()) return {}; | 
| 345 |  |     // Construct garbage | 
| 346 | 0 |     size_t garb_len = provider.ConsumeIntegralInRange<size_t>(0, V2Transport::MAX_GARBAGE_LEN); | 
| 347 | 0 |     std::vector<uint8_t> garb; | 
| 348 | 0 |     if (garb_len <= 64) { | 
| 349 |  |         // When the garbage length is up to 64 bytes, read it directly from the fuzzer input. | 
| 350 | 0 |         garb = provider.ConsumeBytes<uint8_t>(garb_len); | 
| 351 | 0 |         garb.resize(garb_len); | 
| 352 | 0 |     } else { | 
| 353 |  |         // If it's longer, generate it from the RNG. This avoids having large amounts of | 
| 354 |  |         // (hopefully) irrelevant data needing to be stored in the fuzzer data. | 
| 355 | 0 |         garb = rng.randbytes(garb_len); | 
| 356 | 0 |     } | 
| 357 |  |     // Retrieve entropy | 
| 358 | 0 |     auto ent = provider.ConsumeBytes<std::byte>(32); | 
| 359 | 0 |     ent.resize(32); | 
| 360 |  |     // Use as entropy SHA256(ent || garbage). This prevents a situation where the fuzzer manages to | 
| 361 |  |     // include the garbage terminator (which is a function of both ellswift keys) in the garbage. | 
| 362 |  |     // This is extremely unlikely (~2^-116) with random keys/garbage, but the fuzzer can choose | 
| 363 |  |     // both non-randomly and dependently. Since the entropy is hashed anyway inside the ellswift | 
| 364 |  |     // computation, no coverage should be lost by using a hash as entropy, and it removes the | 
| 365 |  |     // possibility of garbage that happens to contain what is effectively a hash of the keys. | 
| 366 | 0 |     CSHA256().Write(UCharCast(ent.data()), ent.size()) | 
| 367 | 0 |              .Write(garb.data(), garb.size()) | 
| 368 | 0 |              .Finalize(UCharCast(ent.data())); | 
| 369 |  | 
 | 
| 370 | 0 |     return std::make_unique<V2Transport>(nodeid, initiator, key, ent, std::move(garb)); | 
| 371 | 0 | } | 
| 372 |  |  | 
| 373 |  | } // namespace | 
| 374 |  |  | 
| 375 |  | FUZZ_TARGET(p2p_transport_bidirectional, .init = initialize_p2p_transport_serialization) | 
| 376 | 0 | { | 
| 377 |  |     // Test with two V1 transports talking to each other. | 
| 378 | 0 |     FuzzedDataProvider provider{buffer.data(), buffer.size()}; | 
| 379 | 0 |     InsecureRandomContext rng(provider.ConsumeIntegral<uint64_t>()); | 
| 380 | 0 |     auto t1 = MakeV1Transport(NodeId{0}); | 
| 381 | 0 |     auto t2 = MakeV1Transport(NodeId{1}); | 
| 382 | 0 |     if (!t1 || !t2) return; | 
| 383 | 0 |     SimulationTest(*t1, *t2, rng, provider); | 
| 384 | 0 | } | 
| 385 |  |  | 
| 386 |  | FUZZ_TARGET(p2p_transport_bidirectional_v2, .init = initialize_p2p_transport_serialization) | 
| 387 | 0 | { | 
| 388 |  |     // Test with two V2 transports talking to each other. | 
| 389 | 0 |     FuzzedDataProvider provider{buffer.data(), buffer.size()}; | 
| 390 | 0 |     InsecureRandomContext rng(provider.ConsumeIntegral<uint64_t>()); | 
| 391 | 0 |     auto t1 = MakeV2Transport(NodeId{0}, true, rng, provider); | 
| 392 | 0 |     auto t2 = MakeV2Transport(NodeId{1}, false, rng, provider); | 
| 393 | 0 |     if (!t1 || !t2) return; | 
| 394 | 0 |     SimulationTest(*t1, *t2, rng, provider); | 
| 395 | 0 | } | 
| 396 |  |  | 
| 397 |  | FUZZ_TARGET(p2p_transport_bidirectional_v1v2, .init = initialize_p2p_transport_serialization) | 
| 398 | 0 | { | 
| 399 |  |     // Test with a V1 initiator talking to a V2 responder. | 
| 400 | 0 |     FuzzedDataProvider provider{buffer.data(), buffer.size()}; | 
| 401 | 0 |     InsecureRandomContext rng(provider.ConsumeIntegral<uint64_t>()); | 
| 402 | 0 |     auto t1 = MakeV1Transport(NodeId{0}); | 
| 403 | 0 |     auto t2 = MakeV2Transport(NodeId{1}, false, rng, provider); | 
| 404 | 0 |     if (!t1 || !t2) return; | 
| 405 | 0 |     SimulationTest(*t1, *t2, rng, provider); | 
| 406 | 0 | } |