diff --git a/src/base/net/stratum/DaemonClient.cpp b/src/base/net/stratum/DaemonClient.cpp index 4e311abf..9b1cdc42 100644 --- a/src/base/net/stratum/DaemonClient.cpp +++ b/src/base/net/stratum/DaemonClient.cpp @@ -148,6 +148,11 @@ int64_t xmrig::DaemonClient::submit(const JobResult &result) memcpy(data + sig_offset * 2, result.sig, 64 * 2); memcpy(data + m_blocktemplate.offset(BlockTemplate::TX_PUBKEY_OFFSET) * 2, result.sig_data, 32 * 2); memcpy(data + m_blocktemplate.offset(BlockTemplate::EPH_PUBLIC_KEY_OFFSET) * 2, result.sig_data + 32 * 2, 32 * 2); + + // Handle view tag for txout_to_tagged_key outputs + if (m_blocktemplate.outputType() == 3) { + Cvt::toHex(data + m_blocktemplate.offset(BlockTemplate::EPH_PUBLIC_KEY_OFFSET) * 2 + 32 * 2, 2, &result.view_tag, 1); + } } if (result.extra_nonce >= 0) { @@ -404,7 +409,8 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code) m_blocktemplate.offset(BlockTemplate::TX_PUBKEY_OFFSET) - k, m_blocktemplate.offset(BlockTemplate::TX_EXTRA_NONCE_OFFSET) - k, m_blocktemplate.txExtraNonce().size(), - m_blocktemplate.minerTxMerkleTreeBranch() + m_blocktemplate.minerTxMerkleTreeBranch(), + m_blocktemplate.outputType() == 3 ); # endif @@ -441,7 +447,7 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code) } uint8_t derivation[32]; - if (!generate_key_derivation(m_blocktemplate.blob(BlockTemplate::TX_PUBKEY_OFFSET), secret_viewkey, derivation)) { + if (!generate_key_derivation(m_blocktemplate.blob(BlockTemplate::TX_PUBKEY_OFFSET), secret_viewkey, derivation, nullptr)) { return jobError("Failed to generate key derivation for miner signature."); } diff --git a/src/base/net/stratum/Job.cpp b/src/base/net/stratum/Job.cpp index 56f5de80..d62e00b1 100644 --- a/src/base/net/stratum/Job.cpp +++ b/src/base/net/stratum/Job.cpp @@ -245,6 +245,7 @@ void xmrig::Job::copy(const Job &other) m_minerTxExtraNonceOffset = other.m_minerTxExtraNonceOffset; m_minerTxExtraNonceSize = other.m_minerTxExtraNonceSize; m_minerTxMerkleTreeBranch = other.m_minerTxMerkleTreeBranch; + m_hasViewTag = other.m_hasViewTag; # else memcpy(m_ephPublicKey, other.m_ephPublicKey, sizeof(m_ephPublicKey)); memcpy(m_ephSecretKey, other.m_ephSecretKey, sizeof(m_ephSecretKey)); @@ -300,6 +301,7 @@ void xmrig::Job::move(Job &&other) m_minerTxExtraNonceOffset = other.m_minerTxExtraNonceOffset; m_minerTxExtraNonceSize = other.m_minerTxExtraNonceSize; m_minerTxMerkleTreeBranch = std::move(other.m_minerTxMerkleTreeBranch); + m_hasViewTag = other.m_hasViewTag; # else memcpy(m_ephPublicKey, other.m_ephPublicKey, sizeof(m_ephPublicKey)); memcpy(m_ephSecretKey, other.m_ephSecretKey, sizeof(m_ephSecretKey)); @@ -323,7 +325,7 @@ void xmrig::Job::setSpendSecretKey(const uint8_t *key) } -void xmrig::Job::setMinerTx(const uint8_t *begin, const uint8_t *end, size_t minerTxEphPubKeyOffset, size_t minerTxPubKeyOffset, size_t minerTxExtraNonceOffset, size_t minerTxExtraNonceSize, const Buffer &minerTxMerkleTreeBranch) +void xmrig::Job::setMinerTx(const uint8_t *begin, const uint8_t *end, size_t minerTxEphPubKeyOffset, size_t minerTxPubKeyOffset, size_t minerTxExtraNonceOffset, size_t minerTxExtraNonceSize, const Buffer &minerTxMerkleTreeBranch, bool hasViewTag) { m_minerTxPrefix.assign(begin, end); m_minerTxEphPubKeyOffset = minerTxEphPubKeyOffset; @@ -331,6 +333,13 @@ void xmrig::Job::setMinerTx(const uint8_t *begin, const uint8_t *end, size_t min m_minerTxExtraNonceOffset = minerTxExtraNonceOffset; m_minerTxExtraNonceSize = minerTxExtraNonceSize; m_minerTxMerkleTreeBranch = minerTxMerkleTreeBranch; + m_hasViewTag = hasViewTag; +} + + +void xmrig::Job::setViewTagInMinerTx(uint8_t view_tag) +{ + memcpy(m_minerTxPrefix.data() + m_minerTxEphPubKeyOffset + 32, &view_tag, 1); } @@ -340,7 +349,7 @@ void xmrig::Job::setExtraNonceInMinerTx(uint32_t extra_nonce) } -void xmrig::Job::generateSignatureData(String &signatureData) const +void xmrig::Job::generateSignatureData(String &signatureData, uint8_t& view_tag) const { uint8_t* eph_public_key = m_minerTxPrefix.data() + m_minerTxEphPubKeyOffset; uint8_t* txkey_pub = m_minerTxPrefix.data() + m_minerTxPubKeyOffset; @@ -351,14 +360,14 @@ void xmrig::Job::generateSignatureData(String &signatureData) const uint8_t derivation[32]; - generate_key_derivation(m_viewPublicKey, txkey_sec, derivation); + generate_key_derivation(m_viewPublicKey, txkey_sec, derivation, &view_tag); 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); + generate_key_derivation(txkey_pub, m_viewSecretKey, derivation, nullptr); derive_secret_key(derivation, 0, m_spendSecretKey, buf + 64); signatureData = Cvt::toHex(buf, sizeof(buf)); diff --git a/src/base/net/stratum/Job.h b/src/base/net/stratum/Job.h index e314a266..1ecff369 100644 --- a/src/base/net/stratum/Job.h +++ b/src/base/net/stratum/Job.h @@ -120,10 +120,13 @@ public: # endif # ifdef XMRIG_PROXY_PROJECT + inline bool hasViewTag() const { return m_hasViewTag; } + void setSpendSecretKey(const uint8_t* key); - void setMinerTx(const uint8_t* begin, const uint8_t* end, size_t minerTxEphPubKeyOffset, size_t minerTxPubKeyOffset, size_t minerTxExtraNonceOffset, size_t minerTxExtraNonceSize, const Buffer& minerTxMerkleTreeBranch); + void setMinerTx(const uint8_t* begin, const uint8_t* end, size_t minerTxEphPubKeyOffset, size_t minerTxPubKeyOffset, size_t minerTxExtraNonceOffset, size_t minerTxExtraNonceSize, const Buffer& minerTxMerkleTreeBranch, bool hasViewTag); + void setViewTagInMinerTx(uint8_t view_tag); void setExtraNonceInMinerTx(uint32_t extra_nonce); - void generateSignatureData(String& signatureData) const; + void generateSignatureData(String& signatureData, uint8_t& view_tag) const; void generateHashingBlob(String& blob) const; # else inline const uint8_t* ephSecretKey() const { return m_hasMinerSignature ? m_ephSecretKey : nullptr; } @@ -178,6 +181,7 @@ private: size_t m_minerTxExtraNonceOffset = 0; size_t m_minerTxExtraNonceSize = 0; Buffer m_minerTxMerkleTreeBranch; + bool m_hasViewTag = false; # else // Miner signatures uint8_t m_ephPublicKey[32]{}; diff --git a/src/base/tools/cryptonote/Signatures.cpp b/src/base/tools/cryptonote/Signatures.cpp index 93571258..13f0c948 100644 --- a/src/base/tools/cryptonote/Signatures.cpp +++ b/src/base/tools/cryptonote/Signatures.cpp @@ -147,7 +147,7 @@ bool check_signature(const uint8_t* prefix_hash, const uint8_t* pub, const uint8 } -bool generate_key_derivation(const uint8_t* key1, const uint8_t* key2, uint8_t* derivation) +bool generate_key_derivation(const uint8_t* key1, const uint8_t* key2, uint8_t* derivation, uint8_t* view_tag) { ge_p3 point; ge_p2 point2; @@ -162,6 +162,22 @@ bool generate_key_derivation(const uint8_t* key1, const uint8_t* key2, uint8_t* ge_p1p1_to_p2(&point2, &point3); ge_tobytes(derivation, &point2); + if (view_tag) { + constexpr uint8_t salt[] = "view_tag"; + constexpr size_t SALT_SIZE = sizeof(salt) - 1; + + uint8_t buf[SALT_SIZE + 32 + 1]; + memcpy(buf, salt, SALT_SIZE); + memcpy(buf + SALT_SIZE, derivation, 32); + + // Assuming output_index == 0 + buf[SALT_SIZE + 32] = 0; + + uint8_t view_tag_full[32]; + xmrig::keccak(buf, sizeof(buf), view_tag_full, sizeof(view_tag_full)); + *view_tag = view_tag_full[0]; + } + return true; } diff --git a/src/base/tools/cryptonote/Signatures.h b/src/base/tools/cryptonote/Signatures.h index 04813313..24ea9ac6 100644 --- a/src/base/tools/cryptonote/Signatures.h +++ b/src/base/tools/cryptonote/Signatures.h @@ -31,7 +31,7 @@ namespace xmrig { void generate_signature(const uint8_t* prefix_hash, const uint8_t* pub, const uint8_t* sec, uint8_t* sig); bool check_signature(const uint8_t* prefix_hash, const uint8_t* pub, const uint8_t* sig); -bool generate_key_derivation(const uint8_t* key1, const uint8_t* key2, uint8_t* derivation); +bool generate_key_derivation(const uint8_t* key1, const uint8_t* key2, uint8_t* derivation, uint8_t* view_tag); void derive_secret_key(const uint8_t* derivation, size_t output_index, const uint8_t* base, uint8_t* derived_key); bool derive_public_key(const uint8_t* derivation, size_t output_index, const uint8_t* base, uint8_t* derived_key);