Skip to content
Bitcoin Roots

v29.4-roots.1 · Commit 2: [PATCH 02/13] runtime: preserve shared operator controls

src/util/obfuscation.h

Before: /dev/null · After: src/util/obfuscation.h

File metadata
new file mode 100644
index 0000000000000000000000000000000000000000..9c92e13b5885fc48ab76f4ebbed7532be1902ab5

Download original patch · Release notes

Diff rows 1–115 of 115. Line numbers refer to the original before/after files.

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. Before is on the left; after is on the right. Unified view fits narrow screens more easily.

src/util/obfuscation.h ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ Obfuscation() { SetRotations(0); }
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()(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 64-bit alignment boundary
40
+ if (const auto misalign{std::bit_cast<uintptr_t>(target.data()) % KEY_SIZE}) {
41
+ const size_t alignment{std::min(KEY_SIZE - misalign, target.size())};
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 64-byte 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 64-bit 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::bit_cast<std::array<uint8_t, KEY_SIZE>>(m_rotations[0]));
82
+ }
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
+ {
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(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