/src/wolfssl-heapmath/wolfcrypt/src/blake2s.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | BLAKE2 reference source code package - reference C implementations |
3 | | |
4 | | Written in 2012 by Samuel Neves <sneves@dei.uc.pt> |
5 | | |
6 | | To the extent possible under law, the author(s) have dedicated all copyright |
7 | | and related and neighboring rights to this software to the public domain |
8 | | worldwide. This software is distributed without any warranty. |
9 | | |
10 | | You should have received a copy of the CC0 Public Domain Dedication along with |
11 | | this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. |
12 | | */ |
13 | | /* blake2s.c |
14 | | * |
15 | | * Copyright (C) 2006-2025 wolfSSL Inc. |
16 | | * |
17 | | * This file is part of wolfSSL. |
18 | | * |
19 | | * wolfSSL is free software; you can redistribute it and/or modify |
20 | | * it under the terms of the GNU General Public License as published by |
21 | | * the Free Software Foundation; either version 3 of the License, or |
22 | | * (at your option) any later version. |
23 | | * |
24 | | * wolfSSL is distributed in the hope that it will be useful, |
25 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
26 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
27 | | * GNU General Public License for more details. |
28 | | * |
29 | | * You should have received a copy of the GNU General Public License |
30 | | * along with this program; if not, write to the Free Software |
31 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA |
32 | | */ |
33 | | |
34 | | #include <wolfssl/wolfcrypt/libwolfssl_sources.h> |
35 | | |
36 | | #ifdef HAVE_BLAKE2S |
37 | | |
38 | | #include <wolfssl/wolfcrypt/blake2.h> |
39 | | #include <wolfssl/wolfcrypt/blake2-impl.h> |
40 | | |
41 | | static const word32 blake2s_IV[8] = |
42 | | { |
43 | | 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, |
44 | | 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 |
45 | | }; |
46 | | |
47 | | static const byte blake2s_sigma[10][16] = |
48 | | { |
49 | | { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , |
50 | | { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , |
51 | | { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , |
52 | | { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , |
53 | | { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , |
54 | | { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , |
55 | | { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , |
56 | | { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , |
57 | | { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , |
58 | | { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } |
59 | | }; |
60 | | |
61 | | |
62 | | static WC_INLINE int blake2s_set_lastnode( blake2s_state *S ) |
63 | 0 | { |
64 | 0 | S->f[1] = ~0U; |
65 | 0 | return 0; |
66 | 0 | } |
67 | | |
68 | | /* Some helper functions, not necessarily useful */ |
69 | | static WC_INLINE int blake2s_set_lastblock( blake2s_state *S ) |
70 | 0 | { |
71 | 0 | if( S->last_node ) blake2s_set_lastnode( S ); |
72 | |
|
73 | 0 | S->f[0] = ~0U; |
74 | 0 | return 0; |
75 | 0 | } |
76 | | |
77 | | static WC_INLINE int blake2s_increment_counter( blake2s_state *S, const word32 |
78 | | inc ) |
79 | 0 | { |
80 | 0 | S->t[0] += inc; |
81 | 0 | S->t[1] += ( S->t[0] < inc ); |
82 | 0 | return 0; |
83 | 0 | } |
84 | | |
85 | | static WC_INLINE int blake2s_init0( blake2s_state *S ) |
86 | 0 | { |
87 | 0 | int i; |
88 | 0 | XMEMSET( S, 0, sizeof( blake2s_state ) ); |
89 | |
|
90 | 0 | for( i = 0; i < 8; ++i ) S->h[i] = blake2s_IV[i]; |
91 | |
|
92 | 0 | return 0; |
93 | 0 | } |
94 | | |
95 | | /* init xors IV with input parameter block */ |
96 | | int blake2s_init_param( blake2s_state *S, const blake2s_param *P ) |
97 | 0 | { |
98 | 0 | word32 i; |
99 | 0 | byte *p ; |
100 | 0 | blake2s_init0( S ); |
101 | 0 | p = ( byte * )( P ); |
102 | | |
103 | | /* IV XOR ParamBlock */ |
104 | 0 | for( i = 0; i < 8; ++i ) |
105 | 0 | S->h[i] ^= load32( p + sizeof( S->h[i] ) * i ); |
106 | |
|
107 | 0 | return 0; |
108 | 0 | } |
109 | | |
110 | | |
111 | | |
112 | | int blake2s_init( blake2s_state *S, const byte outlen ) |
113 | 0 | { |
114 | | #ifdef WOLFSSL_BLAKE2S_INIT_EACH_FIELD |
115 | | blake2s_param P[1]; |
116 | | #else |
117 | 0 | volatile blake2s_param P[1]; |
118 | 0 | #endif |
119 | |
|
120 | 0 | if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return BAD_FUNC_ARG; |
121 | | |
122 | | #ifdef WOLFSSL_BLAKE2S_INIT_EACH_FIELD |
123 | | P->digest_length = outlen; |
124 | | P->key_length = 0; |
125 | | P->fanout = 1; |
126 | | P->depth = 1; |
127 | | store32( &P->leaf_length, 0 ); |
128 | | store32( &P->node_offset, 0 ); |
129 | | P->node_depth = 0; |
130 | | P->inner_length = 0; |
131 | | XMEMSET( P->salt, 0, sizeof( P->salt ) ); |
132 | | XMEMSET( P->personal, 0, sizeof( P->personal ) ); |
133 | | #else |
134 | 0 | XMEMSET( (blake2s_param *)P, 0, sizeof( *P ) ); |
135 | 0 | P->digest_length = outlen; |
136 | 0 | P->fanout = 1; |
137 | 0 | P->depth = 1; |
138 | 0 | #endif |
139 | 0 | return blake2s_init_param( S, (blake2s_param *)P ); |
140 | 0 | } |
141 | | |
142 | | |
143 | | int blake2s_init_key( blake2s_state *S, const byte outlen, const void *key, |
144 | | const byte keylen ) |
145 | 0 | { |
146 | 0 | int ret = 0; |
147 | | #ifdef WOLFSSL_BLAKE2S_INIT_EACH_FIELD |
148 | | blake2s_param P[1]; |
149 | | #else |
150 | 0 | volatile blake2s_param P[1]; |
151 | 0 | #endif |
152 | |
|
153 | 0 | if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return BAD_FUNC_ARG; |
154 | | |
155 | 0 | if ( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return BAD_FUNC_ARG; |
156 | | |
157 | | #ifdef WOLFSSL_BLAKE2S_INIT_EACH_FIELD |
158 | | P->digest_length = outlen; |
159 | | P->key_length = keylen; |
160 | | P->fanout = 1; |
161 | | P->depth = 1; |
162 | | store32( &P->leaf_length, 0 ); |
163 | | store64( &P->node_offset, 0 ); |
164 | | P->node_depth = 0; |
165 | | P->inner_length = 0; |
166 | | XMEMSET( P->salt, 0, sizeof( P->salt ) ); |
167 | | XMEMSET( P->personal, 0, sizeof( P->personal ) ); |
168 | | #else |
169 | 0 | XMEMSET( (blake2s_param *)P, 0, sizeof( *P ) ); |
170 | 0 | P->digest_length = outlen; |
171 | 0 | P->key_length = keylen; |
172 | 0 | P->fanout = 1; |
173 | 0 | P->depth = 1; |
174 | 0 | #endif |
175 | |
|
176 | 0 | ret = blake2s_init_param( S, (blake2s_param *)P ); |
177 | 0 | if (ret < 0) |
178 | 0 | return ret; |
179 | | |
180 | 0 | { |
181 | 0 | #ifdef WOLFSSL_SMALL_STACK |
182 | 0 | byte* block; |
183 | |
|
184 | 0 | block = (byte*)XMALLOC(BLAKE2S_BLOCKBYTES, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
185 | |
|
186 | 0 | if ( block == NULL ) return MEMORY_E; |
187 | | #else |
188 | | byte block[BLAKE2S_BLOCKBYTES]; |
189 | | #endif |
190 | | |
191 | 0 | XMEMSET( block, 0, BLAKE2S_BLOCKBYTES ); |
192 | 0 | XMEMCPY( block, key, keylen ); |
193 | 0 | ret = blake2s_update( S, block, BLAKE2S_BLOCKBYTES ); |
194 | 0 | secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from */ |
195 | | /* memory */ |
196 | |
|
197 | 0 | #ifdef WOLFSSL_SMALL_STACK |
198 | 0 | XFREE(block, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
199 | 0 | #endif |
200 | 0 | } |
201 | 0 | return ret; |
202 | 0 | } |
203 | | |
204 | | static WC_INLINE int blake2s_compress( |
205 | | blake2s_state *S, |
206 | | const byte block[BLAKE2S_BLOCKBYTES], |
207 | | word32* m, |
208 | | word32* v) |
209 | 0 | { |
210 | 0 | word32 i; |
211 | |
|
212 | 0 | for( i = 0; i < 16; ++i ) |
213 | 0 | m[i] = load32( block + i * sizeof( m[i] ) ); |
214 | |
|
215 | 0 | for( i = 0; i < 8; ++i ) |
216 | 0 | v[i] = S->h[i]; |
217 | |
|
218 | 0 | v[ 8] = blake2s_IV[0]; |
219 | 0 | v[ 9] = blake2s_IV[1]; |
220 | 0 | v[10] = blake2s_IV[2]; |
221 | 0 | v[11] = blake2s_IV[3]; |
222 | 0 | v[12] = S->t[0] ^ blake2s_IV[4]; |
223 | 0 | v[13] = S->t[1] ^ blake2s_IV[5]; |
224 | 0 | v[14] = S->f[0] ^ blake2s_IV[6]; |
225 | 0 | v[15] = S->f[1] ^ blake2s_IV[7]; |
226 | 0 | #define G(r,i,a,b,c,d) \ |
227 | 0 | do { \ |
228 | 0 | (a) = (a) + (b) + m[blake2s_sigma[r][2*(i)+0]]; \ |
229 | 0 | (d) = rotr32((d) ^ (a), 16); \ |
230 | 0 | (c) = (c) + (d); \ |
231 | 0 | (b) = rotr32((b) ^ (c), 12); \ |
232 | 0 | (a) = (a) + (b) + m[blake2s_sigma[r][2*(i)+1]]; \ |
233 | 0 | (d) = rotr32((d) ^ (a), 8); \ |
234 | 0 | (c) = (c) + (d); \ |
235 | 0 | (b) = rotr32((b) ^ (c), 7); \ |
236 | 0 | } while(0) |
237 | 0 | #define ROUND(r) \ |
238 | 0 | do { \ |
239 | 0 | G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ |
240 | 0 | G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ |
241 | 0 | G(r,2,v[ 2],v[ 6],v[10],v[14]); \ |
242 | 0 | G(r,3,v[ 3],v[ 7],v[11],v[15]); \ |
243 | 0 | G(r,4,v[ 0],v[ 5],v[10],v[15]); \ |
244 | 0 | G(r,5,v[ 1],v[ 6],v[11],v[12]); \ |
245 | 0 | G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ |
246 | 0 | G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ |
247 | 0 | } while(0) |
248 | 0 | ROUND( 0 ); |
249 | 0 | ROUND( 1 ); |
250 | 0 | ROUND( 2 ); |
251 | 0 | ROUND( 3 ); |
252 | 0 | ROUND( 4 ); |
253 | 0 | ROUND( 5 ); |
254 | 0 | ROUND( 6 ); |
255 | 0 | ROUND( 7 ); |
256 | 0 | ROUND( 8 ); |
257 | 0 | ROUND( 9 ); |
258 | |
|
259 | 0 | for( i = 0; i < 8; ++i ) |
260 | 0 | S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; |
261 | |
|
262 | 0 | #undef G |
263 | 0 | #undef ROUND |
264 | |
|
265 | 0 | return 0; |
266 | 0 | } |
267 | | |
268 | | /* inlen now in bytes */ |
269 | | int blake2s_update( blake2s_state *S, const byte *in, word32 inlen ) |
270 | 0 | { |
271 | 0 | int ret = 0; |
272 | 0 | #ifdef WOLFSSL_SMALL_STACK |
273 | 0 | word32* m; |
274 | 0 | word32* v; |
275 | |
|
276 | 0 | m = (word32*)XMALLOC(sizeof(word32) * 32, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
277 | |
|
278 | 0 | if ( m == NULL ) return MEMORY_E; |
279 | | |
280 | 0 | v = &m[16]; |
281 | | #else |
282 | | word32 m[16]; |
283 | | word32 v[16]; |
284 | | #endif |
285 | |
|
286 | 0 | while( inlen > 0 ) |
287 | 0 | { |
288 | 0 | word32 left = S->buflen; |
289 | 0 | word32 fill = 2 * BLAKE2S_BLOCKBYTES - left; |
290 | |
|
291 | 0 | if( inlen > fill ) |
292 | 0 | { |
293 | 0 | XMEMCPY( S->buf + left, in, (wolfssl_word)fill ); /* Fill buffer */ |
294 | 0 | S->buflen += fill; |
295 | 0 | blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES ); |
296 | |
|
297 | 0 | { |
298 | 0 | ret= blake2s_compress( S, S->buf, m, v ); |
299 | 0 | if (ret < 0) break; |
300 | 0 | } |
301 | | |
302 | 0 | XMEMCPY( S->buf, S->buf + BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES ); |
303 | | /* Shift buffer left */ |
304 | 0 | S->buflen -= BLAKE2S_BLOCKBYTES; |
305 | 0 | in += fill; |
306 | 0 | inlen -= fill; |
307 | 0 | } |
308 | 0 | else /* inlen <= fill */ |
309 | 0 | { |
310 | 0 | XMEMCPY( S->buf + left, in, (wolfssl_word)inlen ); |
311 | 0 | S->buflen += inlen; /* Be lazy, do not compress */ |
312 | 0 | inlen = 0; |
313 | 0 | } |
314 | 0 | } |
315 | |
|
316 | 0 | #ifdef WOLFSSL_SMALL_STACK |
317 | 0 | XFREE(m, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
318 | 0 | #endif |
319 | |
|
320 | 0 | return ret; |
321 | 0 | } |
322 | | |
323 | | /* Is this correct? */ |
324 | | int blake2s_final( blake2s_state *S, byte *out, byte outlen ) |
325 | 0 | { |
326 | 0 | int ret = 0; |
327 | 0 | word32 i; |
328 | 0 | byte buffer[BLAKE2S_BLOCKBYTES]; |
329 | 0 | #ifdef WOLFSSL_SMALL_STACK |
330 | 0 | word32* m; |
331 | 0 | word32* v; |
332 | |
|
333 | 0 | m = (word32*)XMALLOC(sizeof(word32) * 32, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
334 | |
|
335 | 0 | if ( m == NULL ) return MEMORY_E; |
336 | | |
337 | 0 | v = &m[16]; |
338 | | #else |
339 | | word32 m[16]; |
340 | | word32 v[16]; |
341 | | #endif |
342 | |
|
343 | 0 | if( S->buflen > BLAKE2S_BLOCKBYTES ) |
344 | 0 | { |
345 | 0 | blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES ); |
346 | |
|
347 | 0 | { |
348 | 0 | ret = blake2s_compress( S, S->buf, m, v ); |
349 | 0 | if (ret < 0) goto out; |
350 | 0 | } |
351 | | |
352 | 0 | S->buflen -= BLAKE2S_BLOCKBYTES; |
353 | 0 | XMEMCPY( S->buf, S->buf + BLAKE2S_BLOCKBYTES, (wolfssl_word)S->buflen ); |
354 | 0 | } |
355 | | |
356 | 0 | blake2s_increment_counter( S, S->buflen ); |
357 | 0 | blake2s_set_lastblock( S ); |
358 | 0 | XMEMSET( S->buf + S->buflen, 0, (wolfssl_word)(2 * BLAKE2S_BLOCKBYTES - S->buflen) ); |
359 | | /* Padding */ |
360 | 0 | { |
361 | 0 | ret = blake2s_compress( S, S->buf, m, v ); |
362 | 0 | if (ret < 0) goto out; |
363 | 0 | } |
364 | | |
365 | 0 | for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ |
366 | 0 | store64( buffer + sizeof( S->h[i] ) * i, S->h[i] ); |
367 | |
|
368 | 0 | XMEMCPY( out, buffer, outlen ); |
369 | |
|
370 | 0 | out: |
371 | |
|
372 | 0 | #ifdef WOLFSSL_SMALL_STACK |
373 | 0 | XFREE(m, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
374 | 0 | #endif |
375 | |
|
376 | 0 | return ret; |
377 | 0 | } |
378 | | |
379 | | /* inlen, at least, should be word32. Others can be size_t. */ |
380 | | int blake2s( byte *out, const void *in, const void *key, const byte outlen, |
381 | | const word32 inlen, byte keylen ) |
382 | 0 | { |
383 | 0 | blake2s_state S[1]; |
384 | | |
385 | | /* Verify parameters */ |
386 | 0 | if ( NULL == in ) return BAD_FUNC_ARG; |
387 | | |
388 | 0 | if ( NULL == out ) return BAD_FUNC_ARG; |
389 | | |
390 | 0 | if( NULL == key ) keylen = 0; |
391 | |
|
392 | 0 | if( keylen > 0 ) |
393 | 0 | { |
394 | 0 | int ret = blake2s_init_key( S, outlen, key, keylen ); |
395 | 0 | if (ret < 0) return ret; |
396 | 0 | } |
397 | 0 | else |
398 | 0 | { |
399 | 0 | int ret = blake2s_init( S, outlen ); |
400 | 0 | if (ret < 0) return ret; |
401 | 0 | } |
402 | | |
403 | 0 | { |
404 | 0 | int ret = blake2s_update( S, ( byte * )in, inlen ); |
405 | 0 | if (ret < 0) return ret; |
406 | 0 | } |
407 | | |
408 | 0 | return blake2s_final( S, out, outlen ); |
409 | 0 | } |
410 | | |
411 | | #if defined(BLAKE2S_SELFTEST) |
412 | | #include <string.h> |
413 | | #include "blake2-kat.h" |
414 | | int main( int argc, char **argv ) |
415 | | { |
416 | | byte key[BLAKE2S_KEYBYTES]; |
417 | | byte buf[KAT_LENGTH]; |
418 | | |
419 | | for( word32 i = 0; i < BLAKE2S_KEYBYTES; ++i ) |
420 | | key[i] = ( byte )i; |
421 | | |
422 | | for( word32 i = 0; i < KAT_LENGTH; ++i ) |
423 | | buf[i] = ( byte )i; |
424 | | |
425 | | for( word32 i = 0; i < KAT_LENGTH; ++i ) |
426 | | { |
427 | | byte hash[BLAKE2S_OUTBYTES]; |
428 | | if ( blake2s( hash, buf, key, BLAKE2S_OUTBYTES, i, BLAKE2S_KEYBYTES ) < 0 ) |
429 | | { |
430 | | puts( "error" ); |
431 | | return -1; |
432 | | } |
433 | | |
434 | | if( 0 != XMEMCMP( hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES ) ) |
435 | | { |
436 | | puts( "error" ); |
437 | | return -1; |
438 | | } |
439 | | } |
440 | | |
441 | | puts( "ok" ); |
442 | | return 0; |
443 | | } |
444 | | #endif |
445 | | |
446 | | |
447 | | /* wolfCrypt API */ |
448 | | |
449 | | /* Init Blake2s digest, track size in case final doesn't want to "remember" */ |
450 | | int wc_InitBlake2s(Blake2s* b2s, word32 digestSz) |
451 | 0 | { |
452 | 0 | if (b2s == NULL){ |
453 | 0 | return BAD_FUNC_ARG; |
454 | 0 | } |
455 | 0 | b2s->digestSz = digestSz; |
456 | |
|
457 | 0 | return blake2s_init(b2s->S, (byte)digestSz); |
458 | 0 | } |
459 | | |
460 | | |
461 | | /* Init Blake2s digest with key, track size in case final doesn't want to "remember" */ |
462 | | int wc_InitBlake2s_WithKey(Blake2s* b2s, word32 digestSz, const byte *key, word32 keylen) |
463 | 0 | { |
464 | 0 | if (b2s == NULL){ |
465 | 0 | return BAD_FUNC_ARG; |
466 | 0 | } |
467 | 0 | b2s->digestSz = digestSz; |
468 | |
|
469 | 0 | if (keylen >= 256) |
470 | 0 | return BAD_FUNC_ARG; |
471 | | |
472 | 0 | if (key) |
473 | 0 | return blake2s_init_key(b2s->S, (byte)digestSz, key, (byte)keylen); |
474 | 0 | else |
475 | 0 | return blake2s_init(b2s->S, (byte)digestSz); |
476 | 0 | } |
477 | | |
478 | | |
479 | | /* Blake2s Update */ |
480 | | int wc_Blake2sUpdate(Blake2s* b2s, const byte* data, word32 sz) |
481 | 0 | { |
482 | 0 | if (b2s == NULL){ |
483 | 0 | return BAD_FUNC_ARG; |
484 | 0 | } |
485 | 0 | if (data == NULL && sz != 0){ |
486 | 0 | return BAD_FUNC_ARG; |
487 | 0 | } |
488 | 0 | if (sz == 0){ |
489 | 0 | return 0; |
490 | 0 | } |
491 | | |
492 | 0 | return blake2s_update(b2s->S, data, sz); |
493 | 0 | } |
494 | | |
495 | | |
496 | | /* Blake2s Final, if pass in zero size we use init digestSz */ |
497 | | int wc_Blake2sFinal(Blake2s* b2s, byte* final, word32 requestSz) |
498 | 0 | { |
499 | 0 | word32 sz; |
500 | |
|
501 | 0 | if (b2s == NULL){ |
502 | 0 | return BAD_FUNC_ARG; |
503 | 0 | } |
504 | 0 | if (final == NULL){ |
505 | 0 | return BAD_FUNC_ARG; |
506 | 0 | } |
507 | | |
508 | 0 | sz = requestSz ? requestSz : b2s->digestSz; |
509 | |
|
510 | 0 | return blake2s_final(b2s->S, final, (byte)sz); |
511 | 0 | } |
512 | | |
513 | | |
514 | | /* end CTaoCrypt API */ |
515 | | |
516 | | #endif /* HAVE_BLAKE2S */ |
517 | | |