mirror of
https://github.com/SChernykh/p2pool.git
synced 2024-12-23 11:59:31 +00:00
Crypto: added cache for faster key derivation
This commit is contained in:
parent
ba6a2c8eb2
commit
b35b4a9f76
6 changed files with 124 additions and 90 deletions
|
@ -47,6 +47,7 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
108
src/crypto.cpp
108
src/crypto.cpp
|
@ -20,6 +20,7 @@
|
||||||
#include "keccak.h"
|
#include "keccak.h"
|
||||||
#include "uv_util.h"
|
#include "uv_util.h"
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "crypto-ops.h"
|
#include "crypto-ops.h"
|
||||||
|
@ -108,24 +109,6 @@ bool check_keys(const hash& pub, const hash& sec)
|
||||||
return pub == pub_check;
|
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<uint8_t*>(&derivation), &point2);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static FORCEINLINE void hash_to_scalar(const uint8_t* data, size_t length, uint8_t(&res)[HASH_SIZE])
|
static FORCEINLINE void hash_to_scalar(const uint8_t* data, size_t length, uint8_t(&res)[HASH_SIZE])
|
||||||
{
|
{
|
||||||
keccak(data, static_cast<int>(length), res, HASH_SIZE);
|
keccak(data, static_cast<int>(length), res, HASH_SIZE);
|
||||||
|
@ -153,9 +136,71 @@ static FORCEINLINE void derivation_to_scalar(const hash& derivation, size_t outp
|
||||||
hash_to_scalar(begin, end - begin, res);
|
hash_to_scalar(begin, end - begin, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
// cppcheck-suppress constParameter
|
class Cache
|
||||||
bool derive_public_key(const hash& derivation, size_t output_index, const hash& base, hash& derived_key)
|
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
Cache()
|
||||||
|
{
|
||||||
|
uv_mutex_init_checked(&m);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Cache()
|
||||||
|
{
|
||||||
|
uv_mutex_destroy(&m);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_derivation(const hash& key1, const hash& key2, hash& derivation)
|
||||||
|
{
|
||||||
|
std::array<uint8_t, HASH_SIZE * 2> 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<uint8_t*>(&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<uint8_t, HASH_SIZE * 2 + sizeof(size_t)> 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];
|
uint8_t scalar[HASH_SIZE];
|
||||||
ge_p3 point1;
|
ge_p3 point1;
|
||||||
ge_p3 point2;
|
ge_p3 point2;
|
||||||
|
@ -174,7 +219,30 @@ bool derive_public_key(const hash& derivation, size_t output_index, const hash&
|
||||||
ge_p1p1_to_p2(&point5, &point4);
|
ge_p1p1_to_p2(&point5, &point4);
|
||||||
ge_tobytes(derived_key.h, &point5);
|
ge_tobytes(derived_key.h, &point5);
|
||||||
|
|
||||||
|
{
|
||||||
|
MutexLock lock(m);
|
||||||
|
public_keys.emplace(index, derived_key);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uv_mutex_t m;
|
||||||
|
std::unordered_map<std::array<uint8_t, HASH_SIZE * 2>, hash> derivations;
|
||||||
|
std::unordered_map<std::array<uint8_t, HASH_SIZE * 2 + sizeof(size_t)>, 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
|
} // namespace p2pool
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <array>
|
|
||||||
|
|
||||||
// Only uncomment it to debug issues with uncle/orphan blocks
|
// Only uncomment it to debug issues with uncle/orphan blocks
|
||||||
//#define DEBUG_BROADCAST_DELAY_MS 100
|
//#define DEBUG_BROADCAST_DELAY_MS 100
|
||||||
|
|
13
src/util.h
13
src/util.h
|
@ -136,4 +136,17 @@ struct hash<p2pool::hash>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
struct hash<std::array<uint8_t, N>>
|
||||||
|
{
|
||||||
|
FORCEINLINE size_t operator()(const std::array<uint8_t, N>& value) const
|
||||||
|
{
|
||||||
|
uint64_t result = 0xcbf29ce484222325ull;
|
||||||
|
for (size_t i = 0; i < N; ++i) {
|
||||||
|
result = (result ^ value[i]) * 0x100000001b3ull;
|
||||||
|
}
|
||||||
|
return static_cast<size_t>(result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
#include "wallet.h"
|
#include "wallet.h"
|
||||||
#include "keccak.h"
|
#include "keccak.h"
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
#include <array>
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "crypto-ops.h"
|
#include "crypto-ops.h"
|
||||||
|
@ -81,23 +80,16 @@ static_assert(rev_alphabet.num_symbols == 58, "Check alphabet");
|
||||||
namespace p2pool {
|
namespace p2pool {
|
||||||
|
|
||||||
Wallet::Wallet(const char* address)
|
Wallet::Wallet(const char* address)
|
||||||
: m_txkeySec{}
|
|
||||||
, m_outputIndex(std::numeric_limits<size_t>::max())
|
|
||||||
, m_derivation{}
|
|
||||||
, m_ephPublicKey{}
|
|
||||||
{
|
{
|
||||||
uv_mutex_init_checked(&m_lock);
|
|
||||||
decode(address);
|
decode(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
Wallet::~Wallet()
|
Wallet::~Wallet()
|
||||||
{
|
{
|
||||||
uv_mutex_destroy(&m_lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Wallet::Wallet(const Wallet& w)
|
Wallet::Wallet(const Wallet& w)
|
||||||
{
|
{
|
||||||
uv_mutex_init_checked(&m_lock);
|
|
||||||
operator=(w);
|
operator=(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,18 +100,11 @@ Wallet& Wallet::operator=(const Wallet& w)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
MutexLock lock(m_lock);
|
|
||||||
MutexLock lock2(w.m_lock);
|
|
||||||
|
|
||||||
m_prefix = w.m_prefix;
|
m_prefix = w.m_prefix;
|
||||||
m_spendPublicKey = w.m_spendPublicKey;
|
m_spendPublicKey = w.m_spendPublicKey;
|
||||||
m_viewPublicKey = w.m_viewPublicKey;
|
m_viewPublicKey = w.m_viewPublicKey;
|
||||||
m_checksum = w.m_checksum;
|
m_checksum = w.m_checksum;
|
||||||
m_type = w.m_type;
|
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;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -204,8 +189,6 @@ bool Wallet::assign(const hash& spend_pub_key, const hash& view_pub_key, Network
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MutexLock lock(m_lock);
|
|
||||||
|
|
||||||
m_prefix = 0;
|
m_prefix = 0;
|
||||||
m_spendPublicKey = spend_pub_key;
|
m_spendPublicKey = spend_pub_key;
|
||||||
m_viewPublicKey = view_pub_key;
|
m_viewPublicKey = view_pub_key;
|
||||||
|
@ -213,43 +196,19 @@ bool Wallet::assign(const hash& spend_pub_key, const hash& view_pub_key, Network
|
||||||
|
|
||||||
m_type = type;
|
m_type = type;
|
||||||
|
|
||||||
m_txkeySec = {};
|
|
||||||
m_outputIndex = std::numeric_limits<size_t>::max();
|
|
||||||
m_derivation = {};
|
|
||||||
m_ephPublicKey = {};
|
|
||||||
|
|
||||||
return true;
|
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;
|
hash derivation;
|
||||||
bool derivation_changed = false;
|
|
||||||
|
|
||||||
if (txkey_sec == m_txkeySec) {
|
|
||||||
derivation = m_derivation;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!generate_key_derivation(m_viewPublicKey, txkey_sec, derivation)) {
|
if (!generate_key_derivation(m_viewPublicKey, txkey_sec, derivation)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_derivation = derivation;
|
|
||||||
m_txkeySec = txkey_sec;
|
|
||||||
derivation_changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)) {
|
if (!derive_public_key(derivation, output_index, m_spendPublicKey, eph_public_key)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_outputIndex = output_index;
|
|
||||||
m_ephPublicKey = eph_public_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
FORCEINLINE const hash& spend_public_key() const { return m_spendPublicKey; }
|
FORCEINLINE const hash& spend_public_key() const { return m_spendPublicKey; }
|
||||||
FORCEINLINE const hash& view_public_key() const { return m_viewPublicKey; }
|
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; }
|
||||||
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;
|
hash m_viewPublicKey;
|
||||||
uint32_t m_checksum;
|
uint32_t m_checksum;
|
||||||
NetworkType m_type;
|
NetworkType m_type;
|
||||||
|
|
||||||
mutable uv_mutex_t m_lock;
|
|
||||||
hash m_txkeySec;
|
|
||||||
size_t m_outputIndex;
|
|
||||||
hash m_derivation;
|
|
||||||
hash m_ephPublicKey;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace p2pool
|
} // namespace p2pool
|
||||||
|
|
Loading…
Reference in a new issue