From 3168b08043546cd248a81563e21ff096019f1521 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 18 Apr 2023 12:16:45 -0400 Subject: [PATCH] Bench test for EllSwift ECDH Co-authored-by: Dhruv Mehta <856960+dhruv@users.noreply.github.com> --- src/Makefile.bench.include | 1 + src/bench/bip324_ecdh.cpp | 51 ++++++++++++++++++++++++++++++++++++++ src/random.cpp | 6 +++++ src/random.h | 3 +++ 4 files changed, 61 insertions(+) create mode 100644 src/bench/bip324_ecdh.cpp diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index f970bf9958f..10c8389c800 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -18,6 +18,7 @@ bench_bench_bitcoin_SOURCES = \ bench/bench.cpp \ bench/bench.h \ bench/bench_bitcoin.cpp \ + bench/bip324_ecdh.cpp \ bench/block_assemble.cpp \ bench/ccoins_caching.cpp \ bench/chacha20.cpp \ diff --git a/src/bench/bip324_ecdh.cpp b/src/bench/bip324_ecdh.cpp new file mode 100644 index 00000000000..659da0f08e6 --- /dev/null +++ b/src/bench/bip324_ecdh.cpp @@ -0,0 +1,51 @@ +// Copyright (c) 2022 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include + +#include +#include + +static void BIP324_ECDH(benchmark::Bench& bench) +{ + ECC_Start(); + FastRandomContext rng; + + std::array key_data; + std::array our_ellswift_data; + std::array their_ellswift_data; + + rng.fillrand(key_data); + rng.fillrand(our_ellswift_data); + rng.fillrand(their_ellswift_data); + + bench.batch(1).unit("ecdh").run([&] { + CKey key; + key.Set(UCharCast(key_data.data()), UCharCast(key_data.data()) + 32, true); + EllSwiftPubKey our_ellswift(our_ellswift_data); + EllSwiftPubKey their_ellswift(their_ellswift_data); + + auto ret = key.ComputeBIP324ECDHSecret(their_ellswift, our_ellswift, true); + + // To make sure that the computation is not the same on every iteration (ellswift decoding + // is variable-time), distribute bytes from the shared secret over the 3 inputs. The most + // important one is their_ellswift, because that one is actually decoded, so it's given most + // bytes. The data is copied into the middle, so that both halves are affected: + // - Copy 8 bytes from the resulting shared secret into middle of the private key. + std::copy(ret.begin(), ret.begin() + 8, key_data.begin() + 12); + // - Copy 8 bytes from the resulting shared secret into the middle of our ellswift key. + std::copy(ret.begin() + 8, ret.begin() + 16, our_ellswift_data.begin() + 28); + // - Copy 16 bytes from the resulting shared secret into the middle of their ellswift key. + std::copy(ret.begin() + 16, ret.end(), their_ellswift_data.begin() + 24); + }); + + ECC_Stop(); +} + +BENCHMARK(BIP324_ECDH, benchmark::PriorityLevel::HIGH); diff --git a/src/random.cpp b/src/random.cpp index 54500e6cc6b..39ceae42063 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -599,6 +599,12 @@ std::vector FastRandomContext::randbytes(size_t len) return ret; } +void FastRandomContext::fillrand(Span output) +{ + if (requires_seed) RandomSeed(); + rng.Keystream(UCharCast(output.data()), output.size()); +} + FastRandomContext::FastRandomContext(const uint256& seed) noexcept : requires_seed(false), bitbuf_size(0) { rng.SetKey32(seed.begin()); diff --git a/src/random.h b/src/random.h index 49c0dff5bf5..50f56ed9117 100644 --- a/src/random.h +++ b/src/random.h @@ -213,6 +213,9 @@ public: /** Generate random bytes. */ std::vector randbytes(size_t len); + /** Fill a byte Span with random bytes. */ + void fillrand(Span output); + /** Generate a random 32-bit integer. */ uint32_t rand32() noexcept { return randbits(32); }