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: 2026-04-07 04:59:12 Functions: 100.0 % 9 9
Branches: 70.2 % 188 132

             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 <crypto/hex_base.h>
       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 <cstdint>
      17                 :             : #include <ios>
      18                 :             : #include <memory>
      19                 :             : 
      20                 :             : class Obfuscation
      21                 :             : {
      22                 :             : public:
      23                 :             :     using KeyType = uint64_t;
      24                 :             :     static constexpr size_t KEY_SIZE{sizeof(KeyType)};
      25                 :             : 
      26   [ +  -  +  -  :       30373 :     Obfuscation() { SetRotations(0); }
                   +  - ]
           [ +  -  +  - ]
         [ +  - ][ +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
           +  - ][ +  -  
          +  -  +  -  +  
          -  +  -  +  -  
           +  - ][ +  -  
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      27                 :        2880 :     explicit Obfuscation(std::span<const std::byte, KEY_SIZE> key_bytes)
      28                 :        2880 :     {
      29                 :        5760 :         SetRotations(ToKey(key_bytes));
      30                 :        2880 :     }
      31                 :             : 
      32   [ +  +  +  +  :    70988347 :     operator bool() const { return m_rotations[0] != 0; }
           +  + ][ -  + ]
           [ +  -  +  -  
             +  -  +  - ]
      33                 :             : 
      34                 :     2073656 :     void operator()(std::span<std::byte> target, size_t key_offset = 0) const
      35                 :             :     {
      36         [ +  + ]:     2073656 :         if (!*this) return;
      37                 :             : 
      38         [ +  + ]:     1600776 :         KeyType rot_key{m_rotations[key_offset % KEY_SIZE]}; // Continue obfuscation from where we left off
      39         [ +  + ]:     1600776 :         if (target.size() > KEY_SIZE) {
      40                 :             :             // Obfuscate until KEY_SIZE alignment boundary
      41         [ +  + ]:     1138440 :             if (const auto misalign{reinterpret_cast<uintptr_t>(target.data()) % KEY_SIZE}) {
      42                 :         399 :                 const size_t alignment{KEY_SIZE - misalign};
      43                 :         399 :                 XorWord(target.first(alignment), rot_key);
      44                 :             : 
      45                 :         399 :                 target = {std::assume_aligned<KEY_SIZE>(target.data() + alignment), target.size() - alignment};
      46                 :         399 :                 rot_key = m_rotations[(key_offset + alignment) % KEY_SIZE];
      47                 :             :             }
      48                 :             :             // Aligned obfuscation in 8*KEY_SIZE chunks
      49         [ +  + ]:   291949933 :             for (constexpr auto unroll{8}; target.size() >= KEY_SIZE * unroll; target = target.subspan(KEY_SIZE * unroll)) {
      50         [ +  + ]:  2617303437 :                 for (size_t i{0}; i < unroll; ++i) {
      51                 :  2326491944 :                     XorWord(target.subspan(i * KEY_SIZE, KEY_SIZE), rot_key);
      52                 :             :                 }
      53                 :             :             }
      54                 :             :             // Aligned obfuscation in KEY_SIZE chunks
      55         [ +  + ]:     4494505 :             for (; target.size() >= KEY_SIZE; target = target.subspan(KEY_SIZE)) {
      56                 :     3356065 :                 XorWord(target.first<KEY_SIZE>(), rot_key);
      57                 :             :             }
      58                 :             :         }
      59                 :     1600776 :         XorWord(target, rot_key);
      60                 :             :     }
      61                 :             : 
      62                 :             :     template <typename Stream>
      63                 :        1498 :     void Serialize(Stream& s) const
      64                 :             :     {
      65                 :             :         // Use vector serialization for convenient compact size prefix.
      66                 :        1498 :         std::vector<std::byte> bytes{KEY_SIZE};
      67         [ +  - ]:        1498 :         std::memcpy(bytes.data(), &m_rotations[0], KEY_SIZE);
      68                 :        1498 :         s << bytes;
      69                 :        1498 :     }
      70                 :             : 
      71                 :             :     template <typename Stream>
      72                 :        1362 :     void Unserialize(Stream& s)
      73                 :             :     {
      74                 :        1362 :         std::vector<std::byte> bytes{KEY_SIZE};
      75         [ -  + ]:        1362 :         s >> bytes;
      76   [ -  +  -  -  :        1362 :         if (bytes.size() != KEY_SIZE) throw std::ios_base::failure(strprintf("Obfuscation key size should be exactly %s bytes long", KEY_SIZE));
                   -  - ]
      77                 :        2724 :         SetRotations(ToKey(std::span<std::byte, KEY_SIZE>(bytes)));
      78                 :        1362 :     }
      79                 :             : 
      80                 :        3436 :     std::string HexKey() const
      81                 :             :     {
      82                 :        3436 :         return HexStr(std::as_bytes(std::span{&m_rotations[0], 1}));
      83                 :             :     }
      84                 :             : 
      85                 :             : private:
      86                 :             :     // Cached key rotations for different offsets.
      87                 :             :     std::array<KeyType, KEY_SIZE> m_rotations;
      88                 :             : 
      89                 :       34615 :     void SetRotations(KeyType key)
      90                 :             :     {
      91   [ +  +  +  +  :      311535 :         for (size_t i{0}; i < KEY_SIZE; ++i) {
             +  +  +  + ]
           [ +  +  +  + ]
           [ +  +  +  +  
           +  + ][ +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
           +  + ][ +  +  
          +  +  +  +  +  
          +  +  +  +  +  
           -  - ][ +  +  
          +  +  +  +  +  
             +  +  +  +  
           + ][ -  -  +  
          +  -  -  +  +  
          -  -  -  -  -  
                      - ]
      92                 :      276920 :             int key_rotation_bits{int(CHAR_BIT * i)};
      93                 :      276920 :             if constexpr (std::endian::native == std::endian::big) key_rotation_bits *= -1;
      94                 :      276920 :             m_rotations[i] = std::rotr(key, key_rotation_bits);
      95                 :             :         }
      96                 :             :     }
      97                 :             : 
      98                 :        4242 :     static KeyType ToKey(std::span<const std::byte, KEY_SIZE> key_span)
      99                 :             :     {
     100                 :        4242 :         KeyType key{};
     101                 :        4242 :         std::memcpy(&key, key_span.data(), KEY_SIZE);
     102                 :        4242 :         return key;
     103                 :             :     }
     104                 :             : 
     105                 :  2331449184 :     static void XorWord(std::span<std::byte> target, KeyType key)
     106                 :             :     {
     107         [ -  + ]:  2331449184 :         assert(target.size() <= KEY_SIZE);
     108         [ +  + ]:  2331449184 :         if (target.empty()) return;
     109                 :  2331188824 :         KeyType raw{};
     110                 :  2331188824 :         std::memcpy(&raw, target.data(), target.size());
     111                 :  2331188824 :         raw ^= key;
     112                 :  2331188824 :         std::memcpy(target.data(), &raw, target.size());
     113                 :             :     }
     114                 :             : };
     115                 :             : 
     116                 :             : #endif // BITCOIN_UTIL_OBFUSCATION_H
        

Generated by: LCOV version 2.0-1