mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-08-27 19:01:41 +02:00
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 <6399679+maflcko@users.noreply.github.com>
This commit is contained in:
@@ -4,7 +4,6 @@
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <random.h>
|
||||
#include <streams.h>
|
||||
#include <util/obfuscation.h>
|
||||
|
||||
#include <cstddef>
|
||||
@@ -18,7 +17,7 @@ static void ObfuscationBench(benchmark::Bench& bench)
|
||||
|
||||
size_t offset{0};
|
||||
bench.batch(data.size()).unit("byte").run([&] {
|
||||
util::Xor(data, key, offset++); // mutated differently each time
|
||||
Obfuscation().Xor(data, key, offset++); // mutated differently each time
|
||||
ankerl::nanobench::doNotOptimizeAway(data);
|
||||
});
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@
|
||||
#include <span.h>
|
||||
#include <streams.h>
|
||||
#include <util/fs_helpers.h>
|
||||
#include <util/obfuscation.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
@@ -24,7 +25,7 @@ std::size_t AutoFile::detail_fread(std::span<std::byte> dst)
|
||||
size_t ret = std::fread(dst.data(), 1, dst.size(), m_file);
|
||||
if (!m_obfuscation.empty()) {
|
||||
if (!m_position.has_value()) throw std::ios_base::failure("AutoFile::read: position unknown");
|
||||
util::Xor(dst.subspan(0, ret), m_obfuscation, *m_position);
|
||||
Obfuscation().Xor(dst.subspan(0, ret), m_obfuscation, *m_position);
|
||||
}
|
||||
if (m_position.has_value()) *m_position += ret;
|
||||
return ret;
|
||||
@@ -103,7 +104,7 @@ void AutoFile::write_buffer(std::span<std::byte> src)
|
||||
if (!m_file) throw std::ios_base::failure("AutoFile::write_buffer: file handle is nullptr");
|
||||
if (m_obfuscation.size()) {
|
||||
if (!m_position) throw std::ios_base::failure("AutoFile::write_buffer: obfuscation position unknown");
|
||||
util::Xor(src, m_obfuscation, *m_position); // obfuscate in-place
|
||||
Obfuscation().Xor(src, m_obfuscation, *m_position); // obfuscate in-place
|
||||
}
|
||||
if (std::fwrite(src.data(), 1, src.size(), m_file) != src.size()) {
|
||||
throw std::ios_base::failure("AutoFile::write_buffer: write failed");
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include <span.h>
|
||||
#include <support/allocators/zeroafterfree.h>
|
||||
#include <util/check.h>
|
||||
#include <util/obfuscation.h>
|
||||
#include <util/overflow.h>
|
||||
#include <util/syserror.h>
|
||||
|
||||
@@ -27,27 +28,6 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace util {
|
||||
inline void Xor(std::span<std::byte> write, std::span<const std::byte> key, size_t key_offset = 0)
|
||||
{
|
||||
if (key.size() == 0) {
|
||||
return;
|
||||
}
|
||||
key_offset %= key.size();
|
||||
|
||||
for (size_t i = 0, j = key_offset; i != write.size(); i++) {
|
||||
write[i] ^= key[j++];
|
||||
|
||||
// This potentially acts on very many bytes of data, so it's
|
||||
// important that we calculate `j`, i.e. the `key` index in this
|
||||
// way instead of doing a %, which would effectively be a division
|
||||
// for each byte Xor'd -- much slower than need be.
|
||||
if (j == key.size())
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
} // namespace util
|
||||
|
||||
/* Minimal stream for overwriting and/or appending to an existing byte vector
|
||||
*
|
||||
* The referenced vector will grow as necessary
|
||||
@@ -279,7 +259,7 @@ public:
|
||||
*/
|
||||
void Xor(const std::vector<unsigned char>& key)
|
||||
{
|
||||
util::Xor(MakeWritableByteSpan(*this), MakeByteSpan(key));
|
||||
Obfuscation().Xor(MakeWritableByteSpan(*this), MakeByteSpan(key));
|
||||
}
|
||||
|
||||
/** Compute total memory usage of this object (own memory + any dynamic memory). */
|
||||
|
@@ -24,7 +24,7 @@ BOOST_AUTO_TEST_CASE(xor_roundtrip_random_chunks)
|
||||
auto apply_random_xor_chunks{[&](std::span<std::byte> target, std::span<const std::byte, Obfuscation::KEY_SIZE> obfuscation) {
|
||||
for (size_t offset{0}; offset < target.size();) {
|
||||
const size_t chunk_size{1 + m_rng.randrange(target.size() - offset)};
|
||||
util::Xor(target.subspan(offset, chunk_size), obfuscation, offset);
|
||||
Obfuscation().Xor(target.subspan(offset, chunk_size), obfuscation, offset);
|
||||
offset += chunk_size;
|
||||
}
|
||||
}};
|
||||
@@ -67,7 +67,7 @@ BOOST_AUTO_TEST_CASE(xor_bytes_reference)
|
||||
std::vector actual{expected};
|
||||
|
||||
expected_xor(std::span{expected}.subspan(write_offset), key_bytes, key_offset);
|
||||
util::Xor(std::span{actual}.subspan(write_offset), key_bytes, key_offset);
|
||||
Obfuscation().Xor(std::span{actual}.subspan(write_offset), key_bytes, key_offset);
|
||||
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), actual.begin(), actual.end());
|
||||
}
|
||||
|
@@ -6,11 +6,29 @@
|
||||
#define BITCOIN_UTIL_OBFUSCATION_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <span.h>
|
||||
|
||||
class Obfuscation
|
||||
{
|
||||
public:
|
||||
static constexpr size_t KEY_SIZE{sizeof(uint64_t)};
|
||||
|
||||
void Xor(std::span<std::byte> write, std::span<const std::byte> key, size_t key_offset = 0)
|
||||
{
|
||||
assert(key.size() == KEY_SIZE);
|
||||
key_offset %= KEY_SIZE;
|
||||
|
||||
for (size_t i = 0, j = key_offset; i != write.size(); i++) {
|
||||
write[i] ^= key[j++];
|
||||
|
||||
// This potentially acts on very many bytes of data, so it's
|
||||
// important that we calculate `j`, i.e. the `key` index in this
|
||||
// way instead of doing a %, which would effectively be a division
|
||||
// for each byte Xor'd -- much slower than need be.
|
||||
if (j == KEY_SIZE)
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // BITCOIN_UTIL_OBFUSCATION_H
|
||||
|
Reference in New Issue
Block a user