Bitcoin Core  31.0.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 {
21 public:
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 
84 private:
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
assert(!tx.IsCoinBase())
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
static KeyType ToKey(std::span< const std::byte, KEY_SIZE > key_span)
Definition: obfuscation.h:97
memcpy(result.begin(), stream.data(), stream.size())
static constexpr size_t KEY_SIZE
Definition: obfuscation.h:23
void Unserialize(Stream &s)
Definition: obfuscation.h:71
void SetRotations(KeyType key)
Definition: obfuscation.h:88
void Serialize(Stream &s) const
Definition: obfuscation.h:62
std::array< KeyType, KEY_SIZE > m_rotations
Definition: obfuscation.h:86
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
std::string HexKey() const
Definition: obfuscation.h:79
uint64_t KeyType
Definition: obfuscation.h:22
Obfuscation(std::span< const std::byte, KEY_SIZE > key_bytes)
Definition: obfuscation.h:26
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