digestpp 1.0
C++11 header-only message digest library
Loading...
Searching...
No Matches
blake_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_BLAKE_HPP
6#define DIGESTPP_PROVIDERS_BLAKE_HPP
7
12#include <array>
13
14namespace digestpp
15{
16
17namespace detail
18{
19
20namespace blake_functions
21{
22 static inline void G(int r, int i, uint32_t& a, uint32_t& b, uint32_t& c, uint32_t& d, uint32_t* M)
23 {
24 a = a + b + (M[blake_constants<void>::S[r % 10][2 * i]]
26 d = rotate_right(d ^ a, 16);
27 c = c + d;
28 b = rotate_right(b ^ c, 12);
29 a = a + b + (M[blake_constants<void>::S[r % 10][2 * i + 1]]
31 d = rotate_right(d ^ a, 8);
32 c = c + d;
33 b = rotate_right(b ^ c, 7);
34 }
35
36 static inline void G(int r, int i, uint64_t& a, uint64_t& b, uint64_t& c, uint64_t& d, uint64_t* M)
37 {
38 a = a + b + (M[blake_constants<void>::S[r % 10][2 * i]]
40 d = rotate_right(d ^ a, 32);
41 c = c + d;
42 b = rotate_right(b ^ c, 25);
43 a = a + b + (M[blake_constants<void>::S[r % 10][2 * i + 1]]
45 d = rotate_right(d ^ a, 16);
46 c = c + d;
47 b = rotate_right(b ^ c, 11);
48 }
49
50 template<typename T>
51 static inline void round(int r, T* M, T* v)
52 {
53 G(r, 0, v[0], v[4], v[8], v[12], M);
54 G(r, 1, v[1], v[5], v[9], v[13], M);
55 G(r, 2, v[2], v[6], v[10], v[14], M);
56 G(r, 3, v[3], v[7], v[11], v[15], M);
57 G(r, 4, v[0], v[5], v[10], v[15], M);
58 G(r, 5, v[1], v[6], v[11], v[12], M);
59 G(r, 6, v[2], v[7], v[8], v[13], M);
60 G(r, 7, v[3], v[4], v[9], v[14], M);
61 }
62
63 template<typename T>
64 inline T C(int t);
65
66 template<>
67 inline uint32_t C<uint32_t>(int t)
68 {
70 }
71
72 template<>
73 inline uint64_t C<uint64_t>(int t)
74 {
76 }
77
78 template<typename T>
79 inline void transform(const unsigned char* data, size_t num_blks, bool padding, std::array<T, 12>& H, uint64_t total, bool final)
80 {
81 for (size_t blk = 0; blk < num_blks; blk++)
82 {
83 T M[16];
84 for (int i = 0; i < 16; i++)
85 M[i] = byteswap(reinterpret_cast<const T*>(data)[blk * 16 + i]);
86
87 uint64_t totalbytes = total + (!final ? (blk + 1) * sizeof(M) * 8 : 0);
88 T t0 = static_cast<T>(totalbytes);
89 T t1 = sizeof(T) == 8 ? 0 : static_cast<T>(totalbytes >> 32);
90 if (padding)
91 t0 = t1 = 0;
92
93 T v[16];
94 memcpy(v, H.data(), sizeof(T) * 8);
95 v[8 + 0] = H[8] ^ C<T>(0);
96 v[8 + 1] = H[9] ^ C<T>(1);
97 v[8 + 2] = H[10] ^ C<T>(2);
98 v[8 + 3] = H[11] ^ C<T>(3);
99 v[12] = t0 ^ C<T>(4);
100 v[13] = t0 ^ C<T>(5);
101 v[14] = t1 ^ C<T>(6);
102 v[15] = t1 ^ C<T>(7);
103
104 // The loop is fully unrolled for performance reasons
105 round(0, M, v);
106 round(1, M, v);
107 round(2, M, v);
108 round(3, M, v);
109 round(4, M, v);
110 round(5, M, v);
111 round(6, M, v);
112 round(7, M, v);
113 round(8, M, v);
114 round(9, M, v);
115 round(10, M, v);
116 round(11, M, v);
117 round(12, M, v);
118 round(13, M, v);
119 if (sizeof(T) == 8)
120 {
121 round(14, M, v);
122 round(15, M, v);
123 }
124
125 H[0] = H[0] ^ H[8] ^ v[0] ^ v[0 + 8];
126 H[0 + 4] = H[0 + 4] ^ H[8] ^ v[0 + 4] ^ v[0 + 8 + 4];
127 H[1] = H[1] ^ H[9] ^ v[1] ^ v[1 + 8];
128 H[1 + 4] = H[1 + 4] ^ H[9] ^ v[1 + 4] ^ v[1 + 8 + 4];
129 H[2] = H[2] ^ H[10] ^ v[2] ^ v[2 + 8];
130 H[2 + 4] = H[2 + 4] ^ H[10] ^ v[2 + 4] ^ v[2 + 8 + 4];
131 H[3] = H[3] ^ H[11] ^ v[3] ^ v[3 + 8];
132 H[3 + 4] = H[3 + 4] ^ H[11] ^ v[3 + 4] ^ v[3 + 8 + 4];
133 }
134 }
135
136 template<typename T>
137 inline void set_salt(std::array<T, 12>& H, const unsigned char* salt, size_t saltlen)
138 {
139 if (saltlen)
140 for (int i = 0; i < 4; i++)
141 H[8 + i] = byteswap(reinterpret_cast<const T*>(salt)[i]);
142 else
143 H[8] = H[9] = H[10] = H[11] = 0;
144 }
145}
146
147template<size_t HS = 0>
149{
150public:
151 static const bool is_xof = false;
152
153 template<size_t hss=HS, typename std::enable_if<hss == 0>::type* = nullptr>
154 blake_provider(size_t hashsize)
155 : hs(hashsize)
156 {
157 validate_hash_size(hashsize, {224, 256, 384, 512});
158 zero_memory(u.H512);
159 }
160
161 template<size_t hss=HS, typename std::enable_if<hss != 0>::type* = nullptr>
163 : hs(hss)
164 {
165 static_assert(hss == 224 || hss == 256 || hss == 384 || hss == 512);
166 zero_memory(u.H512);
167 }
168
170 {
171 clear();
172 }
173
174 inline void init()
175 {
176 pos = 0;
177 total = 0;
178
179 switch(hs)
180 {
181 case 512:
182 u.H512[0] = 0x6A09E667F3BCC908ull;
183 u.H512[1] = 0xBB67AE8584CAA73Bull;
184 u.H512[2] = 0x3C6EF372FE94F82Bull;
185 u.H512[3] = 0xA54FF53A5F1D36F1ull;
186 u.H512[4] = 0x510E527FADE682D1ull;
187 u.H512[5] = 0x9B05688C2B3E6C1Full;
188 u.H512[6] = 0x1F83D9ABFB41BD6Bull;
189 u.H512[7] = 0x5BE0CD19137E2179ull;
190 break;
191 case 384:
192 u.H512[0] = 0xcbbb9d5dc1059ed8ull;
193 u.H512[1] = 0x629a292a367cd507ull;
194 u.H512[2] = 0x9159015a3070dd17ull;
195 u.H512[3] = 0x152fecd8f70e5939ull;
196 u.H512[4] = 0x67332667ffc00b31ull;
197 u.H512[5] = 0x8eb44a8768581511ull;
198 u.H512[6] = 0xdb0c2e0d64f98fa7ull;
199 u.H512[7] = 0x47b5481dbefa4fa4ull;
200 break;
201 case 256:
202 u.H256[0] = 0x6a09e667;
203 u.H256[1] = 0xbb67ae85;
204 u.H256[2] = 0x3c6ef372;
205 u.H256[3] = 0xa54ff53a;
206 u.H256[4] = 0x510e527f;
207 u.H256[5] = 0x9b05688c;
208 u.H256[6] = 0x1f83d9ab;
209 u.H256[7] = 0x5be0cd19;
210 break;
211 case 224:
212 u.H256[0] = 0xC1059ED8;
213 u.H256[1] = 0x367CD507;
214 u.H256[2] = 0x3070DD17;
215 u.H256[3] = 0xF70E5939;
216 u.H256[4] = 0xFFC00B31;
217 u.H256[5] = 0x68581511;
218 u.H256[6] = 0x64F98FA7;
219 u.H256[7] = 0xBEFA4FA4;
220 break;
221 }
222 }
223
224 inline void update(const unsigned char* data, size_t len)
225 {
226 detail::absorb_bytes(data, len, block_bytes(), block_bytes(), m.data(), pos, total,
227 [this](const unsigned char* data, size_t len) { transform(data, len, false, false); });
228 }
229
230 inline void set_salt(const unsigned char* salt, size_t salt_len)
231 {
232 if (salt_len && ((hs > 256 && salt_len != 32) || (hs <= 256 && salt_len != 16)))
233 throw std::runtime_error("invalid salt length");
234
235 if (hs > 256)
236 blake_functions::set_salt(u.H512, salt, salt_len);
237 else
238 blake_functions::set_salt(u.H256, salt, salt_len);
239 }
240
241 inline void final(unsigned char* hash)
242 {
243 size_t messageend = hs > 256 ? 111 : 55;
244 bool truncated = hs != 512 && hs != 256;
245 bool padding = !pos;
246 total += 8 * pos;
247 m[pos] = pos == messageend && !truncated ? 0x81 : 0x80;
248 if (pos++ > messageend)
249 {
250 if (block_bytes() != pos)
251 memset(&m[pos], 0, block_bytes() - pos);
252 transform(m.data(), 1, false, true);
253 pos = 0;
254 padding = true;
255 }
256 if (pos <= messageend)
257 {
258 memset(&m[pos], 0, messageend - pos);
259 m[messageend] = truncated ? 0x00 : 0x01;
260 }
261 uint64_t mlen = byteswap(total);
262 if (block_bytes() == 128)
263 memset(&m[128 - 16], 0, sizeof(uint64_t));
264 memcpy(&m[block_bytes() - 8], &mlen, sizeof(uint64_t));
265 transform(m.data(), 1, padding, true);
266 if (hs > 256)
267 {
268 for (int i = 0; i < 8; i++)
269 u.H512[i] = byteswap(u.H512[i]);
270 memcpy(hash, u.H512.data(), hash_size()/8);
271 }
272 else
273 {
274 for (int i = 0; i < 8; i++)
275 u.H256[i] = byteswap(u.H256[i]);
276 memcpy(hash, u.H256.data(), hash_size()/8);
277 }
278 }
279
280 inline void clear()
281 {
282 zero_memory(u.H512);
283 zero_memory(m);
284 }
285
286 inline size_t hash_size() const { return hs; }
287
288private:
289 inline size_t block_bytes() const { return hs > 256 ? 128 : 64; }
290
291 inline void transform(const unsigned char* mp, size_t num_blks, bool padding, bool final)
292 {
293 if (hs > 256)
294 blake_functions::transform(mp, num_blks, padding, u.H512, total, final);
295 else
296 blake_functions::transform(mp, num_blks, padding, u.H256, total, final);
297 }
298
299 union { std::array<uint64_t, 12> H512; std::array<uint32_t, 12> H256; } u;
300 std::array<unsigned char, 128> m;
301 size_t hs;
302 size_t pos;
303 uint64_t total;
304
305};
306
307} // namespace detail
308
309} // namespace digestpp
310
311#endif
Definition blake_provider.hpp:149
blake_provider()
Definition blake_provider.hpp:162
blake_provider(size_t hashsize)
Definition blake_provider.hpp:154
~blake_provider()
Definition blake_provider.hpp:169
void update(const unsigned char *data, size_t len)
Definition blake_provider.hpp:224
void clear()
Definition blake_provider.hpp:280
void set_salt(const unsigned char *salt, size_t salt_len)
Definition blake_provider.hpp:230
std::array< uint32_t, 12 > H256
Definition blake_provider.hpp:299
std::array< uint64_t, 12 > H512
Definition blake_provider.hpp:299
size_t hash_size() const
Definition blake_provider.hpp:286
void init()
Definition blake_provider.hpp:174
static void G(int r, int i, uint32_t &a, uint32_t &b, uint32_t &c, uint32_t &d, uint32_t *M)
Definition blake_provider.hpp:22
uint64_t C< uint64_t >(int t)
Definition blake_provider.hpp:73
void set_salt(std::array< T, 12 > &H, const unsigned char *salt, size_t saltlen)
Definition blake_provider.hpp:137
uint32_t C< uint32_t >(int t)
Definition blake_provider.hpp:67
static void round(int r, T *M, T *v)
Definition blake_provider.hpp:51
void transform(const unsigned char *data, size_t num_blks, bool padding, std::array< T, 12 > &H, uint64_t total, bool final)
Definition blake_provider.hpp:79
uint16_t byteswap(uint16_t val)
Definition functions.hpp:16
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 blake_constants.hpp:16
Definition traits.hpp:17