LCOV - code coverage report
Current view: top level - src/util - obfuscation.h (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 100.0 % 50 50
Test Date: 2025-08-01 05:08:13 Functions: 100.0 % 8 8
Branches: 52.9 % 274 145

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2025-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                 :             : #ifndef BITCOIN_UTIL_OBFUSCATION_H
       6                 :             : #define BITCOIN_UTIL_OBFUSCATION_H
       7                 :             : 
       8                 :             : #include <cstdint>
       9                 :             : #include <span.h>
      10                 :             : #include <tinyformat.h>
      11                 :             : #include <util/strencodings.h>
      12                 :             : 
      13                 :             : #include <array>
      14                 :             : #include <bit>
      15                 :             : #include <climits>
      16                 :             : #include <ios>
      17                 :             : #include <memory>
      18                 :             : 
      19                 :             : class Obfuscation
      20                 :             : {
      21                 :             : public:
      22                 :             :     using KeyType = uint64_t;
      23                 :             :     static constexpr size_t KEY_SIZE{sizeof(KeyType)};
      24                 :             : 
      25   [ +  -  +  -  :       29401 :     Obfuscation() { SetRotations(0); }
          +  -  +  -  +  
           -  +  - ][ +  
          -  +  -  #  #  
          #  #  #  #  #  
           #  #  # ][ +  
          -  +  -  +  -  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  #  # ][ +  
          -  +  -  +  -  
          +  -  +  -  +  
           -  +  - ][ +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
           -  +  - ][ -  
             -  +  -  +  
                      - ]
      26                 :        2270 :     explicit Obfuscation(std::span<const std::byte, KEY_SIZE> key_bytes)
      27                 :        2270 :     {
      28                 :        4540 :         SetRotations(ToKey(key_bytes));
      29                 :        2270 :     }
      30                 :             : 
      31   [ +  -  +  +  :    53466268 :     operator bool() const { return m_rotations[0] != 0; }
             +  +  +  - ]
           [ +  +  +  -  
             #  #  #  # ]
           [ +  +  +  +  
           +  + ][ -  + ]
      32                 :             : 
      33                 :     1974571 :     void operator()(std::span<std::byte> target, size_t key_offset = 0) const
      34                 :             :     {
      35         [ +  + ]:     1974571 :         if (!*this) return;
      36                 :             : 
      37         [ +  + ]:     1497878 :         KeyType rot_key{m_rotations[key_offset % KEY_SIZE]}; // Continue obfuscation from where we left off
      38         [ +  + ]:     1497878 :         if (target.size() > KEY_SIZE) {
      39                 :             :             // Obfuscate until 64-bit alignment boundary
      40         [ +  + ]:     1060584 :             if (const auto misalign{std::bit_cast<uintptr_t>(target.data()) % KEY_SIZE}) {
      41         [ +  - ]:         398 :                 const size_t alignment{std::min(KEY_SIZE - misalign, target.size())};
      42                 :         398 :                 XorWord(target.first(alignment), rot_key);
      43                 :             : 
      44                 :         398 :                 target = {std::assume_aligned<KEY_SIZE>(target.data() + alignment), target.size() - alignment};
      45                 :         398 :                 rot_key = m_rotations[(key_offset + alignment) % KEY_SIZE];
      46                 :             :             }
      47                 :             :             // Aligned obfuscation in 64-byte chunks
      48         [ +  + ]:   289729079 :             for (constexpr auto unroll{8}; target.size() >= KEY_SIZE * unroll; target = target.subspan(KEY_SIZE * unroll)) {
      49         [ +  + ]:  2598016455 :                 for (size_t i{0}; i < unroll; ++i) {
      50                 :  2309347960 :                     XorWord(target.subspan(i * KEY_SIZE, KEY_SIZE), rot_key);
      51                 :             :                 }
      52                 :             :             }
      53                 :             :             // Aligned obfuscation in 64-bit chunks
      54         [ +  + ]:     4319791 :             for (; target.size() >= KEY_SIZE; target = target.subspan(KEY_SIZE)) {
      55                 :     3259207 :                 XorWord(target.first<KEY_SIZE>(), rot_key);
      56                 :             :             }
      57                 :             :         }
      58                 :     1497878 :         XorWord(target, rot_key);
      59                 :             :     }
      60                 :             : 
      61                 :             :     template <typename Stream>
      62                 :         896 :     void Serialize(Stream& s) const
      63                 :             :     {
      64                 :             :         // Use vector serialization for convenient compact size prefix.
      65                 :         896 :         std::vector<std::byte> bytes{KEY_SIZE};
      66         [ +  - ]:         896 :         std::memcpy(bytes.data(), &m_rotations[0], KEY_SIZE);
      67                 :         896 :         s << bytes;
      68                 :         896 :     }
      69                 :             : 
      70                 :             :     template <typename Stream>
      71                 :        1756 :     void Unserialize(Stream& s)
      72                 :             :     {
      73                 :        1756 :         std::vector<std::byte> bytes{KEY_SIZE};
      74         [ -  + ]:        1756 :         s >> bytes;
      75   [ -  +  -  -  :        1756 :         if (bytes.size() != KEY_SIZE) throw std::ios_base::failure(strprintf("Obfuscation key size should be exactly %s bytes long", KEY_SIZE));
                   -  - ]
      76                 :        3512 :         SetRotations(ToKey(std::span<std::byte, KEY_SIZE>(bytes)));
      77                 :        1756 :     }
      78                 :             : 
      79                 :        3150 :     std::string HexKey() const
      80                 :             :     {
      81                 :        3150 :         return HexStr(std::bit_cast<std::array<uint8_t, KEY_SIZE>>(m_rotations[0]));
      82                 :             :     }
      83                 :             : 
      84                 :             : private:
      85                 :             :     // Cached key rotations for different offsets.
      86                 :             :     std::array<KeyType, KEY_SIZE> m_rotations;
      87                 :             : 
      88                 :       33427 :     void SetRotations(KeyType key)
      89                 :             :     {
      90   [ +  +  +  +  :      300843 :         for (size_t i{0}; i < KEY_SIZE; ++i) {
          +  +  +  +  +  
           +  +  + ][ +  
          +  +  +  +  +  
          +  +  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ +  +  +  
          +  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
           [ +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  +  
           + ][ -  -  +  
             +  +  +  +  
           + ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
      91                 :      267416 :             int key_rotation_bits{int(CHAR_BIT * i)};
      92                 :      267416 :             if constexpr (std::endian::native == std::endian::big) key_rotation_bits *= -1;
      93                 :      267416 :             m_rotations[i] = std::rotr(key, key_rotation_bits);
      94                 :             :         }
      95                 :             :     }
      96                 :             : 
      97                 :        4026 :     static KeyType ToKey(std::span<const std::byte, KEY_SIZE> key_span)
      98                 :             :     {
      99                 :        4026 :         KeyType key{};
     100                 :        4026 :         std::memcpy(&key, key_span.data(), KEY_SIZE);
     101                 :        4026 :         return key;
     102                 :             :     }
     103                 :             : 
     104                 :  2314105443 :     static void XorWord(std::span<std::byte> target, KeyType key)
     105                 :             :     {
     106         [ -  + ]:  2314105443 :         assert(target.size() <= KEY_SIZE);
     107         [ +  + ]:  2314105443 :         if (target.empty()) return;
     108                 :  2313844480 :         KeyType raw{};
     109                 :  2313844480 :         std::memcpy(&raw, target.data(), target.size());
     110                 :  2313844480 :         raw ^= key;
     111                 :  2313844480 :         std::memcpy(target.data(), &raw, target.size());
     112                 :             :     }
     113                 :             : };
     114                 :             : 
     115                 :             : #endif // BITCOIN_UTIL_OBFUSCATION_H
        

Generated by: LCOV version 2.0-1