call out non-ASCII
[ghsmtp.git] / picosha2.h
blobbc00c7435766e151d4e75928e5e936257d26f6b7
1 /*
2 The MIT License (MIT)
4 Copyright (C) 2017 okdshin
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 THE SOFTWARE.
24 #ifndef PICOSHA2_H
25 #define PICOSHA2_H
26 // picosha2:20140213
28 #ifndef PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR
29 #define PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR \
30 1048576 //=1024*1024: default is 1MB memory
31 #endif
33 #include <algorithm>
34 #include <cassert>
35 #include <iterator>
36 #include <sstream>
37 #include <vector>
38 #include <fstream>
39 namespace picosha2 {
40 typedef unsigned long word_t;
41 typedef unsigned char byte_t;
43 static const size_t k_digest_size = 32;
45 namespace detail {
46 inline byte_t mask_8bit(byte_t x) { return x & 0xff; }
48 inline word_t mask_32bit(word_t x) { return x & 0xffffffff; }
50 const word_t add_constant[64] = {
51 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
52 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
53 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
54 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
55 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
56 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
57 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
58 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
59 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
60 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
61 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
63 const word_t initial_message_digest[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372,
64 0xa54ff53a, 0x510e527f, 0x9b05688c,
65 0x1f83d9ab, 0x5be0cd19};
67 inline word_t ch(word_t x, word_t y, word_t z) { return (x & y) ^ ((~x) & z); }
69 inline word_t maj(word_t x, word_t y, word_t z) {
70 return (x & y) ^ (x & z) ^ (y & z);
73 inline word_t rotr(word_t x, std::size_t n) {
74 assert(n < 32);
75 return mask_32bit((x >> n) | (x << (32 - n)));
78 inline word_t bsig0(word_t x) { return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22); }
80 inline word_t bsig1(word_t x) { return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25); }
82 inline word_t shr(word_t x, std::size_t n) {
83 assert(n < 32);
84 return x >> n;
87 inline word_t ssig0(word_t x) { return rotr(x, 7) ^ rotr(x, 18) ^ shr(x, 3); }
89 inline word_t ssig1(word_t x) { return rotr(x, 17) ^ rotr(x, 19) ^ shr(x, 10); }
91 template <typename RaIter1, typename RaIter2>
92 void hash256_block(RaIter1 message_digest, RaIter2 first, RaIter2 last) {
93 assert(first + 64 == last);
94 static_cast<void>(last); // for avoiding unused-variable warning
95 word_t w[64];
96 std::fill(w, w + 64, 0);
97 for (std::size_t i = 0; i < 16; ++i) {
98 w[i] = (static_cast<word_t>(mask_8bit(*(first + i * 4))) << 24) |
99 (static_cast<word_t>(mask_8bit(*(first + i * 4 + 1))) << 16) |
100 (static_cast<word_t>(mask_8bit(*(first + i * 4 + 2))) << 8) |
101 (static_cast<word_t>(mask_8bit(*(first + i * 4 + 3))));
103 for (std::size_t i = 16; i < 64; ++i) {
104 w[i] = mask_32bit(ssig1(w[i - 2]) + w[i - 7] + ssig0(w[i - 15]) +
105 w[i - 16]);
108 word_t a = *message_digest;
109 word_t b = *(message_digest + 1);
110 word_t c = *(message_digest + 2);
111 word_t d = *(message_digest + 3);
112 word_t e = *(message_digest + 4);
113 word_t f = *(message_digest + 5);
114 word_t g = *(message_digest + 6);
115 word_t h = *(message_digest + 7);
117 for (std::size_t i = 0; i < 64; ++i) {
118 word_t temp1 = h + bsig1(e) + ch(e, f, g) + add_constant[i] + w[i];
119 word_t temp2 = bsig0(a) + maj(a, b, c);
120 h = g;
121 g = f;
122 f = e;
123 e = mask_32bit(d + temp1);
124 d = c;
125 c = b;
126 b = a;
127 a = mask_32bit(temp1 + temp2);
129 *message_digest += a;
130 *(message_digest + 1) += b;
131 *(message_digest + 2) += c;
132 *(message_digest + 3) += d;
133 *(message_digest + 4) += e;
134 *(message_digest + 5) += f;
135 *(message_digest + 6) += g;
136 *(message_digest + 7) += h;
137 for (std::size_t i = 0; i < 8; ++i) {
138 *(message_digest + i) = mask_32bit(*(message_digest + i));
142 } // namespace detail
144 template <typename InIter>
145 void output_hex(InIter first, InIter last, std::ostream& os) {
146 os.setf(std::ios::hex, std::ios::basefield);
147 while (first != last) {
148 os.width(2);
149 os.fill('0');
150 os << static_cast<unsigned int>(*first);
151 ++first;
153 os.setf(std::ios::dec, std::ios::basefield);
156 template <typename InIter>
157 void bytes_to_hex_string(InIter first, InIter last, std::string& hex_str) {
158 std::ostringstream oss;
159 output_hex(first, last, oss);
160 hex_str.assign(oss.str());
163 template <typename InContainer>
164 void bytes_to_hex_string(const InContainer& bytes, std::string& hex_str) {
165 bytes_to_hex_string(bytes.begin(), bytes.end(), hex_str);
168 template <typename InIter>
169 std::string bytes_to_hex_string(InIter first, InIter last) {
170 std::string hex_str;
171 bytes_to_hex_string(first, last, hex_str);
172 return hex_str;
175 template <typename InContainer>
176 std::string bytes_to_hex_string(const InContainer& bytes) {
177 std::string hex_str;
178 bytes_to_hex_string(bytes, hex_str);
179 return hex_str;
182 class hash256_one_by_one {
183 public:
184 hash256_one_by_one() { init(); }
186 void init() {
187 buffer_.clear();
188 std::fill(data_length_digits_, data_length_digits_ + 4, 0);
189 std::copy(detail::initial_message_digest,
190 detail::initial_message_digest + 8, h_);
193 template <typename RaIter>
194 void process(RaIter first, RaIter last) {
195 add_to_data_length(static_cast<word_t>(std::distance(first, last)));
196 std::copy(first, last, std::back_inserter(buffer_));
197 std::size_t i = 0;
198 for (; i + 64 <= buffer_.size(); i += 64) {
199 detail::hash256_block(h_, buffer_.begin() + i,
200 buffer_.begin() + i + 64);
202 buffer_.erase(buffer_.begin(), buffer_.begin() + i);
205 void finish() {
206 byte_t temp[64];
207 std::fill(temp, temp + 64, 0);
208 std::size_t remains = buffer_.size();
209 std::copy(buffer_.begin(), buffer_.end(), temp);
210 temp[remains] = 0x80;
212 if (remains > 55) {
213 std::fill(temp + remains + 1, temp + 64, 0);
214 detail::hash256_block(h_, temp, temp + 64);
215 std::fill(temp, temp + 64 - 4, 0);
216 } else {
217 std::fill(temp + remains + 1, temp + 64 - 4, 0);
220 write_data_bit_length(&(temp[56]));
221 detail::hash256_block(h_, temp, temp + 64);
224 template <typename OutIter>
225 void get_hash_bytes(OutIter first, OutIter last) const {
226 for (const word_t* iter = h_; iter != h_ + 8; ++iter) {
227 for (std::size_t i = 0; i < 4 && first != last; ++i) {
228 *(first++) = detail::mask_8bit(
229 static_cast<byte_t>((*iter >> (24 - 8 * i))));
234 private:
235 void add_to_data_length(word_t n) {
236 word_t carry = 0;
237 data_length_digits_[0] += n;
238 for (std::size_t i = 0; i < 4; ++i) {
239 data_length_digits_[i] += carry;
240 if (data_length_digits_[i] >= 65536u) {
241 carry = data_length_digits_[i] >> 16;
242 data_length_digits_[i] &= 65535u;
243 } else {
244 break;
248 void write_data_bit_length(byte_t* begin) {
249 word_t data_bit_length_digits[4];
250 std::copy(data_length_digits_, data_length_digits_ + 4,
251 data_bit_length_digits);
253 // convert byte length to bit length (multiply 8 or shift 3 times left)
254 word_t carry = 0;
255 for (std::size_t i = 0; i < 4; ++i) {
256 word_t before_val = data_bit_length_digits[i];
257 data_bit_length_digits[i] <<= 3;
258 data_bit_length_digits[i] |= carry;
259 data_bit_length_digits[i] &= 65535u;
260 carry = (before_val >> (16 - 3)) & 65535u;
263 // write data_bit_length
264 for (int i = 3; i >= 0; --i) {
265 (*begin++) = static_cast<byte_t>(data_bit_length_digits[i] >> 8);
266 (*begin++) = static_cast<byte_t>(data_bit_length_digits[i]);
269 std::vector<byte_t> buffer_;
270 word_t data_length_digits_[4]; // as 64bit integer (16bit x 4 integer)
271 word_t h_[8];
274 inline void get_hash_hex_string(const hash256_one_by_one& hasher,
275 std::string& hex_str) {
276 byte_t hash[k_digest_size];
277 hasher.get_hash_bytes(hash, hash + k_digest_size);
278 return bytes_to_hex_string(hash, hash + k_digest_size, hex_str);
281 inline std::string get_hash_hex_string(const hash256_one_by_one& hasher) {
282 std::string hex_str;
283 get_hash_hex_string(hasher, hex_str);
284 return hex_str;
287 namespace impl {
288 template <typename RaIter, typename OutIter>
289 void hash256_impl(RaIter first, RaIter last, OutIter first2, OutIter last2, int,
290 std::random_access_iterator_tag) {
291 hash256_one_by_one hasher;
292 // hasher.init();
293 hasher.process(first, last);
294 hasher.finish();
295 hasher.get_hash_bytes(first2, last2);
298 template <typename InputIter, typename OutIter>
299 void hash256_impl(InputIter first, InputIter last, OutIter first2,
300 OutIter last2, int buffer_size, std::input_iterator_tag) {
301 std::vector<byte_t> buffer(buffer_size);
302 hash256_one_by_one hasher;
303 // hasher.init();
304 while (first != last) {
305 int size = buffer_size;
306 for (int i = 0; i != buffer_size; ++i, ++first) {
307 if (first == last) {
308 size = i;
309 break;
311 buffer[i] = *first;
313 hasher.process(buffer.begin(), buffer.begin() + size);
315 hasher.finish();
316 hasher.get_hash_bytes(first2, last2);
320 template <typename InIter, typename OutIter>
321 void hash256(InIter first, InIter last, OutIter first2, OutIter last2,
322 int buffer_size = PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR) {
323 picosha2::impl::hash256_impl(
324 first, last, first2, last2, buffer_size,
325 typename std::iterator_traits<InIter>::iterator_category());
328 template <typename InIter, typename OutContainer>
329 void hash256(InIter first, InIter last, OutContainer& dst) {
330 hash256(first, last, dst.begin(), dst.end());
333 template <typename InContainer, typename OutIter>
334 void hash256(const InContainer& src, OutIter first, OutIter last) {
335 hash256(src.begin(), src.end(), first, last);
338 template <typename InContainer, typename OutContainer>
339 void hash256(const InContainer& src, OutContainer& dst) {
340 hash256(src.begin(), src.end(), dst.begin(), dst.end());
343 template <typename InIter>
344 void hash256_hex_string(InIter first, InIter last, std::string& hex_str) {
345 byte_t hashed[k_digest_size];
346 hash256(first, last, hashed, hashed + k_digest_size);
347 std::ostringstream oss;
348 output_hex(hashed, hashed + k_digest_size, oss);
349 hex_str.assign(oss.str());
352 template <typename InIter>
353 std::string hash256_hex_string(InIter first, InIter last) {
354 std::string hex_str;
355 hash256_hex_string(first, last, hex_str);
356 return hex_str;
359 inline void hash256_hex_string(const std::string& src, std::string& hex_str) {
360 hash256_hex_string(src.begin(), src.end(), hex_str);
363 template <typename InContainer>
364 void hash256_hex_string(const InContainer& src, std::string& hex_str) {
365 hash256_hex_string(src.begin(), src.end(), hex_str);
368 template <typename InContainer>
369 std::string hash256_hex_string(const InContainer& src) {
370 return hash256_hex_string(src.begin(), src.end());
372 template<typename OutIter>void hash256(std::ifstream& f, OutIter first, OutIter last){
373 hash256(std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>(), first,last);
376 }// namespace picosha2
377 #endif // PICOSHA2_H