From b35b4a9f76162c5464d37ec8e7d109a530341c3c Mon Sep 17 00:00:00 2001 From: SChernykh Date: Tue, 14 Sep 2021 11:06:49 +0200 Subject: [PATCH] Crypto: added cache for faster key derivation --- src/common.h | 1 + src/crypto.cpp | 140 +++++++++++++++++++++++++++++++++------------ src/side_chain.cpp | 1 - src/util.h | 13 +++++ src/wallet.cpp | 51 ++--------------- src/wallet.h | 8 +-- 6 files changed, 124 insertions(+), 90 deletions(-) diff --git a/src/common.h b/src/common.h index 8e433ed..5077550 100644 --- a/src/common.h +++ b/src/common.h @@ -47,6 +47,7 @@ #include #include +#include #include #include #include diff --git a/src/crypto.cpp b/src/crypto.cpp index 7f34fb4..87f9f15 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -20,6 +20,7 @@ #include "keccak.h" #include "uv_util.h" #include +#include extern "C" { #include "crypto-ops.h" @@ -108,24 +109,6 @@ bool check_keys(const hash& pub, const hash& sec) return pub == pub_check; } -bool generate_key_derivation(const hash& key1, const hash& key2, hash& derivation) -{ - ge_p3 point; - ge_p2 point2; - ge_p1p1 point3; - - if (ge_frombytes_vartime(&point, key1.h) != 0) { - return false; - } - - ge_scalarmult(&point2, key2.h, &point); - ge_mul8(&point3, &point2); - ge_p1p1_to_p2(&point2, &point3); - ge_tobytes(reinterpret_cast(&derivation), &point2); - - return true; -} - static FORCEINLINE void hash_to_scalar(const uint8_t* data, size_t length, uint8_t(&res)[HASH_SIZE]) { keccak(data, static_cast(length), res, HASH_SIZE); @@ -153,28 +136,113 @@ static FORCEINLINE void derivation_to_scalar(const hash& derivation, size_t outp hash_to_scalar(begin, end - begin, res); } -// cppcheck-suppress constParameter -bool derive_public_key(const hash& derivation, size_t output_index, const hash& base, hash& derived_key) +class Cache { - uint8_t scalar[HASH_SIZE]; - ge_p3 point1; - ge_p3 point2; - ge_cached point3; - ge_p1p1 point4; - ge_p2 point5; - - if (ge_frombytes_vartime(&point1, base.h) != 0) { - return false; +public: + Cache() + { + uv_mutex_init_checked(&m); } - derivation_to_scalar(derivation, output_index, scalar); - ge_scalarmult_base(&point2, reinterpret_cast(&scalar)); - ge_p3_to_cached(&point3, &point2); - ge_add(&point4, &point1, &point3); - ge_p1p1_to_p2(&point5, &point4); - ge_tobytes(derived_key.h, &point5); + ~Cache() + { + uv_mutex_destroy(&m); + } - return true; + bool get_derivation(const hash& key1, const hash& key2, hash& derivation) + { + std::array index; + memcpy(index.data(), key1.h, HASH_SIZE); + memcpy(index.data() + HASH_SIZE, key2.h, HASH_SIZE); + + { + MutexLock lock(m); + auto it = derivations.find(index); + if (it != derivations.end()) { + derivation = it->second; + return true; + } + } + + ge_p3 point; + ge_p2 point2; + ge_p1p1 point3; + + if (ge_frombytes_vartime(&point, key1.h) != 0) { + return false; + } + + ge_scalarmult(&point2, key2.h, &point); + ge_mul8(&point3, &point2); + ge_p1p1_to_p2(&point2, &point3); + ge_tobytes(reinterpret_cast(&derivation), &point2); + + { + MutexLock lock(m); + derivations.emplace(index, derivation); + } + + return true; + } + + bool get_public_key(const hash& derivation, size_t output_index, const hash& base, hash& derived_key) + { + std::array index; + memcpy(index.data(), derivation.h, HASH_SIZE); + memcpy(index.data() + HASH_SIZE, base.h, HASH_SIZE); + memcpy(index.data() + HASH_SIZE * 2, &output_index, sizeof(size_t)); + + { + MutexLock lock(m); + auto it = public_keys.find(index); + if (it != public_keys.end()) { + derived_key = it->second; + return true; + } + } + + uint8_t scalar[HASH_SIZE]; + ge_p3 point1; + ge_p3 point2; + ge_cached point3; + ge_p1p1 point4; + ge_p2 point5; + + if (ge_frombytes_vartime(&point1, base.h) != 0) { + return false; + } + + derivation_to_scalar(derivation, output_index, scalar); + ge_scalarmult_base(&point2, reinterpret_cast(&scalar)); + ge_p3_to_cached(&point3, &point2); + ge_add(&point4, &point1, &point3); + ge_p1p1_to_p2(&point5, &point4); + ge_tobytes(derived_key.h, &point5); + + { + MutexLock lock(m); + public_keys.emplace(index, derived_key); + } + + return true; + } + +private: + uv_mutex_t m; + std::unordered_map, hash> derivations; + std::unordered_map, hash> public_keys; +}; + +static Cache cache; + +bool generate_key_derivation(const hash& key1, const hash& key2, hash& derivation) +{ + return cache.get_derivation(key1, key2, derivation); +} + +bool derive_public_key(const hash& derivation, size_t output_index, const hash& base, hash& derived_key) +{ + return cache.get_public_key(derivation, output_index, base, derived_key); } } // namespace p2pool diff --git a/src/side_chain.cpp b/src/side_chain.cpp index 08b42de..3152e25 100644 --- a/src/side_chain.cpp +++ b/src/side_chain.cpp @@ -34,7 +34,6 @@ #include #include #include -#include // Only uncomment it to debug issues with uncle/orphan blocks //#define DEBUG_BROADCAST_DELAY_MS 100 diff --git a/src/util.h b/src/util.h index 2f25360..bc55422 100644 --- a/src/util.h +++ b/src/util.h @@ -136,4 +136,17 @@ struct hash } }; +template +struct hash> +{ + FORCEINLINE size_t operator()(const std::array& value) const + { + uint64_t result = 0xcbf29ce484222325ull; + for (size_t i = 0; i < N; ++i) { + result = (result ^ value[i]) * 0x100000001b3ull; + } + return static_cast(result); + } +}; + } // namespace std diff --git a/src/wallet.cpp b/src/wallet.cpp index e31c45d..e0a59f5 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -22,7 +22,6 @@ #include "wallet.h" #include "keccak.h" #include "crypto.h" -#include extern "C" { #include "crypto-ops.h" @@ -81,23 +80,16 @@ static_assert(rev_alphabet.num_symbols == 58, "Check alphabet"); namespace p2pool { Wallet::Wallet(const char* address) - : m_txkeySec{} - , m_outputIndex(std::numeric_limits::max()) - , m_derivation{} - , m_ephPublicKey{} { - uv_mutex_init_checked(&m_lock); decode(address); } Wallet::~Wallet() { - uv_mutex_destroy(&m_lock); } Wallet::Wallet(const Wallet& w) { - uv_mutex_init_checked(&m_lock); operator=(w); } @@ -108,18 +100,11 @@ Wallet& Wallet::operator=(const Wallet& w) return *this; } - MutexLock lock(m_lock); - MutexLock lock2(w.m_lock); - m_prefix = w.m_prefix; m_spendPublicKey = w.m_spendPublicKey; m_viewPublicKey = w.m_viewPublicKey; m_checksum = w.m_checksum; m_type = w.m_type; - m_txkeySec = w.m_txkeySec; - m_outputIndex = w.m_outputIndex; - m_derivation = w.m_derivation; - m_ephPublicKey = w.m_ephPublicKey; return *this; } @@ -204,8 +189,6 @@ bool Wallet::assign(const hash& spend_pub_key, const hash& view_pub_key, Network return false; } - MutexLock lock(m_lock); - m_prefix = 0; m_spendPublicKey = spend_pub_key; m_viewPublicKey = view_pub_key; @@ -213,42 +196,18 @@ bool Wallet::assign(const hash& spend_pub_key, const hash& view_pub_key, Network m_type = type; - m_txkeySec = {}; - m_outputIndex = std::numeric_limits::max(); - m_derivation = {}; - m_ephPublicKey = {}; - return true; } -bool Wallet::get_eph_public_key(const hash& txkey_sec, size_t output_index, hash& eph_public_key) +bool Wallet::get_eph_public_key(const hash& txkey_sec, size_t output_index, hash& eph_public_key) const { - MutexLock lock(m_lock); - hash derivation; - bool derivation_changed = false; - - if (txkey_sec == m_txkeySec) { - derivation = m_derivation; - } - else { - if (!generate_key_derivation(m_viewPublicKey, txkey_sec, derivation)) { - return false; - } - m_derivation = derivation; - m_txkeySec = txkey_sec; - derivation_changed = true; + if (!generate_key_derivation(m_viewPublicKey, txkey_sec, derivation)) { + return false; } - if (!derivation_changed && (output_index == m_outputIndex)) { - eph_public_key = m_ephPublicKey; - } - else { - if (!derive_public_key(derivation, output_index, m_spendPublicKey, eph_public_key)) { - return false; - } - m_outputIndex = output_index; - m_ephPublicKey = eph_public_key; + if (!derive_public_key(derivation, output_index, m_spendPublicKey, eph_public_key)) { + return false; } return true; diff --git a/src/wallet.h b/src/wallet.h index 856e860..822e737 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -39,7 +39,7 @@ public: FORCEINLINE const hash& spend_public_key() const { return m_spendPublicKey; } FORCEINLINE const hash& view_public_key() const { return m_viewPublicKey; } - bool get_eph_public_key(const hash& txkey_sec, size_t output_index, hash& eph_public_key); + bool get_eph_public_key(const hash& txkey_sec, size_t output_index, hash& eph_public_key) const; FORCEINLINE bool operator<(const Wallet& w) const { return m_spendPublicKey < w.m_spendPublicKey; } FORCEINLINE bool operator==(const Wallet& w) const { return m_spendPublicKey == w.m_spendPublicKey; } @@ -50,12 +50,6 @@ private: hash m_viewPublicKey; uint32_t m_checksum; NetworkType m_type; - - mutable uv_mutex_t m_lock; - hash m_txkeySec; - size_t m_outputIndex; - hash m_derivation; - hash m_ephPublicKey; }; } // namespace p2pool