diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index 10c8389c800..51bfb1e4593 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -52,7 +52,8 @@ bench_bench_bitcoin_SOURCES = \ bench/streams_findbyte.cpp \ bench/strencodings.cpp \ bench/util_time.cpp \ - bench/verify_script.cpp + bench/verify_script.cpp \ + bench/xor.cpp nodist_bench_bench_bitcoin_SOURCES = $(GENERATED_BENCH_FILES) diff --git a/src/bench/bench.h b/src/bench/bench.h index 78196134e78..6065ddf3fc9 100644 --- a/src/bench/bench.h +++ b/src/bench/bench.h @@ -14,7 +14,7 @@ #include #include -#include +#include // IWYU pragma: export /* * Usage: diff --git a/src/bench/xor.cpp b/src/bench/xor.cpp new file mode 100644 index 00000000000..edda74214a2 --- /dev/null +++ b/src/bench/xor.cpp @@ -0,0 +1,24 @@ +// Copyright (c) The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/license/mit/. + +#include + +#include +#include + +#include +#include + +static void Xor(benchmark::Bench& bench) +{ + FastRandomContext frc{/*fDeterministic=*/true}; + auto data{frc.randbytes(1024)}; + auto key{frc.randbytes(31)}; + + bench.batch(data.size()).unit("byte").run([&] { + util::Xor(data, key); + }); +} + +BENCHMARK(Xor, benchmark::PriorityLevel::HIGH); diff --git a/src/streams.h b/src/streams.h index 03df20b5db8..4fbbdc573c9 100644 --- a/src/streams.h +++ b/src/streams.h @@ -23,6 +23,27 @@ #include #include +namespace util { +inline void Xor(Span write, Span 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 + template class OverrideStream { @@ -316,20 +337,7 @@ public: */ void Xor(const std::vector& key) { - if (key.size() == 0) { - return; - } - - for (size_type i = 0, j = 0; i != size(); i++) { - vch[i] ^= std::byte{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; - } + util::Xor(MakeWritableByteSpan(*this), MakeByteSpan(key)); } }; @@ -469,7 +477,6 @@ public: } }; - /** Non-refcounted RAII wrapper for FILE* * * Will automatically close the file when it goes out of scope if not null.