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