/src/serenity/Userland/Libraries/LibCrypto/Hash/BLAKE2b.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2023, the SerenityOS developers |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include <AK/ByteReader.h> |
8 | | #include <LibCrypto/Hash/BLAKE2b.h> |
9 | | |
10 | | namespace Crypto::Hash { |
11 | 53.7M | constexpr static auto ROTRIGHT(u64 a, size_t b) { return (a >> b) | (a << (64 - b)); } |
12 | | |
13 | | void BLAKE2b::update(u8 const* in, size_t inlen) |
14 | 104 | { |
15 | 104 | if (inlen > 0) { |
16 | 104 | size_t left = m_internal_state.buffer_length; |
17 | 104 | size_t fill = BLAKE2bConstants::blockbytes - left; |
18 | 104 | if (inlen > fill) { |
19 | 91 | m_internal_state.buffer_length = 0; |
20 | | // Fill the buffer. |
21 | 91 | __builtin_memcpy(m_internal_state.buffer + left, in, fill); |
22 | | |
23 | 91 | increment_counter_by(BLAKE2bConstants::blockbytes); |
24 | 91 | transform(m_internal_state.buffer); |
25 | 91 | in += fill; |
26 | 91 | inlen -= fill; |
27 | 139k | while (inlen > BLAKE2bConstants::blockbytes) { |
28 | 139k | increment_counter_by(BLAKE2bConstants::blockbytes); |
29 | 139k | transform(in); |
30 | 139k | in += BLAKE2bConstants::blockbytes; |
31 | 139k | inlen -= BLAKE2bConstants::blockbytes; |
32 | 139k | } |
33 | 91 | } |
34 | 104 | __builtin_memcpy(m_internal_state.buffer + m_internal_state.buffer_length, in, inlen); |
35 | 104 | m_internal_state.buffer_length += inlen; |
36 | 104 | } |
37 | 104 | } |
38 | | |
39 | | BLAKE2b::DigestType BLAKE2b::peek() |
40 | 104 | { |
41 | 104 | DigestType digest; |
42 | 104 | increment_counter_by(m_internal_state.buffer_length); |
43 | | |
44 | | // Set this as the last block |
45 | 104 | m_internal_state.is_at_last_block = UINT64_MAX; |
46 | | |
47 | | // Pad the buffer with zeros |
48 | 104 | __builtin_memset(m_internal_state.buffer + m_internal_state.buffer_length, 0, BLAKE2bConstants::blockbytes - m_internal_state.buffer_length); |
49 | 104 | transform(m_internal_state.buffer); |
50 | | |
51 | 936 | for (size_t i = 0; i < 8; ++i) |
52 | 832 | __builtin_memcpy(&digest.data[0] + sizeof(m_internal_state.hash_state[i]) * i, &m_internal_state.hash_state[i], sizeof(m_internal_state.hash_state[i])); |
53 | | |
54 | 104 | return digest; |
55 | 104 | } |
56 | | |
57 | | BLAKE2b::DigestType BLAKE2b::digest() |
58 | 104 | { |
59 | 104 | auto digest = peek(); |
60 | 104 | reset(); |
61 | 104 | return digest; |
62 | 104 | } |
63 | | |
64 | | void BLAKE2b::increment_counter_by(u64 const amount) |
65 | 139k | { |
66 | 139k | m_internal_state.message_byte_offset[0] += amount; |
67 | 139k | m_internal_state.message_byte_offset[1] += (m_internal_state.message_byte_offset[0] < amount); |
68 | 139k | } |
69 | | |
70 | | void BLAKE2b::mix(u64* work_array, u64 a, u64 b, u64 c, u64 d, u64 x, u64 y) |
71 | 13.4M | { |
72 | 13.4M | constexpr auto rotation_constant_1 = 32; |
73 | 13.4M | constexpr auto rotation_constant_2 = 24; |
74 | 13.4M | constexpr auto rotation_constant_3 = 16; |
75 | 13.4M | constexpr auto rotation_constant_4 = 63; |
76 | | |
77 | 13.4M | work_array[a] = work_array[a] + work_array[b] + x; |
78 | 13.4M | work_array[d] = ROTRIGHT(work_array[d] ^ work_array[a], rotation_constant_1); |
79 | 13.4M | work_array[c] = work_array[c] + work_array[d]; |
80 | 13.4M | work_array[b] = ROTRIGHT(work_array[b] ^ work_array[c], rotation_constant_2); |
81 | 13.4M | work_array[a] = work_array[a] + work_array[b] + y; |
82 | 13.4M | work_array[d] = ROTRIGHT(work_array[d] ^ work_array[a], rotation_constant_3); |
83 | 13.4M | work_array[c] = work_array[c] + work_array[d]; |
84 | 13.4M | work_array[b] = ROTRIGHT(work_array[b] ^ work_array[c], rotation_constant_4); |
85 | 13.4M | } |
86 | | |
87 | | void BLAKE2b::transform(u8 const* block) |
88 | 139k | { |
89 | 139k | u64 m[16]; |
90 | 139k | u64 v[16]; |
91 | | |
92 | 2.37M | for (size_t i = 0; i < 16; ++i) |
93 | 2.23M | m[i] = ByteReader::load64(block + i * sizeof(m[i])); |
94 | | |
95 | 1.25M | for (size_t i = 0; i < 8; ++i) |
96 | 1.11M | v[i] = m_internal_state.hash_state[i]; |
97 | | |
98 | 139k | v[8] = SHA512Constants::InitializationHashes[0]; |
99 | 139k | v[9] = SHA512Constants::InitializationHashes[1]; |
100 | 139k | v[10] = SHA512Constants::InitializationHashes[2]; |
101 | 139k | v[11] = SHA512Constants::InitializationHashes[3]; |
102 | 139k | v[12] = SHA512Constants::InitializationHashes[4] ^ m_internal_state.message_byte_offset[0]; |
103 | 139k | v[13] = SHA512Constants::InitializationHashes[5] ^ m_internal_state.message_byte_offset[1]; |
104 | 139k | v[14] = SHA512Constants::InitializationHashes[6] ^ m_internal_state.is_at_last_block; |
105 | 139k | v[15] = SHA512Constants::InitializationHashes[7]; |
106 | | |
107 | 1.81M | for (size_t i = 0; i < 12; ++i) { |
108 | 1.67M | u64 sigma_selection[16]; |
109 | 28.5M | for (size_t j = 0; j < 16; ++j) |
110 | 26.8M | sigma_selection[j] = BLAKE2bSigma[i % 10][j]; |
111 | 1.67M | mix(v, 0, 4, 8, 12, m[sigma_selection[0]], m[sigma_selection[1]]); |
112 | 1.67M | mix(v, 1, 5, 9, 13, m[sigma_selection[2]], m[sigma_selection[3]]); |
113 | 1.67M | mix(v, 2, 6, 10, 14, m[sigma_selection[4]], m[sigma_selection[5]]); |
114 | 1.67M | mix(v, 3, 7, 11, 15, m[sigma_selection[6]], m[sigma_selection[7]]); |
115 | | |
116 | 1.67M | mix(v, 0, 5, 10, 15, m[sigma_selection[8]], m[sigma_selection[9]]); |
117 | 1.67M | mix(v, 1, 6, 11, 12, m[sigma_selection[10]], m[sigma_selection[11]]); |
118 | 1.67M | mix(v, 2, 7, 8, 13, m[sigma_selection[12]], m[sigma_selection[13]]); |
119 | 1.67M | mix(v, 3, 4, 9, 14, m[sigma_selection[14]], m[sigma_selection[15]]); |
120 | 1.67M | } |
121 | | |
122 | 1.25M | for (size_t i = 0; i < 8; ++i) |
123 | 1.11M | m_internal_state.hash_state[i] = m_internal_state.hash_state[i] ^ v[i] ^ v[i + 8]; |
124 | 139k | } |
125 | | |
126 | | } |