Browse Source

Proxy miner signature support

pull/2445/head
SChernykh 3 years ago
parent
commit
e6d833c227
  1. 37
      src/base/net/stratum/Client.cpp
  2. 1
      src/base/net/stratum/Client.h
  3. 53
      src/base/net/stratum/DaemonClient.cpp
  4. 91
      src/base/net/stratum/Job.cpp
  5. 33
      src/base/net/stratum/Job.h
  6. 13
      src/base/tools/cryptonote/BlockTemplate.cpp
  7. 4
      src/base/tools/cryptonote/BlockTemplate.h
  8. 4
      src/net/JobResult.h
  9. 2
      src/net/strategies/DonateStrategy.cpp

37
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 &params, 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) {

1
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;

53
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 &params, 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 &params, 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 &params, 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) {

91
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

33
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;
};

13
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];

4
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();
};

4
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;
};

2
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());

Loading…
Cancel
Save