From e6d833c227484ff45e543ede512879930987329b Mon Sep 17 00:00:00 2001 From: SChernykh <sergey.v.chernykh@gmail.com> Date: Thu, 17 Jun 2021 22:35:33 +0200 Subject: [PATCH] Proxy miner signature support --- src/base/net/stratum/Client.cpp | 37 ++++++++- src/base/net/stratum/Client.h | 1 + src/base/net/stratum/DaemonClient.cpp | 53 ++++++------ src/base/net/stratum/Job.cpp | 91 ++++++++++++++++++++- src/base/net/stratum/Job.h | 33 ++++++-- src/base/tools/cryptonote/BlockTemplate.cpp | 13 ++- src/base/tools/cryptonote/BlockTemplate.h | 4 +- src/net/JobResult.h | 4 +- src/net/strategies/DonateStrategy.cpp | 2 +- 9 files changed, 185 insertions(+), 53 deletions(-) diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp index e4d1d53ae..039ff6930 100644 --- a/src/base/net/stratum/Client.cpp +++ b/src/base/net/stratum/Client.cpp @@ -53,6 +53,7 @@ #include "base/net/tools/NetBuffer.h" #include "base/tools/Chrono.h" #include "base/tools/Cvt.h" +#include "base/tools/cryptonote/BlobReader.h" #include "net/JobResult.h" @@ -83,7 +84,8 @@ static const char *states[] = { xmrig::Client::Client(int id, const char *agent, IClientListener *listener) : BaseClient(id, listener), m_agent(agent), - m_sendBuf(1024) + m_sendBuf(1024), + m_tempBuf(256) { m_reader.setListener(this); m_key = m_storage.add(this); @@ -198,11 +200,16 @@ int64_t xmrig::Client::submit(const JobResult &result) const char *nonce = result.nonce; const char *data = result.result; # else - char *nonce = m_sendBuf.data(); - char *data = m_sendBuf.data() + 16; + char *nonce = m_tempBuf.data(); + char *data = m_tempBuf.data() + 16; + char *signature = m_tempBuf.data() + 88; Cvt::toHex(nonce, sizeof(uint32_t) * 2 + 1, reinterpret_cast<const uint8_t *>(&result.nonce), sizeof(uint32_t)); Cvt::toHex(data, 65, result.result(), 32); + + if (result.minerSignature()) { + Cvt::toHex(signature, 129, result.minerSignature(), 64); + } # endif Document doc(kObjectType); @@ -214,6 +221,12 @@ int64_t xmrig::Client::submit(const JobResult &result) params.AddMember("nonce", StringRef(nonce), allocator); params.AddMember("result", StringRef(data), allocator); +# ifndef XMRIG_PROXY_PROJECT + if (result.minerSignature()) { + params.AddMember("sig", StringRef(signature), allocator); + } +# endif + if (has<EXT_ALGO>() && result.algorithm.isValid()) { params.AddMember("algo", StringRef(result.algorithm.shortName()), allocator); } @@ -427,6 +440,24 @@ bool xmrig::Client::parseJob(const rapidjson::Value ¶ms, int *code) return false; } +# ifndef XMRIG_PROXY_PROJECT + uint8_t signatureKeyBuf[32 * 2]; + if (Cvt::fromHex(signatureKeyBuf, sizeof(signatureKeyBuf), Json::getValue(params, "sig_key"))) { + job.setEphemeralKeys(signatureKeyBuf, signatureKeyBuf + 32); + + uint8_t major_version; + uint8_t minor_version; + uint64_t timestamp; + + CBlobReader ar(job.blob(), job.size()); + ar(major_version); + ar(minor_version); + ar(timestamp); + + job.setTimestamp(timestamp); + } +# endif + m_job.setClientId(m_rpcId); if (m_job != job) { diff --git a/src/base/net/stratum/Client.h b/src/base/net/stratum/Client.h index e6508c656..fdaac9f15 100644 --- a/src/base/net/stratum/Client.h +++ b/src/base/net/stratum/Client.h @@ -137,6 +137,7 @@ private: std::bitset<EXT_MAX> m_extensions; std::shared_ptr<DnsRequest> m_dns; std::vector<char> m_sendBuf; + std::vector<char> m_tempBuf; String m_rpcId; Tls *m_tls = nullptr; uint64_t m_expire = 0; diff --git a/src/base/net/stratum/DaemonClient.cpp b/src/base/net/stratum/DaemonClient.cpp index bb741b336..7b42f8f8b 100644 --- a/src/base/net/stratum/DaemonClient.cpp +++ b/src/base/net/stratum/DaemonClient.cpp @@ -102,17 +102,28 @@ int64_t xmrig::DaemonClient::submit(const JobResult &result) char *data = (m_apiVersion == API_DERO) ? m_blockhashingblob.data() : m_blocktemplateStr.data(); + const size_t sig_offset = m_job.nonceOffset() + m_job.nonceSize(); + # ifdef XMRIG_PROXY_PROJECT - memcpy(data + 78, result.nonce, 8); + + memcpy(data + m_job.nonceOffset() * 2, result.nonce, 8); + + if (m_blocktemplate.has_miner_signature && result.sig) { + memcpy(data + sig_offset * 2, result.sig, 64 * 2); + memcpy(data + m_blocktemplate.tx_pubkey_index * 2, result.sig_data, 32 * 2); + memcpy(data + m_blocktemplate.eph_public_key_index * 2, result.sig_data + 32 * 2, 32 * 2); + } + # else - Cvt::toHex(data + 78, 8, reinterpret_cast<const uint8_t *>(&result.nonce), 4); -# endif + + Cvt::toHex(data + m_job.nonceOffset() * 2, 8, reinterpret_cast<const uint8_t*>(&result.nonce), 4); if (m_blocktemplate.has_miner_signature) { - const size_t sig_offset = m_job.nonceOffset() + m_job.nonceSize(); Cvt::toHex(data + sig_offset * 2, 128, result.minerSignature(), 64); } +# endif + using namespace rapidjson; Document doc(kObjectType); @@ -295,6 +306,16 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code) return false; } +# ifdef XMRIG_PROXY_PROJECT + job.setSpendSecretKey(secret_spendkey); + job.setMinerTx( + m_blocktemplate.raw_blob.data() + m_blocktemplate.miner_tx_prefix_begin_index, + m_blocktemplate.raw_blob.data() + m_blocktemplate.miner_tx_prefix_end_index, + m_blocktemplate.eph_public_key_index - m_blocktemplate.miner_tx_prefix_begin_index, + m_blocktemplate.tx_pubkey_index - m_blocktemplate.miner_tx_prefix_begin_index, + m_blocktemplate.miner_tx_merkle_tree_branch + ); +# else uint8_t secret_viewkey[32]; derive_view_secret_key(secret_spendkey, secret_viewkey); @@ -306,29 +327,6 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code) } uint8_t derivation[32]; - -# ifdef XMRIG_PROXY_PROJECT - // Generate unique keys for miner transaction - // TODO: make it unique for each connection - { - uint8_t* eph_public_key = m_blocktemplate.raw_blob.data() + m_blocktemplate.eph_public_key_index; - uint8_t* txkey_pub = m_blocktemplate.raw_blob.data() + m_blocktemplate.tx_pubkey_index; - uint8_t txkey_sec[32]; - - generate_keys(txkey_pub, txkey_sec); - generate_key_derivation(public_viewkey, txkey_sec, derivation); - derive_public_key(derivation, 0, public_spendkey, eph_public_key); - - Cvt::toHex(blocktemplate.data() + m_blocktemplate.eph_public_key_index * 2, 64, eph_public_key, 32); - Cvt::toHex(blocktemplate.data() + m_blocktemplate.tx_pubkey_index * 2, 64, txkey_pub, 32); - - m_blocktemplate.UpdateMinerTxHash(); - m_blocktemplate.GenerateHashingBlob(); - - Cvt::toHex(m_blockhashingblob.data() + m_blocktemplate.miner_tx_prefix_begin_index * 2, 64, m_blocktemplate.root_hash, 32); - } -# endif - if (!generate_key_derivation(m_blocktemplate.raw_blob.data() + m_blocktemplate.tx_pubkey_index, secret_viewkey, derivation)) { LOG_ERR("Failed to generate key derivation for miner signature."); *code = 9; @@ -359,6 +357,7 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code) job.setEphemeralKeys(m_blocktemplate.raw_blob.data() + m_blocktemplate.eph_public_key_index, eph_secret_key); job.setTimestamp(m_blocktemplate.timestamp); +# endif } if (m_apiVersion == API_DERO) { diff --git a/src/base/net/stratum/Job.cpp b/src/base/net/stratum/Job.cpp index a8becb1a2..71d09a4ca 100644 --- a/src/base/net/stratum/Job.cpp +++ b/src/base/net/stratum/Job.cpp @@ -32,6 +32,7 @@ #include "base/net/stratum/Job.h" #include "base/tools/Buffer.h" #include "base/tools/Cvt.h" +#include "base/tools/cryptonote/BlockTemplate.h" #include "base/tools/cryptonote/Signatures.h" #include "base/crypto/keccak.h" @@ -172,12 +173,23 @@ void xmrig::Job::copy(const Job &other) m_benchSize = other.m_benchSize; # endif - m_hasMinerSignature = other.m_hasMinerSignature; - +# ifdef XMRIG_PROXY_PROJECT + memcpy(m_spendSecretKey, other.m_spendSecretKey, sizeof(m_spendSecretKey)); + memcpy(m_viewSecretKey, other.m_viewSecretKey, sizeof(m_viewSecretKey)); + memcpy(m_spendPublicKey, other.m_spendPublicKey, sizeof(m_spendPublicKey)); + memcpy(m_viewPublicKey, other.m_viewPublicKey, sizeof(m_viewPublicKey)); + m_minerTxPrefix = other.m_minerTxPrefix; + m_minerTxEphPubKeyOffset = other.m_minerTxEphPubKeyOffset; + m_minerTxPubKeyOffset = other.m_minerTxPubKeyOffset; + m_minerTxMerkleTreeBranch = other.m_minerTxMerkleTreeBranch; +# else memcpy(m_ephPublicKey, other.m_ephPublicKey, sizeof(m_ephPublicKey)); memcpy(m_ephSecretKey, other.m_ephSecretKey, sizeof(m_ephSecretKey)); m_timestamp = other.m_timestamp; +# endif + + m_hasMinerSignature = other.m_hasMinerSignature; } @@ -214,15 +226,83 @@ void xmrig::Job::move(Job &&other) m_benchSize = other.m_benchSize; # endif - m_hasMinerSignature = other.m_hasMinerSignature; - +# ifdef XMRIG_PROXY_PROJECT + memcpy(m_spendSecretKey, other.m_spendSecretKey, sizeof(m_spendSecretKey)); + memcpy(m_viewSecretKey, other.m_viewSecretKey, sizeof(m_viewSecretKey)); + memcpy(m_spendPublicKey, other.m_spendPublicKey, sizeof(m_spendPublicKey)); + memcpy(m_viewPublicKey, other.m_viewPublicKey, sizeof(m_viewPublicKey)); + m_minerTxPrefix = std::move(other.m_minerTxPrefix); + m_minerTxEphPubKeyOffset = other.m_minerTxEphPubKeyOffset; + m_minerTxPubKeyOffset = other.m_minerTxPubKeyOffset; + m_minerTxMerkleTreeBranch = std::move(other.m_minerTxMerkleTreeBranch); +# else memcpy(m_ephPublicKey, other.m_ephPublicKey, sizeof(m_ephPublicKey)); memcpy(m_ephSecretKey, other.m_ephSecretKey, sizeof(m_ephSecretKey)); m_timestamp = other.m_timestamp; +# endif + + m_hasMinerSignature = other.m_hasMinerSignature; } +#ifdef XMRIG_PROXY_PROJECT + + +void xmrig::Job::setSpendSecretKey(uint8_t* key) +{ + m_hasMinerSignature = true; + memcpy(m_spendSecretKey, key, sizeof(m_spendSecretKey)); + xmrig::derive_view_secret_key(m_spendSecretKey, m_viewSecretKey); + xmrig::secret_key_to_public_key(m_spendSecretKey, m_spendPublicKey); + xmrig::secret_key_to_public_key(m_viewSecretKey, m_viewPublicKey); +} + + +void xmrig::Job::setMinerTx(const uint8_t* begin, const uint8_t* end, size_t minerTxEphPubKeyOffset, size_t minerTxPubKeyOffset, const Buffer& minerTxMerkleTreeBranch) +{ + m_minerTxPrefix.assign(begin, end); + m_minerTxEphPubKeyOffset = minerTxEphPubKeyOffset; + m_minerTxPubKeyOffset = minerTxPubKeyOffset; + m_minerTxMerkleTreeBranch = minerTxMerkleTreeBranch; +} + + +void xmrig::Job::generateHashingBlob(String& blob, String& signatureData) const +{ + uint8_t* eph_public_key = m_minerTxPrefix.data() + m_minerTxEphPubKeyOffset; + uint8_t* txkey_pub = m_minerTxPrefix.data() + m_minerTxPubKeyOffset; + + uint8_t txkey_sec[32]; + + generate_keys(txkey_pub, txkey_sec); + + uint8_t derivation[32]; + + generate_key_derivation(m_viewPublicKey, txkey_sec, derivation); + derive_public_key(derivation, 0, m_spendPublicKey, eph_public_key); + + uint8_t buf[32 * 3] = {}; + memcpy(buf, txkey_pub, 32); + memcpy(buf + 32, eph_public_key, 32); + + generate_key_derivation(txkey_pub, m_viewSecretKey, derivation); + derive_secret_key(derivation, 0, m_spendSecretKey, buf + 64); + + signatureData = xmrig::Cvt::toHex(buf, sizeof(buf)); + + uint8_t root_hash[32]; + const uint8_t* p = m_minerTxPrefix.data(); + xmrig::BlockTemplate::CalculateRootHash(p, p + m_minerTxPrefix.size(), m_minerTxMerkleTreeBranch, root_hash); + + blob = rawBlob(); + xmrig::Cvt::toHex(blob.data() + (nonceOffset() + nonceSize() + 64) * 2, 64, root_hash, 32); +} + + +#else + + void xmrig::Job::generateMinerSignature(uint64_t data, uint8_t* sig) const { uint8_t sig_data[32]; @@ -237,3 +317,6 @@ void xmrig::Job::generateMinerSignature(uint64_t data, uint8_t* sig) const xmrig::generate_signature(prefix_hash, m_ephPublicKey, m_ephSecretKey, sig); } + + +#endif diff --git a/src/base/net/stratum/Job.h b/src/base/net/stratum/Job.h index 047e9b150..701534ea5 100644 --- a/src/base/net/stratum/Job.h +++ b/src/base/net/stratum/Job.h @@ -82,7 +82,7 @@ public: inline uint32_t backend() const { return m_backend; } inline uint64_t diff() const { return m_diff; } inline uint64_t height() const { return m_height; } - inline uint64_t nonceMask() const { return isNicehash() ? 0xFFFFFFULL : (nonceSize() == sizeof(uint64_t) ? (-1ULL >> (extraNonce().size() * 4)): 0xFFFFFFFFULL); } + inline uint64_t nonceMask() const { return isNicehash() ? 0xFFFFFFULL : (nonceSize() == sizeof(uint64_t) ? (static_cast<uint64_t>(-1LL) >> (extraNonce().size() * 4)) : 0xFFFFFFFFULL); } inline uint64_t target() const { return m_target; } inline uint8_t *blob() { return m_blob; } inline uint8_t fixedByte() const { return *(m_blob + 42); } @@ -116,6 +116,11 @@ public: inline void setBenchSize(uint32_t size) { m_benchSize = size; } # endif +# ifdef XMRIG_PROXY_PROJECT + void setSpendSecretKey(uint8_t* key); + void setMinerTx(const uint8_t* begin, const uint8_t* end, size_t minerTxEphPubKeyOffset, size_t minerTxPubKeyOffset, const Buffer& minerTxMerkleTreeBranch); + void generateHashingBlob(String& blob, String& signatureData) const; +# else inline const uint8_t* ephSecretKey() const { return m_hasMinerSignature ? m_ephSecretKey : nullptr; } inline uint64_t timestamp() const { return m_timestamp; } @@ -128,8 +133,10 @@ public: inline void setTimestamp(uint64_t timestamp) { m_timestamp = timestamp; } - inline bool hasMinerSignature() const { return m_hasMinerSignature; } void generateMinerSignature(uint64_t data, uint8_t* sig) const; +# endif + + inline bool hasMinerSignature() const { return m_hasMinerSignature; } private: void copy(const Job &other); @@ -154,16 +161,28 @@ private: char m_rawBlob[kMaxBlobSize * 2 + 8]{}; char m_rawTarget[24]{}; String m_rawSeedHash; + + // Miner signatures + uint8_t m_spendSecretKey[32]; + uint8_t m_viewSecretKey[32]; + uint8_t m_spendPublicKey[32]; + uint8_t m_viewPublicKey[32]; + mutable Buffer m_minerTxPrefix; + size_t m_minerTxEphPubKeyOffset = 0; + size_t m_minerTxPubKeyOffset = 0; + Buffer m_minerTxMerkleTreeBranch; +# else + // Miner signatures + uint8_t m_ephPublicKey[32]{}; + uint8_t m_ephSecretKey[32]{}; + uint64_t m_timestamp = 0; # endif + bool m_hasMinerSignature = false; + # ifdef XMRIG_FEATURE_BENCHMARK uint32_t m_benchSize = 0; # endif - - bool m_hasMinerSignature = false; - uint8_t m_ephPublicKey[32]{}; - uint8_t m_ephSecretKey[32]{}; - uint64_t m_timestamp = 0; }; diff --git a/src/base/tools/cryptonote/BlockTemplate.cpp b/src/base/tools/cryptonote/BlockTemplate.cpp index 39bc8b819..f84a668b8 100644 --- a/src/base/tools/cryptonote/BlockTemplate.cpp +++ b/src/base/tools/cryptonote/BlockTemplate.cpp @@ -115,7 +115,7 @@ bool BlockTemplate::Init(const String& blockTemplate, Coin coin) # ifdef XMRIG_PROXY_PROJECT hashes.resize((num_hashes + 1) * HASH_SIZE); - CalculateMinerTxHash(hashes.data()); + CalculateMinerTxHash(raw_blob.data() + miner_tx_prefix_begin_index, raw_blob.data() + miner_tx_prefix_end_index, hashes.data()); for (uint64_t i = 1; i <= num_hashes; ++i) { uint8_t h[HASH_SIZE]; @@ -124,21 +124,20 @@ bool BlockTemplate::Init(const String& blockTemplate, Coin coin) } CalculateMerkleTreeHash(); - GenerateHashingBlob(); # endif return true; } -void BlockTemplate::CalculateMinerTxHash(uint8_t* hash) +void BlockTemplate::CalculateMinerTxHash(const uint8_t* prefix_begin, const uint8_t* prefix_end, uint8_t* hash) { uint8_t hashes[HASH_SIZE * 3]; // Calculate 3 partial hashes // 1. Prefix - keccak(raw_blob.data() + miner_tx_prefix_begin_index, static_cast<int>(miner_tx_prefix_end_index - miner_tx_prefix_begin_index), hashes, HASH_SIZE); + keccak(prefix_begin, static_cast<int>(prefix_end - prefix_begin), hashes, HASH_SIZE); // 2. Base RCT, single 0 byte in miner tx static const uint8_t known_second_hash[HASH_SIZE] = { @@ -203,11 +202,9 @@ void BlockTemplate::CalculateMerkleTreeHash() } -void BlockTemplate::UpdateMinerTxHash() +void BlockTemplate::CalculateRootHash(const uint8_t* prefix_begin, const uint8_t* prefix_end, const Buffer& miner_tx_merkle_tree_branch, uint8_t* root_hash) { - CalculateMinerTxHash(hashes.data()); - - memcpy(root_hash, hashes.data(), HASH_SIZE); + CalculateMinerTxHash(prefix_begin, prefix_end, root_hash); for (size_t i = 0; i < miner_tx_merkle_tree_branch.size(); i += HASH_SIZE) { uint8_t h[HASH_SIZE * 2]; diff --git a/src/base/tools/cryptonote/BlockTemplate.h b/src/base/tools/cryptonote/BlockTemplate.h index 079cc021b..8c3e67616 100644 --- a/src/base/tools/cryptonote/BlockTemplate.h +++ b/src/base/tools/cryptonote/BlockTemplate.h @@ -80,9 +80,9 @@ struct BlockTemplate bool Init(const String& blockTemplate, Coin coin); - void CalculateMinerTxHash(uint8_t* hash); + static void CalculateMinerTxHash(const uint8_t* prefix_begin, const uint8_t* prefix_end, uint8_t* hash); + static void CalculateRootHash(const uint8_t* prefix_begin, const uint8_t* prefix_end, const Buffer& miner_tx_merkle_tree_branch, uint8_t* root_hash); void CalculateMerkleTreeHash(); - void UpdateMinerTxHash(); void GenerateHashingBlob(); }; diff --git a/src/net/JobResult.h b/src/net/JobResult.h index 22fbb3118..614baf14a 100644 --- a/src/net/JobResult.h +++ b/src/net/JobResult.h @@ -63,6 +63,7 @@ public: } if (miner_signature) { + m_hasMinerSignature = true; memcpy(m_minerSignature, miner_signature, sizeof(m_minerSignature)); } } @@ -84,7 +85,7 @@ public: inline const uint8_t *headerHash() const { return m_headerHash; } inline const uint8_t *mixHash() const { return m_mixHash; } - inline const uint8_t *minerSignature() const { return m_minerSignature; } + inline const uint8_t *minerSignature() const { return m_hasMinerSignature ? m_minerSignature : nullptr; } const Algorithm algorithm; const String clientId; @@ -100,6 +101,7 @@ private: uint8_t m_mixHash[32] = { 0 }; uint8_t m_minerSignature[64] = { 0 }; + bool m_hasMinerSignature = false; }; diff --git a/src/net/strategies/DonateStrategy.cpp b/src/net/strategies/DonateStrategy.cpp index a8ecf851a..b288046e4 100644 --- a/src/net/strategies/DonateStrategy.cpp +++ b/src/net/strategies/DonateStrategy.cpp @@ -259,7 +259,7 @@ xmrig::IClient *xmrig::DonateStrategy::createProxy() const IClient *client = strategy->client(); m_tls = client->hasExtension(IClient::EXT_TLS); - Pool pool(client->pool().proxy().isValid() ? client->pool().host() : client->ip(), client->pool().port(), m_userId, client->pool().password(), nullptr, 0, true, client->isTLS(), Pool::MODE_POOL); + Pool pool(client->pool().proxy().isValid() ? client->pool().host() : client->ip(), client->pool().port(), m_userId, client->pool().password(), client->pool().spendSecretKey(), 0, true, client->isTLS(), Pool::MODE_POOL); pool.setAlgo(client->pool().algorithm()); pool.setProxy(client->pool().proxy());