BtcExplorer/hash.h

100 lines
3.3 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> hash160(const T& data) {
return ripemd160(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