I briefly ran the below (vibe coded) benchmark on macOS (M4) and Ubuntu x86_64. Looks like == and != got faster (avoid a full memcmp), but < and > got slower.
| Comparison |
Local AppleClang old β new |
x86_64 GCC old β new |
| ==, first byte differs |
0.495 β 0.586 |
1.933 β 0.492 |
| ==, identical |
8.860 β 0.587 |
1.733 β 0.770 |
| ==, last byte differs |
8.651 β 0.587 |
1.930 β 0.771 |
| <, first byte differs |
0.504 β 0.494 |
1.928 β 0.394 |
| <, identical |
8.842 β 8.439 |
1.732 β 7.502 |
| <, last byte differs |
8.613 β 8.358 |
1.926 β 6.927 |
<details><summary>src/bench/uint256.cpp</summary>
diff --git a/src/bench/CMakeLists.txt b/src/bench/CMakeLists.txt
index 3c81e7986d..080a8ac848 100644
--- a/src/bench/CMakeLists.txt
+++ b/src/bench/CMakeLists.txt
@@ -53,6 +53,7 @@ add_executable(bench_bitcoin
strencodings.cpp
txgraph.cpp
txorphanage.cpp
+ uint256.cpp
util_time.cpp
verify_script.cpp
)
diff --git a/src/bench/uint256.cpp b/src/bench/uint256.cpp
new file mode 100644
--- /dev/null
+++ b/src/bench/uint256.cpp
@@ -0,0 +1,90 @@
+// Copyright (c) 2026-present The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or https://opensource.org/license/mit.
+
+#include <bench/bench.h>
+#include <random.h>
+#include <uint256.h>
+
+#include <cstddef>
+#include <utility>
+#include <vector>
+
+namespace {
+
+enum class Difference {
+ NONE,
+ FIRST_BYTE,
+ LAST_BYTE,
+};
+
+constexpr size_t NUM_PAIRS{4'096};
+
+std::vector<std::pair<uint256, uint256>> MakePairs(Difference difference)
+{
+ FastRandomContext rng{/*fDeterministic=*/true};
+ std::vector<std::pair<uint256, uint256>> pairs;
+ pairs.reserve(NUM_PAIRS);
+
+ for (size_t i{0}; i < NUM_PAIRS; ++i) {
+ uint256 lhs{rng.rand256()};
+ uint256 rhs{lhs};
+ if (difference != Difference::NONE) {
+ const size_t position{difference == Difference::FIRST_BYTE ? 0 : uint256::size() - 1};
+ lhs.begin()[position] = i % 2 == 0 ? 0 : 255;
+ rhs.begin()[position] = i % 2 == 0 ? 255 : 0;
+ }
+ pairs.emplace_back(lhs, rhs);
+ }
+ return pairs;
+}
+
+template <typename Comparator>
+void Comparison(benchmark::Bench& bench, Difference difference, Comparator comparator)
+{
+ const auto pairs{MakePairs(difference)};
+ bench.batch(pairs.size()).unit("comparison").run([&] {
+ for (const auto& [lhs, rhs] : pairs) {
+ ankerl::nanobench::doNotOptimizeAway(comparator(lhs, rhs));
+ }
+ });
+}
+
+void Uint256EqualIdentical(benchmark::Bench& bench)
+{
+ Comparison(bench, Difference::NONE, [](const uint256& lhs, const uint256& rhs) { return lhs == rhs; });
+}
+
+void Uint256EqualFirstByteDifferent(benchmark::Bench& bench)
+{
+ Comparison(bench, Difference::FIRST_BYTE, [](const uint256& lhs, const uint256& rhs) { return lhs == rhs; });
+}
+
+void Uint256EqualLastByteDifferent(benchmark::Bench& bench)
+{
+ Comparison(bench, Difference::LAST_BYTE, [](const uint256& lhs, const uint256& rhs) { return lhs == rhs; });
+}
+
+void Uint256LessIdentical(benchmark::Bench& bench)
+{
+ Comparison(bench, Difference::NONE, [](const uint256& lhs, const uint256& rhs) { return lhs < rhs; });
+}
+
+void Uint256LessFirstByteDifferent(benchmark::Bench& bench)
+{
+ Comparison(bench, Difference::FIRST_BYTE, [](const uint256& lhs, const uint256& rhs) { return lhs < rhs; });
+}
+
+void Uint256LessLastByteDifferent(benchmark::Bench& bench)
+{
+ Comparison(bench, Difference::LAST_BYTE, [](const uint256& lhs, const uint256& rhs) { return lhs < rhs; });
+}
+
+} // namespace
+
+BENCHMARK(Uint256EqualIdentical);
+BENCHMARK(Uint256EqualFirstByteDifferent);
+BENCHMARK(Uint256EqualLastByteDifferent);
+BENCHMARK(Uint256LessIdentical);
+BENCHMARK(Uint256LessFirstByteDifferent);
+BENCHMARK(Uint256LessLastByteDifferent);
</details>