|
| 1 | +#ifndef SHA256_HPP |
| 2 | +#define SHA256_HPP |
| 3 | + |
| 4 | +#include <array> |
| 5 | +#include <cstdint> |
| 6 | +#include <cstring> |
| 7 | +#include <string> |
| 8 | + |
| 9 | +class Sha256 { |
| 10 | + public: |
| 11 | + Sha256() { reset(); } |
| 12 | + |
| 13 | + void reset() { |
| 14 | + bitlen_ = 0; |
| 15 | + datalen_ = 0; |
| 16 | + state_[0] = 0x6a09e667; |
| 17 | + state_[1] = 0xbb67ae85; |
| 18 | + state_[2] = 0x3c6ef372; |
| 19 | + state_[3] = 0xa54ff53a; |
| 20 | + state_[4] = 0x510e527f; |
| 21 | + state_[5] = 0x9b05688c; |
| 22 | + state_[6] = 0x1f83d9ab; |
| 23 | + state_[7] = 0x5be0cd19; |
| 24 | + } |
| 25 | + |
| 26 | + void update(const uint8_t* data, size_t len) { |
| 27 | + for (size_t i = 0; i < len; ++i) { |
| 28 | + data_[datalen_++] = data[i]; |
| 29 | + if (datalen_ == 64) { |
| 30 | + transform(); |
| 31 | + bitlen_ += 512; |
| 32 | + datalen_ = 0; |
| 33 | + } |
| 34 | + } |
| 35 | + } |
| 36 | + |
| 37 | + void update(const std::string& s) { |
| 38 | + update(reinterpret_cast<const uint8_t*>(s.data()), s.size()); |
| 39 | + } |
| 40 | + |
| 41 | + std::array<uint8_t, 32> finalize() { |
| 42 | + uint32_t i = datalen_; |
| 43 | + if (datalen_ < 56) { |
| 44 | + data_[i++] = 0x80; |
| 45 | + while (i < 56) data_[i++] = 0x00; |
| 46 | + } else { |
| 47 | + data_[i++] = 0x80; |
| 48 | + while (i < 64) data_[i++] = 0x00; |
| 49 | + transform(); |
| 50 | + std::memset(data_, 0, 56); |
| 51 | + } |
| 52 | + bitlen_ += static_cast<uint64_t>(datalen_) * 8; |
| 53 | + for (int j = 7; j >= 0; --j) { |
| 54 | + data_[56 + (7 - j)] = static_cast<uint8_t>((bitlen_ >> (j * 8)) & 0xff); |
| 55 | + } |
| 56 | + transform(); |
| 57 | + |
| 58 | + std::array<uint8_t, 32> out{}; |
| 59 | + for (int j = 0; j < 4; ++j) { |
| 60 | + for (int k = 0; k < 8; ++k) { |
| 61 | + out[j + k * 4] = |
| 62 | + static_cast<uint8_t>((state_[k] >> (24 - j * 8)) & 0xff); |
| 63 | + } |
| 64 | + } |
| 65 | + return out; |
| 66 | + } |
| 67 | + |
| 68 | + // Returns the first hex_chars hex characters of SHA-256(s). |
| 69 | + // hex_chars must be <= 64; values are silently clamped to 64. |
| 70 | + static std::string hashHex(const std::string& s, size_t hex_chars = 32) { |
| 71 | + Sha256 h; |
| 72 | + h.update(s); |
| 73 | + auto digest = h.finalize(); |
| 74 | + static const char* kHex = "0123456789abcdef"; |
| 75 | + if (hex_chars > 64) hex_chars = 64; |
| 76 | + size_t bytes = (hex_chars + 1) / 2; |
| 77 | + std::string out; |
| 78 | + out.reserve(bytes * 2); |
| 79 | + for (size_t i = 0; i < bytes; ++i) { |
| 80 | + out.push_back(kHex[(digest[i] >> 4) & 0xf]); |
| 81 | + out.push_back(kHex[digest[i] & 0xf]); |
| 82 | + } |
| 83 | + out.resize(hex_chars); |
| 84 | + return out; |
| 85 | + } |
| 86 | + |
| 87 | + private: |
| 88 | + uint8_t data_[64]; |
| 89 | + uint32_t datalen_; |
| 90 | + uint64_t bitlen_; |
| 91 | + uint32_t state_[8]; |
| 92 | + |
| 93 | + static uint32_t rotr(uint32_t x, uint32_t n) { |
| 94 | + return (x >> n) | (x << (32 - n)); |
| 95 | + } |
| 96 | + |
| 97 | + void transform() { |
| 98 | + static const uint32_t K[64] = { |
| 99 | + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, |
| 100 | + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, |
| 101 | + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, |
| 102 | + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, |
| 103 | + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, |
| 104 | + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, |
| 105 | + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, |
| 106 | + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, |
| 107 | + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, |
| 108 | + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, |
| 109 | + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, |
| 110 | + }; |
| 111 | + |
| 112 | + uint32_t m[64]; |
| 113 | + for (uint32_t i = 0, j = 0; i < 16; ++i, j += 4) { |
| 114 | + m[i] = (uint32_t(data_[j]) << 24) | (uint32_t(data_[j + 1]) << 16) | |
| 115 | + (uint32_t(data_[j + 2]) << 8) | uint32_t(data_[j + 3]); |
| 116 | + } |
| 117 | + for (uint32_t i = 16; i < 64; ++i) { |
| 118 | + uint32_t s0 = rotr(m[i - 15], 7) ^ rotr(m[i - 15], 18) ^ (m[i - 15] >> 3); |
| 119 | + uint32_t s1 = rotr(m[i - 2], 17) ^ rotr(m[i - 2], 19) ^ (m[i - 2] >> 10); |
| 120 | + m[i] = m[i - 16] + s0 + m[i - 7] + s1; |
| 121 | + } |
| 122 | + |
| 123 | + uint32_t a = state_[0], b = state_[1], c = state_[2], d = state_[3]; |
| 124 | + uint32_t e = state_[4], f = state_[5], g = state_[6], h = state_[7]; |
| 125 | + for (uint32_t i = 0; i < 64; ++i) { |
| 126 | + uint32_t S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25); |
| 127 | + uint32_t ch = (e & f) ^ (~e & g); |
| 128 | + uint32_t t1 = h + S1 + ch + K[i] + m[i]; |
| 129 | + uint32_t S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22); |
| 130 | + uint32_t mj = (a & b) ^ (a & c) ^ (b & c); |
| 131 | + uint32_t t2 = S0 + mj; |
| 132 | + h = g; |
| 133 | + g = f; |
| 134 | + f = e; |
| 135 | + e = d + t1; |
| 136 | + d = c; |
| 137 | + c = b; |
| 138 | + b = a; |
| 139 | + a = t1 + t2; |
| 140 | + } |
| 141 | + |
| 142 | + state_[0] += a; |
| 143 | + state_[1] += b; |
| 144 | + state_[2] += c; |
| 145 | + state_[3] += d; |
| 146 | + state_[4] += e; |
| 147 | + state_[5] += f; |
| 148 | + state_[6] += g; |
| 149 | + state_[7] += h; |
| 150 | + } |
| 151 | +}; |
| 152 | + |
| 153 | +#endif // SHA256_HPP |
0 commit comments