digestpp 1.0
C++11 header-only message digest library
Loading...
Searching...
No Matches
blake2_provider.hpp
Go to the documentation of this file.
1/*
2This code is written by kerukuro and released into public domain.
3*/
4
5#ifndef DIGESTPP_PROVIDERS_BLAKE2_HPP
6#define DIGESTPP_PROVIDERS_BLAKE2_HPP
7
12#include <array>
13#include <limits>
14
15namespace digestpp
16{
17
18namespace detail
19{
20
21namespace blake2_functions
22{
23 static inline void G(int r, int i, uint64_t& a, uint64_t& b, uint64_t& c, uint64_t& d, uint64_t* M)
24 {
25 a = a + b + M[blake2_constants<void>::S[r][2 * i]];
26 d = rotate_right(d ^ a, 32);
27 c = c + d;
28 b = rotate_right(b ^ c, 24);
29 a = a + b + M[blake2_constants<void>::S[r][2 * i + 1]];
30 d = rotate_right(d ^ a, 16);
31 c = c + d;
32 b = rotate_right(b ^ c, 63);
33 }
34
35 static inline void G(int r, int i, uint32_t& a, uint32_t& b, uint32_t& c, uint32_t& d, uint32_t* M)
36 {
37 a = a + b + M[blake2_constants<void>::S[r][2 * i]];
38 d = rotate_right(d ^ a, 16);
39 c = c + d;
40 b = rotate_right(b ^ c, 12);
41 a = a + b + M[blake2_constants<void>::S[r][2 * i + 1]];
42 d = rotate_right(d ^ a, 8);
43 c = c + d;
44 b = rotate_right(b ^ c, 7);
45 }
46
47 template<typename T>
48 static inline void round(int r, T* M, T* v)
49 {
50 G(r, 0, v[0], v[4], v[8], v[12], M);
51 G(r, 1, v[1], v[5], v[9], v[13], M);
52 G(r, 2, v[2], v[6], v[10], v[14], M);
53 G(r, 3, v[3], v[7], v[11], v[15], M);
54 G(r, 4, v[0], v[5], v[10], v[15], M);
55 G(r, 5, v[1], v[6], v[11], v[12], M);
56 G(r, 6, v[2], v[7], v[8], v[13], M);
57 G(r, 7, v[3], v[4], v[9], v[14], M);
58 }
59
60 template<typename T>
61 inline T IV(int t);
62
63 template<>
64 inline uint32_t IV<uint32_t>(int t)
65 {
67 }
68
69 template<>
70 inline uint64_t IV<uint64_t>(int t)
71 {
73 }
74
75 inline void initH(std::array<uint32_t, 8>& H, uint8_t fanout)
76 {
77 memcpy(&H[0], blake2s_constants<void>::IV, 32);
78 if (!fanout)
79 H[0] ^= 0x01010000ULL;
80 }
81
82 inline void initH(std::array<uint64_t, 8>& H, uint8_t fanout)
83 {
84 memcpy(&H[0], blake2b_constants<void>::IV, 64);
85 if (!fanout)
86 H[0] ^= 0x0000000001010000ULL;
87 }
88
89 inline void initX(std::array<uint32_t, 8>& H, size_t hs, size_t processed, size_t xoffset, uint32_t rhs)
90 {
91 memcpy(&H[0], blake2s_constants<void>::IV, 32);
92 H[0] ^= (rhs == std::numeric_limits<uint32_t>::max() ? static_cast<size_t>(32) : std::min(hs - processed, static_cast<size_t>(32)));
93 H[1] ^= 0x00000020;
94 H[2] ^= xoffset;
95 H[3] ^= 0x20000000;
96 H[3] ^= static_cast<uint16_t>(rhs);
97 }
98
99 inline void initX(std::array<uint64_t, 8>& H, size_t hs, size_t processed, size_t xoffset, uint64_t rhs)
100 {
101 memcpy(&H[0], blake2b_constants<void>::IV, 64);
102 H[0] ^= (rhs == std::numeric_limits<uint64_t>::max() ? static_cast<size_t>(64) : std::min(hs - processed, static_cast<size_t>(64)));
103 H[0] ^= 0x0000004000000000ULL;
104 H[1] ^= xoffset;
105 H[1] ^= rhs << 32;
106 H[2] ^= 0x0000000000004000ULL;
107 }
108
109}
110
111template<typename T, blake2_type type, size_t HS>
112class blake2p_provider;
113
114template<typename T, blake2_type type, size_t HS = 0>
116{
117public:
118 static const bool is_xof = type == blake2_type::xof;
119
120 template<size_t hss=HS, typename std::enable_if<hss == 0>::type* = nullptr>
121 blake2_provider(size_t hashsize = N)
122 : hs(hashsize), squeezing(false)
123 {
124 static_assert(sizeof(T) == 8 || sizeof(T) == 4, "Invalid T size");
125
126 if (type == blake2_type::hash)
127 detail::validate_hash_size(hashsize, N);
128 else if (type == blake2_type::x_hash)
129 detail::validate_hash_size(hashsize, N * sizeof(T) * 4 - 16);
130
131 zero_memory(s);
132 zero_memory(p);
133 fanout = 0;
134 nodedepth = 0;
135 nodeoffset = 0;
136 }
137
138 template<size_t hss=HS, typename std::enable_if<hss != 0>::type* = nullptr>
140 : hs(hss), squeezing(false)
141 {
142 static_assert(sizeof(T) == 8 || sizeof(T) == 4, "Invalid T size");
143
144 const size_t limit = type == blake2_type::hash ? N : type == blake2_type::x_hash ? N * sizeof(T) * 4 - 16 : SIZE_MAX;
145 static_assert(hss <= limit && hss > 0 && hss % 8 == 0);
146
147 zero_memory(s);
148 zero_memory(p);
149 fanout = 0;
150 nodedepth = 0;
151 nodeoffset = 0;
152 }
153
155 {
156 clear();
157 }
158
159 inline void init()
160 {
161 pos = 0;
162 total = 0;
163 xoffset = 0;
164 squeezing = false;
165
166 blake2_functions::initH(H, fanout);
167
168 if (type == blake2_type::hash)
169 H[0] ^= hash_size()/8;
170 else
171 {
172 H[0] ^= N / 8;
173 T rhs = type == blake2_type::x_hash ? static_cast<T>(hs/8) : (static_cast<T>(-1) >> (sizeof(T) * 4));
174 if (N == 512)
175 H[1] ^= (rhs << (N / 16));
176 else
177 H[3] ^= rhs;
178 }
179 H[0] ^= (k.size() << 8);
180 H[4] ^= s[0];
181 H[5] ^= s[1];
182 H[6] ^= p[0];
183 H[7] ^= p[1];
184
185 if (fanout)
186 {
187 H[0] ^= static_cast<T>(fanout) << 16 | static_cast<T>(2) << 24;
188 H[sizeof(T) == 8 ? 1 : 2] ^= static_cast<T>(nodeoffset);
189
190 if (sizeof(T) == 8)
191 H[2] ^= static_cast<T>(nodedepth) | (static_cast<T>(N / 8) << 8);
192 else
193 H[3] ^= static_cast<T>(nodedepth) << 16 | static_cast<T>(N / 8) << 24;
194 }
195
196 if (!fanout || !nodedepth)
197 absorb_key();
198 }
199
200 inline void update(const unsigned char* data, size_t len)
201 {
202 detail::absorb_bytes(data, len, N / 4, N / 4 + 1, m.data(), pos, total,
203 [this](const unsigned char* data, size_t len) { transform(data, len, false); });
204 }
205
206 inline void set_key(const std::string& key)
207 {
208 if (key.length() > N / 8)
209 throw std::runtime_error("invalid key length");
210
211 k = key;
212 }
213
214 inline void set_salt(const unsigned char* salt, size_t salt_len)
215 {
216 if (salt_len && salt_len != N / 32)
217 throw std::runtime_error("invalid salt length");
218
219 memcpy(&s[0], salt, salt_len);
220 }
221
222 inline void set_personalization(const unsigned char* personalization, size_t personalization_len)
223 {
224 if (personalization_len && personalization_len != N / 32)
225 throw std::runtime_error("invalid personalization length");
226
227 memcpy(&p[0], personalization, personalization_len);
228 }
229
230 inline void set_blake2p_params(uint8_t fo, uint8_t nd, uint8_t no)
231 {
232 fanout = fo;
233 nodedepth = nd;
234 nodeoffset = no;
235 }
236
237 inline void squeeze(unsigned char* hash, size_t hs)
238 {
239 size_t processed = 0;
240 if (!squeezing)
241 {
242 if (type == blake2_type::xof)
243 total += pos * 8;
244 squeezing = true;
245 xoffset = 0;
246 if (N / 4 != pos)
247 memset(&m[pos], 0, N / 4 - pos);
248 transform(m.data(), 1, true);
249 memcpy(&m[0], H.data(), N / 8);
250 }
251 else if (pos < N / 8)
252 {
253 size_t to_copy = std::min(hs, N / 8 - pos);
254 memcpy(hash, reinterpret_cast<unsigned char*>(H.data()) + pos, to_copy);
255 processed += to_copy;
256 pos += to_copy;
257 }
258 while (processed < hs)
259 {
260 blake2_functions::initX(H, hs, processed, xoffset++, type == blake2_type::xof ? static_cast<T>(-1) : static_cast<T>(hs));
261 H[4] ^= s[0];
262 H[5] ^= s[1];
263 H[6] ^= p[0];
264 H[7] ^= p[1];
265 total = N;
266 memset(&m[N / 8], 0, m.size() - N / 8);
267 transform(m.data(), 1, true);
268 pos = std::min(hs - processed, N / 8);
269 memcpy(hash + processed, H.data(), pos);
270 processed += pos;
271 }
272 }
273
274 inline void final(unsigned char* hash, size_t hs_override = 0)
275 {
276 total += pos * 8;
277 size_t hss = hs_override ? hs_override : hs;
278 if (type == blake2_type::hash)
279 {
280 if (N / 4 != pos)
281 memset(&m[pos], 0, N / 4 - pos);
282 transform(m.data(), 1, true);
283 memcpy(hash, H.data(), hss / 8);
284 }
285 else
286 squeeze(hash, hss / 8);
287 }
288
289 inline void clear()
290 {
291 zero_memory(H);
292 zero_memory(m);
293 zero_memory(s);
294 zero_memory(p);
295 zero_memory(k);
296 k.clear();
297 fanout = 0;
298 nodedepth = 0;
299 nodeoffset = 0;
300 }
301
302 inline size_t hash_size() const { return hs; }
303
304private:
305 inline void absorb_key()
306 {
307 if (k.empty())
308 return;
309
310 unsigned char key[N / 4];
311 memcpy(key, k.data(), k.length());
312 if (k.length() != N / 4)
313 memset(key + k.length(), 0, N / 4 - k.length());
314 update(key, sizeof(key));
315 }
316
317 inline void transform(const unsigned char* data, size_t num_blks, bool padding)
318 {
319 for (size_t blk = 0; blk < num_blks; blk++)
320 {
321 T M[16];
322 for (int i = 0; i < 16; i++)
323 M[i] = reinterpret_cast<const T*>(data)[blk * 16 + i];
324 uint64_t totalbytes = total / 8 + (padding ? 0 : (blk + 1) * N) / 4;
325 T t0 = static_cast<T>(totalbytes);
326 T t1 = N == 512 ? 0 : static_cast<T>(totalbytes >> 32);
327 T f0 = 0;
328 T f1 = 0;
329 if (padding)
330 {
331 f0 = static_cast<T>(-1);
332 f1 = fanout && (nodeoffset == fanout - 1 || nodedepth) ? static_cast<T>(-1) : 0;
333 }
334
335 T v[16];
336 memcpy(v, H.data(), sizeof(T) * 8);
337 v[8 + 0] = blake2_functions::IV<T>(0);
338 v[8 + 1] = blake2_functions::IV<T>(1);
339 v[8 + 2] = blake2_functions::IV<T>(2);
340 v[8 + 3] = blake2_functions::IV<T>(3);
341 v[12] = t0 ^ blake2_functions::IV<T>(4);
342 v[13] = t1 ^ blake2_functions::IV<T>(5);
343 v[14] = f0 ^ blake2_functions::IV<T>(6);
344 v[15] = f1 ^ blake2_functions::IV<T>(7);
345
356 if (N == 512)
357 {
358 blake2_functions::round(10, M, v);
359 blake2_functions::round(11, M, v);
360 }
361
362 H[0] = H[0] ^ v[0] ^ v[0 + 8];
363 H[0 + 4] = H[0 + 4] ^ v[0 + 4] ^ v[0 + 8 + 4];
364 H[1] = H[1] ^ v[1] ^ v[1 + 8];
365 H[1 + 4] = H[1 + 4] ^ v[1 + 4] ^ v[1 + 8 + 4];
366 H[2] = H[2] ^ v[2] ^ v[2 + 8];
367 H[2 + 4] = H[2 + 4] ^ v[2 + 4] ^ v[2 + 8 + 4];
368 H[3] = H[3] ^ v[3] ^ v[3 + 8];
369 H[3 + 4] = H[3 + 4] ^ v[3 + 4] ^ v[3 + 8 + 4];
370 }
371
372 }
373
374 friend class blake2p_provider<T, type, HS>;
375
376 constexpr static size_t N = sizeof(T) == 8 ? 512 : 256;
377 std::array<T, 8> H;
378 std::array<T, 2> s;
379 std::array<T, 2> p;
380 std::string k;
381 std::array<unsigned char, N / 4> m;
382 size_t pos;
383 uint64_t total;
384 size_t hs;
385 size_t xoffset;
386 bool squeezing;
387 uint8_t fanout;
388 uint8_t nodedepth;
389 uint8_t nodeoffset;
390};
391
392} // namespace detail
393
394} // namespace digestpp
395
396#endif
Definition blake2_provider.hpp:116
void set_salt(const unsigned char *salt, size_t salt_len)
Definition blake2_provider.hpp:214
void squeeze(unsigned char *hash, size_t hs)
Definition blake2_provider.hpp:237
blake2_provider()
Definition blake2_provider.hpp:139
void set_key(const std::string &key)
Definition blake2_provider.hpp:206
void init()
Definition blake2_provider.hpp:159
blake2_provider(size_t hashsize=N)
Definition blake2_provider.hpp:121
void update(const unsigned char *data, size_t len)
Definition blake2_provider.hpp:200
void set_blake2p_params(uint8_t fo, uint8_t nd, uint8_t no)
Definition blake2_provider.hpp:230
~blake2_provider()
Definition blake2_provider.hpp:154
size_t hash_size() const
Definition blake2_provider.hpp:302
void clear()
Definition blake2_provider.hpp:289
void set_personalization(const unsigned char *personalization, size_t personalization_len)
Definition blake2_provider.hpp:222
Definition blake2p_provider.hpp:23
void initH(std::array< uint32_t, 8 > &H, uint8_t fanout)
Definition blake2_provider.hpp:75
static void round(int r, T *M, T *v)
Definition blake2_provider.hpp:48
uint64_t IV< uint64_t >(int t)
Definition blake2_provider.hpp:70
uint32_t IV< uint32_t >(int t)
Definition blake2_provider.hpp:64
void initX(std::array< uint32_t, 8 > &H, size_t hs, size_t processed, size_t xoffset, uint32_t rhs)
Definition blake2_provider.hpp:89
static void G(int r, int i, uint64_t &a, uint64_t &b, uint64_t &c, uint64_t &d, uint64_t *M)
Definition blake2_provider.hpp:23
uint32_t rotate_right(uint32_t x, unsigned n)
Definition functions.hpp:61
void validate_hash_size(size_t hs, std::initializer_list< size_t > set)
Definition validate_hash_size.hpp:14
void zero_memory(void *v, size_t n)
Definition functions.hpp:85
void absorb_bytes(const unsigned char *data, size_t len, size_t bs, size_t bschk, unsigned char *m, size_t &pos, T &total, TF transform)
Definition absorb_data.hpp:16
digestpp namespace
Definition ascon.hpp:14
Definition blake2_constants.hpp:39
Definition blake2_constants.hpp:16
Definition blake2_constants.hpp:28
Definition traits.hpp:17