341 lines
11 KiB
C++
341 lines
11 KiB
C++
/*
|
|
* MIT License
|
|
*
|
|
* Copyright (c) 2017-2024 nagaDev
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
#ifndef PICOSHA2_H
|
|
#define PICOSHA2_H
|
|
//picosha2:20140213
|
|
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <iterator>
|
|
#include <sstream>
|
|
#include <vector>
|
|
#include <iomanip>
|
|
|
|
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
|
|
#include <cstdint>
|
|
#else
|
|
#include <stdint.h>
|
|
#endif
|
|
|
|
namespace picosha2
|
|
{
|
|
typedef unsigned char byte_t;
|
|
typedef unsigned int word_t;
|
|
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
|
|
typedef uint64_t bits_t;
|
|
#else
|
|
typedef uint64_t bits_t;
|
|
#endif
|
|
|
|
namespace detail
|
|
{
|
|
inline byte_t rotr(byte_t x, byte_t n)
|
|
{
|
|
return (x >> n) | (x << (8 - n));
|
|
}
|
|
|
|
inline word_t rotr(word_t x, word_t n)
|
|
{
|
|
return (x >> n) | (x << (32 - n));
|
|
}
|
|
|
|
inline word_t add(word_t i, word_t j)
|
|
{
|
|
return i + j;
|
|
}
|
|
|
|
template<typename InIter>
|
|
void fill_block(InIter first, InIter last, std::vector<byte_t>& block)
|
|
{
|
|
block.clear();
|
|
block.reserve(std::distance(first, last));
|
|
std::copy(first, last, std::back_inserter(block));
|
|
}
|
|
|
|
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
|
|
template<typename InContainer,
|
|
typename std::enable_if<
|
|
!std::is_same<
|
|
typename std::iterator_traits<typename InContainer::iterator>::iterator_category,
|
|
std::input_iterator_tag>::value>::type* = nullptr>
|
|
#else
|
|
template<typename InContainer>
|
|
#endif
|
|
void fill_block(const InContainer& container, std::vector<byte_t>& block)
|
|
{
|
|
block.clear();
|
|
block.reserve(container.size());
|
|
std::copy(container.begin(), container.end(), std::back_inserter(block));
|
|
}
|
|
|
|
class hash256_one_by_one
|
|
{
|
|
public:
|
|
hash256_one_by_one()
|
|
{
|
|
init();
|
|
}
|
|
|
|
void init()
|
|
{
|
|
h_[0] = 0x6a09e667;
|
|
h_[1] = 0xbb67ae85;
|
|
h_[2] = 0x3c6ef372;
|
|
h_[3] = 0xa54ff53a;
|
|
h_[4] = 0x510e527f;
|
|
h_[5] = 0x9b05688c;
|
|
h_[6] = 0x1f83d9ab;
|
|
h_[7] = 0x5be0cd19;
|
|
|
|
add_len_ = 0;
|
|
buffer_idx_ = 0;
|
|
}
|
|
|
|
template<typename InIter>
|
|
void process(InIter first, InIter last)
|
|
{
|
|
add_len_ += std::distance(first, last);
|
|
for (; first != last; ++first)
|
|
{
|
|
buffer_[buffer_idx_++] = *first;
|
|
if (buffer_idx_ == 64)
|
|
{
|
|
calc_chunk();
|
|
buffer_idx_ = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void finish()
|
|
{
|
|
bits_t len_bit_ = add_len_ * 8;
|
|
word_t len_bit_upper = static_cast<word_t>(len_bit_ >> 32);
|
|
word_t len_bit_lower = static_cast<word_t>(len_bit_ & 0xffffffff);
|
|
|
|
buffer_[buffer_idx_++] = 0x80;
|
|
|
|
if (buffer_idx_ > 56)
|
|
{
|
|
while (buffer_idx_ < 64)
|
|
{
|
|
buffer_[buffer_idx_++] = 0;
|
|
}
|
|
calc_chunk();
|
|
buffer_idx_ = 0;
|
|
}
|
|
|
|
while (buffer_idx_ < 56)
|
|
{
|
|
buffer_[buffer_idx_++] = 0;
|
|
}
|
|
|
|
buffer_[56] = static_cast<byte_t>(len_bit_upper >> 24);
|
|
buffer_[57] = static_cast<byte_t>(len_bit_upper >> 16);
|
|
buffer_[58] = static_cast<byte_t>(len_bit_upper >> 8);
|
|
buffer_[59] = static_cast<byte_t>(len_bit_upper);
|
|
buffer_[60] = static_cast<byte_t>(len_bit_lower >> 24);
|
|
buffer_[61] = static_cast<byte_t>(len_bit_lower >> 16);
|
|
buffer_[62] = static_cast<byte_t>(len_bit_lower >> 8);
|
|
buffer_[63] = static_cast<byte_t>(len_bit_lower);
|
|
|
|
calc_chunk();
|
|
}
|
|
|
|
word_t const* get_hash() const
|
|
{
|
|
return h_;
|
|
}
|
|
|
|
private:
|
|
void calc_chunk()
|
|
{
|
|
word_t w[64];
|
|
for (int i = 0; i < 16; ++i)
|
|
{
|
|
w[i] = (static_cast<word_t>(buffer_[i * 4]) << 24) |
|
|
(static_cast<word_t>(buffer_[i * 4 + 1]) << 16) |
|
|
(static_cast<word_t>(buffer_[i * 4 + 2]) << 8) |
|
|
(static_cast<word_t>(buffer_[i * 4 + 3]));
|
|
}
|
|
|
|
for (int i = 16; i < 64; ++i)
|
|
{
|
|
word_t s0 = rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ (w[i - 15] >> 3);
|
|
word_t s1 = rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ (w[i - 2] >> 10);
|
|
w[i] = add(add(w[i - 16], s0), add(w[i - 7], s1));
|
|
}
|
|
|
|
word_t a = h_[0];
|
|
word_t b = h_[1];
|
|
word_t c = h_[2];
|
|
word_t d = h_[3];
|
|
word_t e = h_[4];
|
|
word_t f = h_[5];
|
|
word_t g = h_[6];
|
|
word_t h = h_[7];
|
|
|
|
static const word_t k[] = {
|
|
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
|
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
|
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
|
};
|
|
|
|
for (int i = 0; i < 64; ++i)
|
|
{
|
|
word_t s1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
|
|
word_t ch = (e & f) ^ ((~e) & g);
|
|
word_t temp1 = add(add(h, s1), add(ch, add(k[i], w[i])));
|
|
word_t s0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
|
|
word_t maj = (a & b) ^ (a & c) ^ (b & c);
|
|
word_t temp2 = add(s0, maj);
|
|
|
|
h = g;
|
|
g = f;
|
|
f = e;
|
|
e = add(d, temp1);
|
|
d = c;
|
|
c = b;
|
|
b = a;
|
|
a = add(temp1, temp2);
|
|
}
|
|
|
|
h_[0] = add(h_[0], a);
|
|
h_[1] = add(h_[1], b);
|
|
h_[2] = add(h_[2], c);
|
|
h_[3] = add(h_[3], d);
|
|
h_[4] = add(h_[4], e);
|
|
h_[5] = add(h_[5], f);
|
|
h_[6] = add(h_[6], g);
|
|
h_[7] = add(h_[7], h);
|
|
}
|
|
|
|
word_t h_[8];
|
|
byte_t buffer_[64];
|
|
size_t buffer_idx_;
|
|
uint64_t add_len_;
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
template<typename InIter>
|
|
void hash256(InIter first, InIter last, std::vector<byte_t>& hash)
|
|
{
|
|
detail::hash256_one_by_one hasher;
|
|
hasher.process(first, last);
|
|
hasher.finish();
|
|
hash.assign(32, 0);
|
|
word_t const* digest = hasher.get_hash();
|
|
for (int i = 0; i < 8; ++i)
|
|
{
|
|
hash[i * 4] = static_cast<byte_t>(digest[i] >> 24);
|
|
hash[i * 4 + 1] = static_cast<byte_t>(digest[i] >> 16);
|
|
hash[i * 4 + 2] = static_cast<byte_t>(digest[i] >> 8);
|
|
hash[i * 4 + 3] = static_cast<byte_t>(digest[i]);
|
|
}
|
|
}
|
|
|
|
template<typename InIter>
|
|
void hash256(InIter first, InIter last, std::string& hex_str)
|
|
{
|
|
std::vector<byte_t> hash(32);
|
|
hash256(first, last, hash);
|
|
hex_str = bytes_to_hex_string(hash.begin(), hash.end());
|
|
}
|
|
|
|
template<typename InIter>
|
|
std::string hash256_hex_string(InIter first, InIter last)
|
|
{
|
|
std::string hex_str;
|
|
hash256(first, last, hex_str);
|
|
return hex_str;
|
|
}
|
|
|
|
template<typename In>
|
|
void hash256(const In& in, std::vector<byte_t>& hash)
|
|
{
|
|
hash256(std::begin(in), std::end(in), hash);
|
|
}
|
|
|
|
template<typename In>
|
|
void hash256(const In& in, std::string& hex_str)
|
|
{
|
|
hash256(std::begin(in), std::end(in), hex_str);
|
|
}
|
|
|
|
template<typename In>
|
|
std::string hash256_hex_string(const In& in)
|
|
{
|
|
return hash256_hex_string(std::begin(in), std::end(in));
|
|
}
|
|
|
|
template<typename InIter>
|
|
std::string bytes_to_hex_string(InIter first, InIter last)
|
|
{
|
|
std::stringstream ss;
|
|
ss << std::hex << std::setfill('0');
|
|
while (first != last)
|
|
{
|
|
ss << std::setw(2) << static_cast<int>(*first);
|
|
++first;
|
|
}
|
|
return ss.str();
|
|
}
|
|
|
|
template<typename In>
|
|
std::string bytes_to_hex_string(const In& bytes)
|
|
{
|
|
return bytes_to_hex_string(std::begin(bytes), std::end(bytes));
|
|
}
|
|
|
|
template<typename OutIter>
|
|
void hex_string_to_bytes(const std::string& hex_str, OutIter out)
|
|
{
|
|
assert(hex_str.length() % 2 == 0);
|
|
for (size_t i = 0; i < hex_str.length(); i += 2)
|
|
{
|
|
int val;
|
|
std::stringstream ss;
|
|
ss << std::hex << hex_str.substr(i, 2);
|
|
ss >> val;
|
|
*out = static_cast<byte_t>(val);
|
|
++out;
|
|
}
|
|
}
|
|
|
|
template<typename OutContainer>
|
|
void hex_string_to_bytes(const std::string& hex_str, OutContainer& bytes)
|
|
{
|
|
hex_string_to_bytes(hex_str, std::back_inserter(bytes));
|
|
}
|
|
|
|
} // namespace picosha2
|
|
|
|
#endif //PICOSHA2_H
|