/Users/eugenesiegel/btc/bitcoin/src/util/obfuscation.h
| Line | Count | Source (jump to first uncovered line) | 
| 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 | 153k |     Obfuscation() { SetRotations(0); } | 
| 26 |  |     explicit Obfuscation(std::span<const std::byte, KEY_SIZE> key_bytes) | 
| 27 | 51.2k |     { | 
| 28 | 51.2k |         SetRotations(ToKey(key_bytes)); | 
| 29 | 51.2k |     } | 
| 30 |  |  | 
| 31 | 16.4M |     operator bool() const { return m_rotations[0] != 0; } | 
| 32 |  |  | 
| 33 |  |     void operator()(std::span<std::byte> target, size_t key_offset = 0) const | 
| 34 | 14.1M |     { | 
| 35 | 14.1M |         if (!*this) return10.4M; | 
| 36 |  |  | 
| 37 | 3.67M |         KeyType rot_key{m_rotations[key_offset % KEY_SIZE]}; // Continue obfuscation from where we left off | 
| 38 | 3.67M |         if (target.size() > KEY_SIZE) { | 
| 39 |  |             // Obfuscate until KEY_SIZE alignment boundary | 
| 40 | 2.43M |             if (const auto misalign{reinterpret_cast<uintptr_t>(target.data()) % KEY_SIZE}) { | 
| 41 | 0 |                 const size_t alignment{KEY_SIZE - misalign}; | 
| 42 | 0 |                 XorWord(target.first(alignment), rot_key); | 
| 43 |  | 
 | 
| 44 | 0 |                 target = {std::assume_aligned<KEY_SIZE>(target.data() + alignment), target.size() - alignment}; | 
| 45 | 0 |                 rot_key = m_rotations[(key_offset + alignment) % KEY_SIZE]; | 
| 46 | 0 |             } | 
| 47 |  |             // Aligned obfuscation in 8*KEY_SIZE chunks | 
| 48 | 634M |             for (constexpr auto unroll{8}; target.size() >= KEY_SIZE * unroll; target = target.subspan(KEY_SIZE * unroll)631M) { | 
| 49 | 5.68G |                 for (size_t i{0}; i < unroll; ++i5.05G) { | 
| 50 | 5.05G |                     XorWord(target.subspan(i * KEY_SIZE, KEY_SIZE), rot_key); | 
| 51 | 5.05G |                 } | 
| 52 | 631M |             } | 
| 53 |  |             // Aligned obfuscation in KEY_SIZE chunks | 
| 54 | 8.49M |             for (; target.size() >= KEY_SIZE; target = target.subspan(KEY_SIZE)6.05M) { | 
| 55 | 6.05M |                 XorWord(target.first<KEY_SIZE>(), rot_key); | 
| 56 | 6.05M |             } | 
| 57 | 2.43M |         } | 
| 58 | 3.67M |         XorWord(target, rot_key); | 
| 59 | 3.67M |     } | 
| 60 |  |  | 
| 61 |  |     template <typename Stream> | 
| 62 |  |     void Serialize(Stream& s) const | 
| 63 | 0 |     { | 
| 64 |  |         // Use vector serialization for convenient compact size prefix. | 
| 65 | 0 |         std::vector<std::byte> bytes{KEY_SIZE}; | 
| 66 | 0 |         std::memcpy(bytes.data(), &m_rotations[0], KEY_SIZE); | 
| 67 | 0 |         s << bytes; | 
| 68 | 0 |     } Unexecuted instantiation: _ZNK11Obfuscation9SerializeI10DataStreamEEvRT_Unexecuted instantiation: _ZNK11Obfuscation9SerializeI8AutoFileEEvRT_ | 
| 69 |  |  | 
| 70 |  |     template <typename Stream> | 
| 71 |  |     void Unserialize(Stream& s) | 
| 72 | 51.2k |     { | 
| 73 | 51.2k |         std::vector<std::byte> bytes{KEY_SIZE}; | 
| 74 | 51.2k |         s >> bytes; | 
| 75 | 51.2k |         if (bytes.size() != KEY_SIZE) throw std::ios_base::failure(0 strprintf0("Obfuscation key size should be exactly %s bytes long", KEY_SIZE)); | Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 |         if (bytes.size() != KEY_SIZE) throw std::ios_base::failure(0 strprintf0("Obfuscation key size should be exactly %s bytes long", KEY_SIZE)); | Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 | 
| 76 | 51.2k |         SetRotations(ToKey(std::span<std::byte, KEY_SIZE>(bytes))); | 
| 77 | 51.2k |     } _ZN11Obfuscation11UnserializeI10DataStreamEEvRT_| Line | Count | Source |  | 72 | 51.2k |     { |  | 73 | 51.2k |         std::vector<std::byte> bytes{KEY_SIZE}; |  | 74 | 51.2k |         s >> bytes; |  | 75 | 51.2k |         if (bytes.size() != KEY_SIZE) throw std::ios_base::failure(0 strprintf0("Obfuscation key size should be exactly %s bytes long", KEY_SIZE)); | Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 |  | 76 | 51.2k |         SetRotations(ToKey(std::span<std::byte, KEY_SIZE>(bytes))); |  | 77 | 51.2k |     } | 
Unexecuted instantiation: _ZN11Obfuscation11UnserializeI8AutoFileEEvRT_ | 
| 78 |  |  | 
| 79 |  |     std::string HexKey() const | 
| 80 | 102k |     { | 
| 81 | 102k |         return HexStr(std::as_bytes(std::span{&m_rotations[0], 1})); | 
| 82 | 102k |     } | 
| 83 |  |  | 
| 84 |  | private: | 
| 85 |  |     // Cached key rotations for different offsets. | 
| 86 |  |     std::array<KeyType, KEY_SIZE> m_rotations; | 
| 87 |  |  | 
| 88 |  |     void SetRotations(KeyType key) | 
| 89 | 256k |     { | 
| 90 | 2.30M |         for (size_t i{0}; i < KEY_SIZE; ++i2.05M) { | 
| 91 | 2.05M |             int key_rotation_bits{int(CHAR_BIT * i)}; | 
| 92 |  |             if constexpr (std::endian::native == std::endian::big) key_rotation_bits *= -1; | 
| 93 | 2.05M |             m_rotations[i] = std::rotr(key, key_rotation_bits); | 
| 94 | 2.05M |         } | 
| 95 | 256k |     } | 
| 96 |  |  | 
| 97 |  |     static KeyType ToKey(std::span<const std::byte, KEY_SIZE> key_span) | 
| 98 | 102k |     { | 
| 99 | 102k |         KeyType key{}; | 
| 100 | 102k |         std::memcpy(&key, key_span.data(), KEY_SIZE); | 
| 101 | 102k |         return key; | 
| 102 | 102k |     } | 
| 103 |  |  | 
| 104 |  |     static void XorWord(std::span<std::byte> target, KeyType key) | 
| 105 | 5.06G |     { | 
| 106 | 5.06G |         assert(target.size() <= KEY_SIZE); | 
| 107 | 5.06G |         if (target.empty()) return738k; | 
| 108 | 5.06G |         KeyType raw{}; | 
| 109 | 5.06G |         std::memcpy(&raw, target.data(), target.size()); | 
| 110 | 5.06G |         raw ^= key; | 
| 111 | 5.06G |         std::memcpy(target.data(), &raw, target.size()); | 
| 112 | 5.06G |     } | 
| 113 |  | }; | 
| 114 |  |  | 
| 115 |  | #endif // BITCOIN_UTIL_OBFUSCATION_H |