121 lines
4.0 KiB
C++
121 lines
4.0 KiB
C++
#ifndef BTCEXPLORER_HASH_H
|
|
#define BTCEXPLORER_HASH_H
|
|
|
|
#include <cstdint>
|
|
#include <array>
|
|
#include <string>
|
|
#include <concepts>
|
|
|
|
#include <openssl/sha.h>
|
|
#include <openssl/ripemd.h>
|
|
|
|
namespace hash {
|
|
|
|
static const char hex_table[16] = {
|
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
|
};
|
|
|
|
static const uint8_t base58map[] = {
|
|
'1', '2', '3', '4', '5', '6', '7', '8',
|
|
'9', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
|
|
'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q',
|
|
'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
|
|
'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
|
|
'h', 'i', 'j', 'k', 'm', 'n', 'o', 'p',
|
|
'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
|
|
'y', 'z' };
|
|
|
|
// Generalization of something acting as contiguous sequence of bytes
|
|
// For example: std::array, std::vector, std::span
|
|
template<typename T>
|
|
concept ByteArray = requires(T collection) {
|
|
{ collection[0] } -> std::same_as<typename T::value_type &>;
|
|
{ collection.size() } -> std::same_as<size_t>;
|
|
{ collection.data() } -> std::same_as<typename T::value_type*>;
|
|
requires sizeof(typename T::value_type) == 1;
|
|
};
|
|
|
|
template<ByteArray T>
|
|
std::string to_string(const T& data) {
|
|
std::string str(data.size()*2, ' ');
|
|
for(size_t i = 0; i < data.size(); ++i) {
|
|
str[2*i] = hex_table[(data[i] & 0xF0) >> 4];
|
|
str[2*i + 1] = hex_table[data[i] & 0x0F];
|
|
}
|
|
return str;
|
|
}
|
|
|
|
template<ByteArray T>
|
|
std::array<uint8_t,SHA256_DIGEST_LENGTH> sha256(const T& data) {
|
|
std::array<uint8_t ,SHA256_DIGEST_LENGTH> hash{};
|
|
SHA256_CTX ctx;
|
|
SHA256_Init(&ctx);
|
|
SHA256_Update(&ctx, data.data(), data.size());
|
|
SHA256_Final(hash.data(), &ctx);
|
|
return hash;
|
|
}
|
|
|
|
template<ByteArray T>
|
|
std::array<uint8_t,RIPEMD160_DIGEST_LENGTH> ripemd160(const T& data) {
|
|
std::array<uint8_t,RIPEMD160_DIGEST_LENGTH> hash{};
|
|
RIPEMD160_CTX ctx;
|
|
RIPEMD160_Init(&ctx);
|
|
RIPEMD160_Update(&ctx, data.data(), data.size());
|
|
RIPEMD160_Final(hash.data(), &ctx);
|
|
return hash;
|
|
}
|
|
|
|
template<ByteArray T>
|
|
std::array<uint8_t,RIPEMD160_DIGEST_LENGTH + 1> ripemd160(const T& data, uint8_t prefix) {
|
|
std::array<uint8_t,RIPEMD160_DIGEST_LENGTH + 1> hash{};
|
|
hash[0] = prefix;
|
|
RIPEMD160_CTX ctx;
|
|
RIPEMD160_Init(&ctx);
|
|
RIPEMD160_Update(&ctx, data.data(), data.size());
|
|
RIPEMD160_Final(hash.data() + 1, &ctx);
|
|
return hash;
|
|
}
|
|
|
|
template<ByteArray T>
|
|
std::array<uint8_t,RIPEMD160_DIGEST_LENGTH> hash160(const T& data) {
|
|
return ripemd160(sha256(data));
|
|
}
|
|
|
|
template<ByteArray T>
|
|
std::array<uint8_t,RIPEMD160_DIGEST_LENGTH + 1> hash160(const T& data, uint8_t prefix) {
|
|
return ripemd160(sha256(data), prefix);
|
|
}
|
|
|
|
template<ByteArray T>
|
|
std::array<uint8_t,SHA256_DIGEST_LENGTH> hash256(const T& data) {
|
|
return sha256(sha256(data));
|
|
}
|
|
|
|
template<ByteArray T>
|
|
std::string base58(const T& data)
|
|
{
|
|
std::vector<uint8_t> digits((data.size() * 138 / 100) + 1);
|
|
size_t digitsLen = 1;
|
|
for (size_t i = 0; i < data.size(); i++)
|
|
{
|
|
uint32_t carry = static_cast<uint32_t>(data[i]);
|
|
for (size_t j = 0; j < digitsLen; j++)
|
|
{
|
|
carry = carry + static_cast<uint32_t>(digits[j] << 8);
|
|
digits[j] = static_cast<uint8_t>(carry % 58);
|
|
carry /= 58;
|
|
}
|
|
for (; carry; carry /= 58)
|
|
digits[digitsLen++] = static_cast<uint8_t>(carry % 58);
|
|
}
|
|
std::string result;
|
|
for (size_t i = 0; i < (data.size() - 1) && !data[i]; i++)
|
|
result.push_back(base58map[0]);
|
|
for (size_t i = 0; i < digitsLen; i++)
|
|
result.push_back(base58map[digits[digitsLen - 1 - i]]);
|
|
return result;
|
|
}
|
|
}
|
|
|
|
#endif //BTCEXPLORER_HASH_H
|