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