Skip to content

Commit 377aab8

Browse files
l0rincmaflcko
andcommitted
refactor: move util::Xor to Obfuscation().Xor
This is meant to focus the usages to narrow the scope of the obfuscation optimization. `Obfuscation::Xor` is mostly a move. Co-authored-by: maflcko <[email protected]>
1 parent fa5d296 commit 377aab8

File tree

5 files changed

+26
-28
lines changed

5 files changed

+26
-28
lines changed

src/bench/obfuscation.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
#include <bench/bench.h>
66
#include <random.h>
7-
#include <streams.h>
87
#include <util/obfuscation.h>
98

109
#include <cstddef>
@@ -18,7 +17,7 @@ static void ObfuscationBench(benchmark::Bench& bench)
1817

1918
size_t offset{0};
2019
bench.batch(data.size()).unit("byte").run([&] {
21-
util::Xor(data, key, offset++); // mutated differently each time
20+
Obfuscation().Xor(data, key, offset++); // mutated differently each time
2221
ankerl::nanobench::doNotOptimizeAway(data);
2322
});
2423
}

src/streams.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <span.h>
77
#include <streams.h>
88
#include <util/fs_helpers.h>
9+
#include <util/obfuscation.h>
910

1011
#include <array>
1112

@@ -24,7 +25,7 @@ std::size_t AutoFile::detail_fread(std::span<std::byte> dst)
2425
size_t ret = std::fread(dst.data(), 1, dst.size(), m_file);
2526
if (!m_obfuscation.empty()) {
2627
if (!m_position.has_value()) throw std::ios_base::failure("AutoFile::read: position unknown");
27-
util::Xor(dst.subspan(0, ret), m_obfuscation, *m_position);
28+
Obfuscation().Xor(dst.subspan(0, ret), m_obfuscation, *m_position);
2829
}
2930
if (m_position.has_value()) *m_position += ret;
3031
return ret;
@@ -103,7 +104,7 @@ void AutoFile::write_buffer(std::span<std::byte> src)
103104
if (!m_file) throw std::ios_base::failure("AutoFile::write_buffer: file handle is nullptr");
104105
if (m_obfuscation.size()) {
105106
if (!m_position) throw std::ios_base::failure("AutoFile::write_buffer: obfuscation position unknown");
106-
util::Xor(src, m_obfuscation, *m_position); // obfuscate in-place
107+
Obfuscation().Xor(src, m_obfuscation, *m_position); // obfuscate in-place
107108
}
108109
if (std::fwrite(src.data(), 1, src.size(), m_file) != src.size()) {
109110
throw std::ios_base::failure("AutoFile::write_buffer: write failed");

src/streams.h

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <span.h>
1212
#include <support/allocators/zeroafterfree.h>
1313
#include <util/check.h>
14+
#include <util/obfuscation.h>
1415
#include <util/overflow.h>
1516
#include <util/syserror.h>
1617

@@ -27,27 +28,6 @@
2728
#include <utility>
2829
#include <vector>
2930

30-
namespace util {
31-
inline void Xor(std::span<std::byte> write, std::span<const std::byte> key, size_t key_offset = 0)
32-
{
33-
if (key.size() == 0) {
34-
return;
35-
}
36-
key_offset %= key.size();
37-
38-
for (size_t i = 0, j = key_offset; i != write.size(); i++) {
39-
write[i] ^= key[j++];
40-
41-
// This potentially acts on very many bytes of data, so it's
42-
// important that we calculate `j`, i.e. the `key` index in this
43-
// way instead of doing a %, which would effectively be a division
44-
// for each byte Xor'd -- much slower than need be.
45-
if (j == key.size())
46-
j = 0;
47-
}
48-
}
49-
} // namespace util
50-
5131
/* Minimal stream for overwriting and/or appending to an existing byte vector
5232
*
5333
* The referenced vector will grow as necessary
@@ -279,7 +259,7 @@ class DataStream
279259
*/
280260
void Xor(const std::vector<unsigned char>& key)
281261
{
282-
util::Xor(MakeWritableByteSpan(*this), MakeByteSpan(key));
262+
Obfuscation().Xor(MakeWritableByteSpan(*this), MakeByteSpan(key));
283263
}
284264

285265
/** Compute total memory usage of this object (own memory + any dynamic memory). */

src/test/streams_tests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ BOOST_AUTO_TEST_CASE(xor_roundtrip_random_chunks)
2424
auto apply_random_xor_chunks{[&](std::span<std::byte> target, std::span<const std::byte, Obfuscation::KEY_SIZE> obfuscation) {
2525
for (size_t offset{0}; offset < target.size();) {
2626
const size_t chunk_size{1 + m_rng.randrange(target.size() - offset)};
27-
util::Xor(target.subspan(offset, chunk_size), obfuscation, offset);
27+
Obfuscation().Xor(target.subspan(offset, chunk_size), obfuscation, offset);
2828
offset += chunk_size;
2929
}
3030
}};
@@ -67,7 +67,7 @@ BOOST_AUTO_TEST_CASE(xor_bytes_reference)
6767
std::vector actual{expected};
6868

6969
expected_xor(std::span{expected}.subspan(write_offset), key_bytes, key_offset);
70-
util::Xor(std::span{actual}.subspan(write_offset), key_bytes, key_offset);
70+
Obfuscation().Xor(std::span{actual}.subspan(write_offset), key_bytes, key_offset);
7171

7272
BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), actual.begin(), actual.end());
7373
}

src/util/obfuscation.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,29 @@
66
#define BITCOIN_UTIL_OBFUSCATION_H
77

88
#include <cstdint>
9+
#include <span.h>
910

1011
class Obfuscation
1112
{
1213
public:
1314
static constexpr size_t KEY_SIZE{sizeof(uint64_t)};
15+
16+
void Xor(std::span<std::byte> write, std::span<const std::byte> key, size_t key_offset = 0)
17+
{
18+
assert(key.size() == KEY_SIZE);
19+
key_offset %= KEY_SIZE;
20+
21+
for (size_t i = 0, j = key_offset; i != write.size(); i++) {
22+
write[i] ^= key[j++];
23+
24+
// This potentially acts on very many bytes of data, so it's
25+
// important that we calculate `j`, i.e. the `key` index in this
26+
// way instead of doing a %, which would effectively be a division
27+
// for each byte Xor'd -- much slower than need be.
28+
if (j == KEY_SIZE)
29+
j = 0;
30+
}
31+
}
1432
};
1533

1634
#endif // BITCOIN_UTIL_OBFUSCATION_H

0 commit comments

Comments
 (0)