242 lines
9.1 KiB
C++
242 lines
9.1 KiB
C++
/* XMRig
|
|
* Copyright (c) 2012-2013 The Cryptonote developers
|
|
* Copyright (c) 2014-2021 The Monero Project
|
|
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
|
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "base/tools/cryptonote/WalletAddress.h"
|
|
#include "3rdparty/rapidjson/document.h"
|
|
#include "base/crypto/keccak.h"
|
|
#include "base/tools/Buffer.h"
|
|
#include "base/tools/cryptonote/BlobReader.h"
|
|
#include "base/tools/cryptonote/umul128.h"
|
|
#include "base/tools/Cvt.h"
|
|
|
|
|
|
#include <array>
|
|
#include <map>
|
|
|
|
|
|
bool xmrig::WalletAddress::decode(const char *address, size_t size)
|
|
{
|
|
static constexpr std::array<int, 9> block_sizes{ 0, 2, 3, 5, 6, 7, 9, 10, 11 };
|
|
static constexpr char alphabet[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
constexpr size_t alphabet_size = sizeof(alphabet) - 1;
|
|
|
|
if (size < kMinSize || size > kMaxSize) {
|
|
return false;
|
|
}
|
|
|
|
int8_t reverse_alphabet[256];
|
|
memset(reverse_alphabet, -1, sizeof(reverse_alphabet));
|
|
|
|
for (size_t i = 0; i < alphabet_size; ++i) {
|
|
reverse_alphabet[static_cast<int>(alphabet[i])] = i;
|
|
}
|
|
|
|
const int len = static_cast<int>(size);
|
|
const int num_full_blocks = len / block_sizes.back();
|
|
const int last_block_size = len % block_sizes.back();
|
|
|
|
int last_block_size_index = -1;
|
|
|
|
for (size_t i = 0; i < block_sizes.size(); ++i) {
|
|
if (block_sizes[i] == last_block_size) {
|
|
last_block_size_index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (last_block_size_index < 0) {
|
|
return false;
|
|
}
|
|
|
|
const size_t data_size = static_cast<size_t>(num_full_blocks) * sizeof(uint64_t) + last_block_size_index;
|
|
if (data_size < kMinDataSize) {
|
|
return false;
|
|
}
|
|
|
|
Buffer data;
|
|
data.reserve(data_size);
|
|
|
|
const char *address_data = address;
|
|
|
|
for (int i = 0; i <= num_full_blocks; ++i) {
|
|
uint64_t num = 0;
|
|
uint64_t order = 1;
|
|
|
|
for (int j = ((i < num_full_blocks) ? block_sizes.back() : last_block_size) - 1; j >= 0; --j) {
|
|
const int digit = reverse_alphabet[static_cast<int>(address_data[j])];
|
|
if (digit < 0) {
|
|
return false;
|
|
}
|
|
|
|
uint64_t hi;
|
|
const uint64_t tmp = num + __umul128(order, static_cast<uint64_t>(digit), &hi);
|
|
if ((tmp < num) || hi) {
|
|
return false;
|
|
}
|
|
|
|
num = tmp;
|
|
order *= alphabet_size;
|
|
}
|
|
|
|
address_data += block_sizes.back();
|
|
|
|
auto p = reinterpret_cast<const uint8_t*>(&num);
|
|
for (int j = ((i < num_full_blocks) ? static_cast<int>(sizeof(num)) : last_block_size_index) - 1; j >= 0; --j) {
|
|
data.emplace_back(p[j]);
|
|
}
|
|
}
|
|
|
|
assert(data.size() == data_size);
|
|
|
|
BlobReader<false> ar(data.data(), data_size);
|
|
|
|
if (ar(m_tag) && ar(m_publicSpendKey) && ar(m_publicViewKey) && ar.skip(ar.remaining() - sizeof(m_checksum)) && ar(m_checksum)) {
|
|
uint8_t md[200];
|
|
keccak(data.data(), data_size - sizeof(m_checksum), md);
|
|
|
|
if (memcmp(m_checksum, md, sizeof(m_checksum)) == 0) {
|
|
m_data = { address, size };
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
m_tag = 0;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool xmrig::WalletAddress::decode(const rapidjson::Value &address)
|
|
{
|
|
return address.IsString() && decode(address.GetString(), address.GetStringLength());
|
|
}
|
|
|
|
|
|
const char *xmrig::WalletAddress::netName() const
|
|
{
|
|
static const std::array<const char *, 3> names = { "mainnet", "testnet", "stagenet" };
|
|
|
|
return names[net()];
|
|
}
|
|
|
|
|
|
const char *xmrig::WalletAddress::typeName() const
|
|
{
|
|
static const std::array<const char *, 3> names = { "public", "integrated", "subaddress" };
|
|
|
|
return names[type()];
|
|
}
|
|
|
|
|
|
rapidjson::Value xmrig::WalletAddress::toJSON(rapidjson::Document &doc) const
|
|
{
|
|
using namespace rapidjson;
|
|
|
|
return isValid() ? m_data.toJSON(doc) : Value(kNullType);
|
|
}
|
|
|
|
|
|
#ifdef XMRIG_FEATURE_API
|
|
rapidjson::Value xmrig::WalletAddress::toAPI(rapidjson::Document &doc) const
|
|
{
|
|
using namespace rapidjson;
|
|
|
|
if (!isValid()) {
|
|
return Value(kNullType);
|
|
}
|
|
|
|
auto &allocator = doc.GetAllocator();
|
|
Value out(kObjectType);
|
|
out.AddMember(StringRef(Coin::kField), coin().toJSON(), allocator);
|
|
out.AddMember("address", m_data.toJSON(doc), allocator);
|
|
out.AddMember("type", StringRef(typeName()), allocator);
|
|
out.AddMember("net", StringRef(netName()), allocator);
|
|
out.AddMember("rpc_port", rpcPort(), allocator);
|
|
out.AddMember("zmq_port", zmqPort(), allocator);
|
|
out.AddMember("tag", m_tag, allocator);
|
|
out.AddMember("view_key", Cvt::toHex(m_publicViewKey, kKeySize, doc), allocator);
|
|
out.AddMember("spend_key", Cvt::toHex(m_publicSpendKey, kKeySize, doc), allocator);
|
|
out.AddMember("checksum", Cvt::toHex(m_checksum, sizeof(m_checksum), doc), allocator);
|
|
|
|
return out;
|
|
}
|
|
#endif
|
|
|
|
|
|
const xmrig::WalletAddress::TagInfo &xmrig::WalletAddress::tagInfo(uint64_t tag)
|
|
{
|
|
static TagInfo dummy = { Coin::INVALID, MAINNET, PUBLIC, 0, 0 };
|
|
static const std::map<uint64_t, TagInfo> tags = {
|
|
{ 0x12, { Coin::MONERO, MAINNET, PUBLIC, 18081, 18082 } },
|
|
{ 0x13, { Coin::MONERO, MAINNET, INTEGRATED, 18081, 18082 } },
|
|
{ 0x2a, { Coin::MONERO, MAINNET, SUBADDRESS, 18081, 18082 } },
|
|
|
|
{ 0x35, { Coin::MONERO, TESTNET, PUBLIC, 28081, 28082 } },
|
|
{ 0x36, { Coin::MONERO, TESTNET, INTEGRATED, 28081, 28082 } },
|
|
{ 0x3f, { Coin::MONERO, TESTNET, SUBADDRESS, 28081, 28082 } },
|
|
|
|
{ 0x18, { Coin::MONERO, STAGENET, PUBLIC, 38081, 38082 } },
|
|
{ 0x19, { Coin::MONERO, STAGENET, INTEGRATED, 38081, 38082 } },
|
|
{ 0x24, { Coin::MONERO, STAGENET, SUBADDRESS, 38081, 38082 } },
|
|
|
|
{ 0x2bb39a, { Coin::SUMO, MAINNET, PUBLIC, 19734, 19735 } },
|
|
{ 0x29339a, { Coin::SUMO, MAINNET, INTEGRATED, 19734, 19735 } },
|
|
{ 0x8319a, { Coin::SUMO, MAINNET, SUBADDRESS, 19734, 19735 } },
|
|
|
|
{ 0x37751a, { Coin::SUMO, TESTNET, PUBLIC, 29734, 29735 } },
|
|
{ 0x34f51a, { Coin::SUMO, TESTNET, INTEGRATED, 29734, 29735 } },
|
|
{ 0x1d351a, { Coin::SUMO, TESTNET, SUBADDRESS, 29734, 29735 } },
|
|
|
|
{ 0x2cca, { Coin::ARQMA, MAINNET, PUBLIC, 19994, 19995 } },
|
|
{ 0x116bc7, { Coin::ARQMA, MAINNET, INTEGRATED, 19994, 19995 } },
|
|
{ 0x6847, { Coin::ARQMA, MAINNET, SUBADDRESS, 19994, 19995 } },
|
|
|
|
{ 0x53ca, { Coin::ARQMA, TESTNET, PUBLIC, 29994, 29995 } },
|
|
{ 0x504a, { Coin::ARQMA, TESTNET, INTEGRATED, 29994, 29995 } },
|
|
{ 0x524a, { Coin::ARQMA, TESTNET, SUBADDRESS, 29994, 29995 } },
|
|
|
|
{ 0x39ca, { Coin::ARQMA, STAGENET, PUBLIC, 39994, 39995 } },
|
|
{ 0x1742ca, { Coin::ARQMA, STAGENET, INTEGRATED, 39994, 39995 } },
|
|
{ 0x1d84ca, { Coin::ARQMA, STAGENET, SUBADDRESS, 39994, 39995 } },
|
|
|
|
{ 0xc8ed8, { Coin::DERO, MAINNET, PUBLIC, 20206, 0 } },
|
|
{ 0xa0ed8, { Coin::DERO, MAINNET, INTEGRATED, 20206, 0 } },
|
|
|
|
{ 0x6cf58, { Coin::DERO, TESTNET, PUBLIC, 30306, 0 } },
|
|
{ 0x44f58, { Coin::DERO, TESTNET, INTEGRATED, 30306, 0 } },
|
|
|
|
{ 0x1032, { Coin::WOWNERO, MAINNET, PUBLIC, 34568, 34569 } },
|
|
{ 0x1a9a, { Coin::WOWNERO, MAINNET, INTEGRATED, 34568, 34569 } },
|
|
{ 0x2fb0, { Coin::WOWNERO, MAINNET, SUBADDRESS, 34568, 34569 } },
|
|
|
|
{ 0x5a, { Coin::GRAFT, MAINNET, PUBLIC, 18981, 18982 } },
|
|
{ 0x5b, { Coin::GRAFT, MAINNET, INTEGRATED, 18981, 18982 } },
|
|
{ 0x66, { Coin::GRAFT, MAINNET, SUBADDRESS, 18981, 18982 } },
|
|
|
|
{ 0x54, { Coin::GRAFT, TESTNET, PUBLIC, 28881, 28882 } },
|
|
{ 0x55, { Coin::GRAFT, TESTNET, INTEGRATED, 28881, 28882 } },
|
|
{ 0x70, { Coin::GRAFT, TESTNET, SUBADDRESS, 28881, 28882 } },
|
|
};
|
|
|
|
const auto it = tags.find(tag);
|
|
|
|
return it == tags.end() ? dummy : it->second;
|
|
}
|