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