LCOV - code coverage report
Current view: top level - src/test/fuzz - bip324.cpp (source / functions) Coverage Total Hit
Test: fuzz_coverage.info Lines: 93.9 % 66 62
Test Date: 2024-09-01 05:20:30 Functions: 66.7 % 3 2
Branches: 57.9 % 114 66

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2023 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 <bip324.h>
       6                 :             : #include <chainparams.h>
       7                 :             : #include <random.h>
       8                 :             : #include <span.h>
       9                 :             : #include <test/fuzz/FuzzedDataProvider.h>
      10                 :             : #include <test/fuzz/fuzz.h>
      11                 :             : #include <test/fuzz/util.h>
      12                 :             : 
      13                 :             : #include <algorithm>
      14                 :             : #include <cstdint>
      15                 :             : #include <vector>
      16                 :             : 
      17                 :             : namespace {
      18                 :             : 
      19                 :           0 : void Initialize()
      20                 :             : {
      21   [ #  #  #  #  :           0 :     static ECC_Context ecc_context{};
                   #  # ]
      22                 :           0 :     SelectParams(ChainType::MAIN);
      23                 :           0 : }
      24                 :             : 
      25                 :             : }  // namespace
      26                 :             : 
      27         [ +  - ]:         635 : FUZZ_TARGET(bip324_cipher_roundtrip, .init=Initialize)
      28                 :             : {
      29                 :             :     // Test that BIP324Cipher's encryption and decryption agree.
      30                 :             : 
      31                 :             :     // Load keys from fuzzer.
      32                 :         633 :     FuzzedDataProvider provider(buffer.data(), buffer.size());
      33                 :             :     // Initiator key
      34                 :         633 :     CKey init_key = ConsumePrivateKey(provider, /*compressed=*/true);
      35   [ +  -  +  + ]:         633 :     if (!init_key.IsValid()) return;
      36                 :             :     // Initiator entropy
      37         [ +  - ]:         628 :     auto init_ent = provider.ConsumeBytes<std::byte>(32);
      38         [ +  - ]:         628 :     init_ent.resize(32);
      39                 :             :     // Responder key
      40                 :         628 :     CKey resp_key = ConsumePrivateKey(provider, /*compressed=*/true);
      41   [ +  -  +  + ]:         628 :     if (!resp_key.IsValid()) return;
      42                 :             :     // Responder entropy
      43         [ +  - ]:         621 :     auto resp_ent = provider.ConsumeBytes<std::byte>(32);
      44         [ +  - ]:         621 :     resp_ent.resize(32);
      45                 :             : 
      46                 :             :     // Initialize ciphers by exchanging public keys.
      47         [ +  - ]:         621 :     BIP324Cipher initiator(init_key, init_ent);
      48         [ +  - ]:         621 :     assert(!initiator);
      49         [ +  - ]:         621 :     BIP324Cipher responder(resp_key, resp_ent);
      50         [ +  - ]:         621 :     assert(!responder);
      51                 :         621 :     initiator.Initialize(responder.GetOurPubKey(), true);
      52         [ +  - ]:         621 :     assert(initiator);
      53                 :         621 :     responder.Initialize(initiator.GetOurPubKey(), false);
      54         [ +  - ]:         621 :     assert(responder);
      55                 :             : 
      56                 :             :     // Initialize RNG deterministically, to generate contents and AAD. We assume that there are no
      57                 :             :     // (potentially buggy) edge cases triggered by specific values of contents/AAD, so we can avoid
      58                 :             :     // reading the actual data for those from the fuzzer input (which would need large amounts of
      59                 :             :     // data).
      60         [ +  - ]:         621 :     InsecureRandomContext rng(provider.ConsumeIntegral<uint64_t>());
      61                 :             : 
      62                 :             :     // Compare session IDs and garbage terminators.
      63   [ +  -  +  - ]:         621 :     assert(std::ranges::equal(initiator.GetSessionID(), responder.GetSessionID()));
      64   [ +  -  +  - ]:         621 :     assert(std::ranges::equal(initiator.GetSendGarbageTerminator(), responder.GetReceiveGarbageTerminator()));
      65   [ +  -  +  - ]:         621 :     assert(std::ranges::equal(initiator.GetReceiveGarbageTerminator(), responder.GetSendGarbageTerminator()));
      66                 :             : 
      67   [ -  +  +  +  :       46473 :     LIMITED_WHILE(provider.remaining_bytes(), 1000) {
                   +  + ]
      68                 :             :         // Mode:
      69                 :             :         // - Bit 0: whether the ignore bit is set in message
      70                 :             :         // - Bit 1: whether the responder (0) or initiator (1) sends
      71                 :             :         // - Bit 2: whether this ciphertext will be corrupted (making it the last sent one)
      72                 :             :         // - Bit 3-4: controls the maximum aad length (max 4095 bytes)
      73                 :             :         // - Bit 5-7: controls the maximum content length (max 16383 bytes, for performance reasons)
      74         [ -  + ]:       45852 :         unsigned mode = provider.ConsumeIntegral<uint8_t>();
      75                 :       45852 :         bool ignore = mode & 1;
      76                 :       45852 :         bool from_init = mode & 2;
      77                 :       45852 :         bool damage = mode & 4;
      78                 :       45852 :         unsigned aad_length_bits = 4 * ((mode >> 3) & 3);
      79         [ -  + ]:       45852 :         unsigned aad_length = provider.ConsumeIntegralInRange<unsigned>(0, (1 << aad_length_bits) - 1);
      80                 :       45852 :         unsigned length_bits = 2 * ((mode >> 5) & 7);
      81         [ -  + ]:       45852 :         unsigned length = provider.ConsumeIntegralInRange<unsigned>(0, (1 << length_bits) - 1);
      82                 :             :         // Generate aad and content.
      83                 :       45852 :         auto aad = rng.randbytes<std::byte>(aad_length);
      84                 :       45852 :         auto contents = rng.randbytes<std::byte>(length);
      85                 :             : 
      86                 :             :         // Pick sides.
      87         [ +  + ]:       45852 :         auto& sender{from_init ? initiator : responder};
      88         [ +  + ]:       45852 :         auto& receiver{from_init ? responder : initiator};
      89                 :             : 
      90                 :             :         // Encrypt
      91         [ -  + ]:       45852 :         std::vector<std::byte> ciphertext(length + initiator.EXPANSION);
      92   [ +  -  +  -  :       45852 :         sender.Encrypt(contents, aad, ignore, ciphertext);
                   +  - ]
      93                 :             : 
      94                 :             :         // Optionally damage 1 bit in either the ciphertext (corresponding to a change in transit)
      95                 :             :         // or the aad (to make sure that decryption will fail if the AAD mismatches).
      96         [ +  + ]:       45852 :         if (damage) {
      97   [ +  -  +  - ]:         692 :             unsigned damage_bit = provider.ConsumeIntegralInRange<unsigned>(0,
      98                 :         346 :                 (ciphertext.size() + aad.size()) * 8U - 1U);
      99                 :         346 :             unsigned damage_pos = damage_bit >> 3;
     100                 :         346 :             std::byte damage_val{(uint8_t)(1U << (damage_bit & 7))};
     101         [ +  + ]:         346 :             if (damage_pos >= ciphertext.size()) {
     102                 :          35 :                 aad[damage_pos - ciphertext.size()] ^= damage_val;
     103                 :          35 :             } else {
     104                 :         311 :                 ciphertext[damage_pos] ^= damage_val;
     105                 :             :             }
     106                 :         346 :         }
     107                 :             : 
     108                 :             :         // Decrypt length
     109         [ -  + ]:       45852 :         uint32_t dec_length = receiver.DecryptLength(Span{ciphertext}.first(initiator.LENGTH_LEN));
     110         [ +  + ]:       45852 :         if (!damage) {
     111         [ -  + ]:       45506 :             assert(dec_length == length);
     112                 :       45506 :         } else {
     113                 :             :             // For performance reasons, don't try to decode if length got increased too much.
     114         [ +  + ]:         346 :             if (dec_length > 16384 + length) break;
     115                 :             :             // Otherwise, just append zeros if dec_length > length.
     116         [ +  - ]:         295 :             ciphertext.resize(dec_length + initiator.EXPANSION);
     117                 :             :         }
     118                 :             : 
     119                 :             :         // Decrypt
     120         [ -  + ]:       45801 :         std::vector<std::byte> decrypt(dec_length);
     121                 :       45801 :         bool dec_ignore{false};
     122   [ +  -  +  -  :       45801 :         bool ok = receiver.Decrypt(Span{ciphertext}.subspan(initiator.LENGTH_LEN), aad, dec_ignore, decrypt);
                   +  - ]
     123                 :             :         // Decryption *must* fail if the packet was damaged, and succeed if it wasn't.
     124         [ -  + ]:       45801 :         assert(!ok == damage);
     125         [ +  + ]:       45801 :         if (!ok) break;
     126         [ -  + ]:       45506 :         assert(ignore == dec_ignore);
     127   [ -  +  -  + ]:       45506 :         assert(decrypt == contents);
     128         [ +  + ]:       45852 :     }
     129         [ -  + ]:         633 : }
        

Generated by: LCOV version 2.0-1