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