REDACTED-rig/src/base/tools/cryptonote/WalletAddress.cpp
2021-06-15 15:51:29 +02:00

114 lines
3.4 KiB
C++

/* XMRig
* Copyright 2012-2013 The Cryptonote developers
* Copyright 2014-2021 The Monero Project
* Copyright 2018-2021 SChernykh <https://github.com/SChernykh>
* Copyright 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/crypto/keccak.h"
#include "base/tools/cryptonote/BlobReader.h"
#include "base/tools/cryptonote/WalletAddress.h"
#include "base/tools/Buffer.h"
#include "crypto/cn/umul128.h"
#include <array>
namespace xmrig {
bool WalletAddress::Decode(const String& address)
{
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;
int8_t reverse_alphabet[256];
memset(reverse_alphabet, -1, sizeof(reverse_alphabet));
for (int i = 0; i < alphabet_size; ++i) {
reverse_alphabet[alphabet[i]] = i;
}
const int len = static_cast<int>(address.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 (int 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;
}
Buffer data;
data.reserve(static_cast<size_t>(num_full_blocks) * sizeof(uint64_t) + last_block_size_index);
const char* address_data = address.data();
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[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();
uint8_t* p = reinterpret_cast<uint8_t*>(&num);
for (int j = ((i < num_full_blocks) ? sizeof(num) : last_block_size_index) - 1; j >= 0; --j) {
data.emplace_back(p[j]);
}
}
CBlobReader ar(data.data(), data.size());
ar(tag);
ar(public_spend_key);
ar(public_view_key);
ar(checksum);
uint8_t md[200];
keccak(data.data(), data.size() - sizeof(checksum), md);
if (memcmp(checksum, md, sizeof(checksum)) != 0) {
return false;
}
return true;
}
} /* namespace xmrig */