LCOV - code coverage report
Current view: top level - src/util - obfuscation.h (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 100.0 % 50 50
Test Date: 2025-08-13 04:26:42 Functions: 75.0 % 8 6
Branches: 55.3 % 228 126

             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   [ +  -  +  -  :        1230 :     Obfuscation() { SetRotations(0); }
          +  -  +  -  +  
           -  +  - ][ +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
           -  +  - ][ +  
          -  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
           [ +  -  +  - ]
           [ -  -  +  -  
                   +  - ]
      26                 :         486 :     explicit Obfuscation(std::span<const std::byte, KEY_SIZE> key_bytes)
      27                 :         486 :     {
      28                 :         972 :         SetRotations(ToKey(key_bytes));
      29                 :         486 :     }
      30                 :             : 
      31   [ +  -  +  -  :       73737 :     operator bool() const { return m_rotations[0] != 0; }
             +  -  +  - ]
           [ +  +  +  +  
             +  +  #  # ]
                 [ -  + ]
      32                 :             : 
      33                 :      174388 :     void operator()(std::span<std::byte> target, size_t key_offset = 0) const
      34                 :             :     {
      35         [ +  + ]:      174388 :         if (!*this) return;
      36                 :             : 
      37         [ +  + ]:       95992 :         KeyType rot_key{m_rotations[key_offset % KEY_SIZE]}; // Continue obfuscation from where we left off
      38         [ +  + ]:       95992 :         if (target.size() > KEY_SIZE) {
      39                 :             :             // Obfuscate until KEY_SIZE alignment boundary
      40         [ +  + ]:       88575 :             if (const auto misalign{reinterpret_cast<uintptr_t>(target.data()) % KEY_SIZE}) {
      41                 :         293 :                 const size_t alignment{KEY_SIZE - misalign};
      42                 :         293 :                 XorWord(target.first(alignment), rot_key);
      43                 :             : 
      44                 :         293 :                 target = {std::assume_aligned<KEY_SIZE>(target.data() + alignment), target.size() - alignment};
      45                 :         293 :                 rot_key = m_rotations[(key_offset + alignment) % KEY_SIZE];
      46                 :             :             }
      47                 :             :             // Aligned obfuscation in 8*KEY_SIZE chunks
      48         [ +  + ]:     1077779 :             for (constexpr auto unroll{8}; target.size() >= KEY_SIZE * unroll; target = target.subspan(KEY_SIZE * unroll)) {
      49         [ +  + ]:     8902836 :                 for (size_t i{0}; i < unroll; ++i) {
      50                 :     7913632 :                     XorWord(target.subspan(i * KEY_SIZE, KEY_SIZE), rot_key);
      51                 :             :                 }
      52                 :             :             }
      53                 :             :             // Aligned obfuscation in KEY_SIZE chunks
      54         [ +  + ]:      188420 :             for (; target.size() >= KEY_SIZE; target = target.subspan(KEY_SIZE)) {
      55                 :       99845 :                 XorWord(target.first<KEY_SIZE>(), rot_key);
      56                 :             :             }
      57                 :             :         }
      58                 :       95992 :         XorWord(target, rot_key);
      59                 :             :     }
      60                 :             : 
      61                 :             :     template <typename Stream>
      62                 :         199 :     void Serialize(Stream& s) const
      63                 :             :     {
      64                 :             :         // Use vector serialization for convenient compact size prefix.
      65                 :         199 :         std::vector<std::byte> bytes{KEY_SIZE};
      66         [ +  - ]:         199 :         std::memcpy(bytes.data(), &m_rotations[0], KEY_SIZE);
      67                 :         199 :         s << bytes;
      68                 :         199 :     }
      69                 :             : 
      70                 :             :     template <typename Stream>
      71                 :          53 :     void Unserialize(Stream& s)
      72                 :             :     {
      73                 :          53 :         std::vector<std::byte> bytes{KEY_SIZE};
      74         [ -  + ]:          53 :         s >> bytes;
      75   [ -  +  -  -  :          53 :         if (bytes.size() != KEY_SIZE) throw std::ios_base::failure(strprintf("Obfuscation key size should be exactly %s bytes long", KEY_SIZE));
                   -  - ]
      76                 :         106 :         SetRotations(ToKey(std::span<std::byte, KEY_SIZE>(bytes)));
      77                 :          53 :     }
      78                 :             : 
      79                 :         652 :     std::string HexKey() const
      80                 :             :     {
      81                 :         652 :         return HexStr(std::as_bytes(std::span{&m_rotations[0], 1}));
      82                 :             :     }
      83                 :             : 
      84                 :             : private:
      85                 :             :     // Cached key rotations for different offsets.
      86                 :             :     std::array<KeyType, KEY_SIZE> m_rotations;
      87                 :             : 
      88                 :        1769 :     void SetRotations(KeyType key)
      89                 :             :     {
      90 [ +  + ][ +  +  :       15921 :         for (size_t i{0}; i < KEY_SIZE; ++i) {
          +  +  +  +  +  
          +  +  +  +  +  
          #  #  #  #  #  
             #  #  #  #  
           # ][ +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
           + ][ +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  #  
           # ][ +  +  +  
          +  #  #  #  #  
             #  #  #  # ]
           [ -  -  +  +  
             +  +  +  + ]
           [ #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
           # ][ -  -  +  
                +  -  - ]
      91                 :       14152 :             int key_rotation_bits{int(CHAR_BIT * i)};
      92                 :       14152 :             if constexpr (std::endian::native == std::endian::big) key_rotation_bits *= -1;
      93                 :       14152 :             m_rotations[i] = std::rotr(key, key_rotation_bits);
      94                 :             :         }
      95                 :             :     }
      96                 :             : 
      97                 :         539 :     static KeyType ToKey(std::span<const std::byte, KEY_SIZE> key_span)
      98                 :             :     {
      99                 :         539 :         KeyType key{};
     100                 :         539 :         std::memcpy(&key, key_span.data(), KEY_SIZE);
     101                 :         539 :         return key;
     102                 :             :     }
     103                 :             : 
     104                 :     8109762 :     static void XorWord(std::span<std::byte> target, KeyType key)
     105                 :             :     {
     106         [ -  + ]:     8109762 :         assert(target.size() <= KEY_SIZE);
     107         [ +  + ]:     8109762 :         if (target.empty()) return;
     108                 :     8108269 :         KeyType raw{};
     109                 :     8108269 :         std::memcpy(&raw, target.data(), target.size());
     110                 :     8108269 :         raw ^= key;
     111                 :     8108269 :         std::memcpy(target.data(), &raw, target.size());
     112                 :             :     }
     113                 :             : };
     114                 :             : 
     115                 :             : #endif // BITCOIN_UTIL_OBFUSCATION_H
        

Generated by: LCOV version 2.0-1