Bitcoin Core 31.99.0
P2P Digital Currency
obfuscation.h
Go to the documentation of this file.
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
21{
22public:
23 using KeyType = uint64_t;
24 static constexpr size_t KEY_SIZE{sizeof(KeyType)};
25
27 explicit Obfuscation(std::span<const std::byte, KEY_SIZE> key_bytes)
28 {
29 SetRotations(ToKey(key_bytes));
30 }
31
32 operator bool() const { return m_rotations[0] != 0; }
33
34 void operator()(std::span<std::byte> target, size_t key_offset = 0) const
35 {
36 if (!*this) return;
37
38 KeyType rot_key{m_rotations[key_offset % KEY_SIZE]}; // Continue obfuscation from where we left off
39 if (target.size() > KEY_SIZE) {
40 // Obfuscate until KEY_SIZE alignment boundary
41 if (const auto misalign{reinterpret_cast<uintptr_t>(target.data()) % KEY_SIZE}) {
42 const size_t alignment{KEY_SIZE - misalign};
43 XorWord(target.first(alignment), rot_key);
44
45 target = {std::assume_aligned<KEY_SIZE>(target.data() + alignment), target.size() - alignment};
46 rot_key = m_rotations[(key_offset + alignment) % KEY_SIZE];
47 }
48 // Aligned obfuscation in 8*KEY_SIZE chunks
49 for (constexpr auto unroll{8}; target.size() >= KEY_SIZE * unroll; target = target.subspan(KEY_SIZE * unroll)) {
50 for (size_t i{0}; i < unroll; ++i) {
51 XorWord(target.subspan(i * KEY_SIZE, KEY_SIZE), rot_key);
52 }
53 }
54 // Aligned obfuscation in KEY_SIZE chunks
55 for (; target.size() >= KEY_SIZE; target = target.subspan(KEY_SIZE)) {
56 XorWord(target.first<KEY_SIZE>(), rot_key);
57 }
58 }
59 XorWord(target, rot_key);
60 }
61
62 template <typename Stream>
63 void Serialize(Stream& s) const
64 {
65 // Use vector serialization for convenient compact size prefix.
66 std::vector<std::byte> bytes{KEY_SIZE};
67 std::memcpy(bytes.data(), &m_rotations[0], KEY_SIZE);
68 s << bytes;
69 }
70
71 template <typename Stream>
72 void Unserialize(Stream& s)
73 {
74 std::vector<std::byte> bytes{KEY_SIZE};
75 s >> bytes;
76 if (bytes.size() != KEY_SIZE) throw std::ios_base::failure(strprintf("Obfuscation key size should be exactly %s bytes long", KEY_SIZE));
77 SetRotations(ToKey(std::span<std::byte, KEY_SIZE>(bytes)));
78 }
79
80 std::string HexKey() const
81 {
82 return HexStr(std::as_bytes(std::span{&m_rotations[0], 1}));
83 }
84
85private:
86 // Cached key rotations for different offsets.
87 std::array<KeyType, KEY_SIZE> m_rotations;
88
90 {
91 for (size_t i{0}; i < KEY_SIZE; ++i) {
92 int key_rotation_bits{int(CHAR_BIT * i)};
93 if constexpr (std::endian::native == std::endian::big) key_rotation_bits *= -1;
94 m_rotations[i] = std::rotr(key, key_rotation_bits);
95 }
96 }
97
98 static KeyType ToKey(std::span<const std::byte, KEY_SIZE> key_span)
99 {
100 KeyType key{};
101 std::memcpy(&key, key_span.data(), KEY_SIZE);
102 return key;
103 }
104
105 static void XorWord(std::span<std::byte> target, KeyType key)
106 {
107 assert(target.size() <= KEY_SIZE);
108 if (target.empty()) return;
109 KeyType raw{};
110 std::memcpy(&raw, target.data(), target.size());
111 raw ^= key;
112 std::memcpy(target.data(), &raw, target.size());
113 }
114};
115
116#endif // BITCOIN_UTIL_OBFUSCATION_H
std::array< KeyType, KEY_SIZE > m_rotations
Definition: obfuscation.h:87
Obfuscation(std::span< const std::byte, KEY_SIZE > key_bytes)
Definition: obfuscation.h:27
void Unserialize(Stream &s)
Definition: obfuscation.h:72
std::string HexKey() const
Definition: obfuscation.h:80
void SetRotations(KeyType key)
Definition: obfuscation.h:89
static KeyType ToKey(std::span< const std::byte, KEY_SIZE > key_span)
Definition: obfuscation.h:98
static void XorWord(std::span< std::byte > target, KeyType key)
Definition: obfuscation.h:105
void operator()(std::span< std::byte > target, size_t key_offset=0) const
Definition: obfuscation.h:34
static constexpr size_t KEY_SIZE
Definition: obfuscation.h:24
void Serialize(Stream &s) const
Definition: obfuscation.h:63
uint64_t KeyType
Definition: obfuscation.h:23
std::string HexStr(const std::span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
Definition: hex_base.cpp:30
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
assert(!tx.IsCoinBase())