HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
SHA2.hpp
1// Copyright Take Vos 2020.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "../byte_string.hpp"
8#include "../required.hpp"
9#include "../assert.hpp"
10#include <bit>
11#include <array>
12#include <cstdint>
13#include <span>
14
15namespace hi::inline v1 {
16namespace detail::SHA2 {
17
18template<typename T>
19struct state {
20 T a;
21 T b;
22 T c;
23 T d;
24 T e;
25 T f;
26 T g;
27 T h;
28
29 constexpr state(T a, T b, T c, T d, T e, T f, T g, T h) noexcept : a(a), b(b), c(c), d(d), e(e), f(f), g(g), h(h) {}
30
31 [[nodiscard]] constexpr T get_word(std::size_t i) const noexcept
32 {
33 switch (i) {
34 case 0: return a;
35 case 1: return b;
36 case 2: return c;
37 case 3: return d;
38 case 4: return e;
39 case 5: return f;
40 case 6: return g;
41 case 7: return h;
42 default: hi_no_default();
43 }
44 }
45
46 [[nodiscard]] constexpr std::byte get_byte(std::size_t i) const noexcept
47 {
48 hi_axiom(i < 8 * sizeof(T));
49 hilet word_nr = i / sizeof(T);
50 hilet byte_nr = i % sizeof(T);
51 hilet word = get_word(word_nr);
52 return static_cast<std::byte>(word >> (sizeof(T) - 1 - byte_nr) * 8);
53 }
54
55 template<std::size_t N>
56 [[nodiscard]] bstring get_bytes() const noexcept
57 {
58 auto r = bstring{};
59 r.reserve(N);
60
61 for (std::size_t i = 0; i != N; ++i) {
62 r += get_byte(i);
63 }
64 return r;
65 }
66
67 constexpr state &operator+=(state const &rhs) noexcept
68 {
69 a += rhs.a;
70 b += rhs.b;
71 c += rhs.c;
72 d += rhs.d;
73 e += rhs.e;
74 f += rhs.f;
75 g += rhs.g;
76 h += rhs.h;
77 return *this;
78 }
79};
80
81template<typename T>
82struct block {
84
85 static constexpr std::size_t size = sizeof(v);
86
87 constexpr void set_byte(std::size_t i, std::byte value) noexcept
88 {
89 hilet word_nr = i / sizeof(T);
90 hilet byte_nr = i % sizeof(T);
91 auto &word = v[word_nr];
92
93 hilet valueT = static_cast<T>(static_cast<uint8_t>(value));
94 word |= valueT << (sizeof(T) - 1 - byte_nr) * 8;
95 }
96
97 constexpr block(std::byte const *ptr) noexcept : v()
98 {
99 for (std::size_t i = 0; i != size; ++i) {
100 set_byte(i, *(ptr++));
101 }
102 }
103
104 constexpr T const &operator[](std::size_t i) const noexcept
105 {
106 return v[i % 16];
107 }
108
109 constexpr T &operator[](std::size_t i) noexcept
110 {
111 return v[i % 16];
112 }
113};
114
115} // namespace detail::SHA2
116
117template<typename T, std::size_t Bits>
118class SHA2 {
119 static_assert(Bits % 8 == 0);
120 static constexpr std::size_t nr_rounds = (sizeof(T) == 4) ? 64 : 80;
121 static constexpr std::size_t pad_length_of_length = (sizeof(T) == 4) ? 8 : 16;
122
125 using byteptr = std::byte *;
126 using cbyteptr = std::byte const *;
127 state_type state;
128
130 overflow_type overflow;
131 typename overflow_type::iterator overflow_it;
132
133 std::size_t size;
134
135 [[nodiscard]] static constexpr T K(std::size_t i) noexcept
136 {
137 constexpr std::array<uint32_t, 64> K32 = {
138 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
139 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
140 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
141 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
142 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
143 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
144 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
145 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
146
147 constexpr std::array<uint64_t, 80> K64 = {
148 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538,
149 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe,
150 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235,
151 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
152 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab,
153 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725,
154 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed,
155 0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
156 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218,
157 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53,
158 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373,
159 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
160 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c,
161 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6,
162 0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
163 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817};
164
165 if constexpr (std::is_same_v<T, uint32_t>) {
166 return K32[i];
167 } else {
168 return K64[i];
169 }
170 }
171
172 [[nodiscard]] static constexpr T Maj(T x, T y, T z) noexcept
173 {
174 return (x & y) ^ (x & z) ^ (y & z);
175 }
176
177 [[nodiscard]] static constexpr T Ch(T x, T y, T z) noexcept
178 {
179 return (x & y) ^ (~x & z);
180 }
181
182 template<int A, int B, int C>
183 [[nodiscard]] static constexpr T S(T x) noexcept
184 {
185 return std::rotr(x, A) ^ std::rotr(x, B) ^ std::rotr(x, C);
186 }
187
188 template<int A, int B, int C>
189 [[nodiscard]] static constexpr T s(T x) noexcept
190 {
191 return std::rotr(x, A) ^ std::rotr(x, B) ^ x >> C;
192 }
193
194 [[nodiscard]] static constexpr T S0(T x) noexcept
195 {
196 if constexpr (std::is_same_v<T, uint32_t>) {
197 return S<2, 13, 22>(x);
198 } else {
199 return S<28, 34, 39>(x);
200 }
201 }
202
203 [[nodiscard]] static constexpr T S1(T x)
204 {
205 if constexpr (std::is_same_v<T, uint32_t>) {
206 return S<6, 11, 25>(x);
207 } else {
208 return S<14, 18, 41>(x);
209 }
210 }
211
212 [[nodiscard]] static constexpr T s0(T x)
213 {
214 if constexpr (std::is_same_v<T, uint32_t>) {
215 return s<7, 18, 3>(x);
216 } else {
217 return s<1, 8, 7>(x);
218 }
219 }
220
221 [[nodiscard]] static constexpr T s1(T x)
222 {
223 if constexpr (std::is_same_v<T, uint32_t>) {
224 return s<17, 19, 10>(x);
225 } else {
226 return s<19, 61, 6>(x);
227 }
228 }
229
230 static constexpr state_type round(state_type const &tmp, T K, T W) noexcept
231 {
232 hilet T1 = tmp.h + S1(tmp.e) + Ch(tmp.e, tmp.f, tmp.g) + K + W;
233
234 hilet T2 = S0(tmp.a) + Maj(tmp.a, tmp.b, tmp.c);
235
236 return {T1 + T2, tmp.a, tmp.b, tmp.c, tmp.d + T1, tmp.e, tmp.f, tmp.g};
237 }
238
239 constexpr void add(block_type W) noexcept
240 {
241 auto tmp = state;
242 for (std::size_t i = 0; i != 16; ++i) {
243 tmp = round(tmp, K(i), W[i]);
244 }
245
246 for (std::size_t i = 16; i != nr_rounds; ++i) {
247 hilet W_ = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16];
248
249 tmp = round(tmp, K(i), W_);
250
251 W[i] = W_;
252 }
253 state += tmp;
254 }
255
256 constexpr void add_to_overflow(cbyteptr &ptr, std::byte const *last) noexcept
257 {
258 while (overflow_it != overflow.end() && ptr != last) {
259 *(overflow_it++) = *(ptr++);
260 }
261 }
262
263 constexpr void pad() noexcept
264 {
265 hi_axiom(overflow_it != overflow.end());
266
267 // Add the terminating '1' bit.
268 *(overflow_it++) = std::byte{0x80};
269
270 // Complete the current block if there is not enough room
271 // for the length in this block.
272 hilet overflow_left = overflow.end() - overflow_it;
273 if (overflow_left < pad_length_of_length) {
274 while (overflow_it != overflow.end()) {
275 *(overflow_it++) = std::byte{0x00};
276 }
277 add(block_type{overflow.data()});
278 overflow_it = overflow.begin();
279 }
280
281 // Pad until the start of length.
282 hilet overflow_length_start = overflow.end() - pad_length_of_length;
283 while (overflow_it != overflow_length_start) {
284 *(overflow_it++) = std::byte{0x00};
285 }
286
287 std::size_t nr_of_bits = size * 8;
288 for (int i = pad_length_of_length - 1; i >= 0; --i) {
289 *(overflow_it++) = i < sizeof(nr_of_bits) ? static_cast<std::byte>(nr_of_bits >> i * 8) : std::byte{0x00};
290 }
291
292 auto b = block_type{overflow.data()};
293 add(b);
294 }
295
296public:
297 constexpr SHA2(T a, T b, T c, T d, T e, T f, T g, T h) noexcept :
298 state(a, b, c, d, e, f, g, h), overflow(), overflow_it(overflow.begin()), size(0)
299 {
300 }
301
302 constexpr SHA2 &add(std::byte const *ptr, std::byte const *last, bool finish = true) noexcept
303 {
304 size += last - ptr;
305
306 if (overflow_it != overflow.begin()) {
307 add_to_overflow(ptr, last);
308
309 if (overflow_it == overflow.end()) {
310 add(block_type{overflow.data()});
311 overflow_it = overflow.begin();
312
313 } else {
314 if (finish) {
315 pad();
316 }
317 return *this;
318 }
319 }
320
321 while (ptr + block_type::size <= last) {
322 add(block_type{ptr});
323 ptr += block_type::size;
324 }
325
326 add_to_overflow(ptr, last);
327
328 if (finish) {
329 pad();
330 }
331 return *this;
332 }
333
334 constexpr SHA2 &add(bstring const &str, bool finish = true) noexcept
335 {
336 hilet first = str.data();
337 hilet last = first + str.size();
338 return add(first, last, finish);
339 }
340
341 constexpr SHA2 &add(bstring_view str, bool finish = true) noexcept
342 {
343 hilet first = str.data();
344 hilet last = first + str.size();
345 return add(first, last, finish);
346 }
347
348 constexpr SHA2 &add(std::string const &str, bool finish = true) noexcept
349 {
350 hilet first = reinterpret_cast<std::byte const *>(str.data());
351 hilet last = first + str.size();
352 return add(first, last, finish);
353 }
354
355 constexpr SHA2 &add(std::string_view str, bool finish = true) noexcept
356 {
357 hilet first = reinterpret_cast<std::byte const *>(str.data());
358 hilet last = first + str.size();
359 return add(first, last, finish);
360 }
361
362 constexpr void add(std::span<std::byte const> str, bool finish = true) noexcept
363 {
364 hilet first = reinterpret_cast<std::byte const *>(str.data());
365 hilet last = first + str.size();
366 add(first, last, finish);
367 }
368
369 [[nodiscard]] bstring get_bytes() const noexcept
370 {
371 return state.template get_bytes<Bits / 8>();
372 }
373};
374
375class SHA224 final : public SHA2<uint32_t, 224> {
376public:
377 SHA224()
378 noexcept : SHA2<uint32_t, 224>(0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4)
379 {
380 }
381};
382
383class SHA256 final : public SHA2<uint32_t, 256> {
384public:
385 SHA256()
386 noexcept : SHA2<uint32_t, 256>(0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19)
387 {
388 }
389};
390
391class SHA384 final : public SHA2<uint64_t, 384> {
392public:
393 SHA384()
394 noexcept :
396 0xcbbb9d5dc1059ed8,
397 0x629a292a367cd507,
398 0x9159015a3070dd17,
399 0x152fecd8f70e5939,
400 0x67332667ffc00b31,
401 0x8eb44a8768581511,
402 0xdb0c2e0d64f98fa7,
403 0x47b5481dbefa4fa4)
404 {
405 }
406};
407
408class SHA512 final : public SHA2<uint64_t, 512> {
409public:
410 SHA512()
411 noexcept :
413 0x6a09e667f3bcc908,
414 0xbb67ae8584caa73b,
415 0x3c6ef372fe94f82b,
416 0xa54ff53a5f1d36f1,
417 0x510e527fade682d1,
418 0x9b05688c2b3e6c1f,
419 0x1f83d9abfb41bd6b,
420 0x5be0cd19137e2179)
421 {
422 }
423};
424
425class SHA512_224 final : public SHA2<uint64_t, 224> {
426public:
427 SHA512_224()
428 noexcept :
430 0x8C3D37C819544DA2,
431 0x73E1996689DCD4D6,
432 0x1DFAB7AE32FF9C82,
433 0x679DD514582F9FCF,
434 0x0F6D2B697BD44DA8,
435 0x77E36F7304C48942,
436 0x3F9D85A86A1D36C8,
437 0x1112E6AD91D692A1)
438 {
439 }
440};
441
442class SHA512_256 final : public SHA2<uint64_t, 256> {
443public:
444 SHA512_256()
445 noexcept :
447 0x22312194FC2BF72C,
448 0x9F555FA3C84C64C2,
449 0x2393B86B6F53B151,
450 0x963877195940EABD,
451 0x96283EE2A88EFFE3,
452 0xBE5E1E2553863992,
453 0x2B0199FC2C85B8AA,
454 0x0EB72DDC81C52CA2)
455 {
456 }
457};
458
459} // namespace hi::inline v1
This file includes required definitions.
#define hilet
Invariant should be the default for variables.
Definition required.hpp:23
Definition SHA2.hpp:19
Definition SHA2.hpp:82
Definition SHA2.hpp:118
Definition SHA2.hpp:375
Definition SHA2.hpp:383
Definition SHA2.hpp:391
Definition SHA2.hpp:408
Definition SHA2.hpp:425
Definition SHA2.hpp:442
T begin(T... args)
T data(T... args)
T end(T... args)
T reserve(T... args)
T size(T... args)