1/*
2   BLAKE2 reference source code package - optimized 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#include <stdio.h>
14#if defined(WIN32)
15#include <windows.h>
16#endif
17#include "blake2.h"
18
19#if defined(__x86_64__) || defined(__i386__) || defined(_M_IX86) || defined(_M_X64)
20#define HAVE_X86
21#endif
22
23typedef enum
24{
25  NONE  = 0,
26#if defined(HAVE_X86)
27  SSE2  = 1,
28  SSSE3 = 2,
29  SSE41 = 3,
30  AVX   = 4,
31  XOP   = 5,
32  /* AVX2  = 6, */
33#endif
34} cpu_feature_t;
35
36static const char feature_names[][8] =
37{
38  "none",
39#if defined(HAVE_X86)
40  "sse2",
41  "ssse3",
42  "sse41",
43  "avx",
44  "xop",
45  /* "avx2" */
46#endif
47};
48
49#if defined(HAVE_X86)
50
51#if defined(__GNUC__)
52static inline void cpuid( uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx )
53{
54  __asm__ __volatile__(
55#if defined(__i386__) /* This is needed for -fPIC to work on i386 */
56    "movl %%ebx, %%esi\n\t"
57#endif
58    "cpuid\n\t"
59#if defined(__i386__)
60    "xchgl %%ebx, %%esi\n\t"
61    : "=a"( *eax ), "=S"( *ebx ), "=c"( *ecx ), "=d"( *edx ) : "a"( *eax ) );
62#else
63    : "=a"( *eax ), "=b"( *ebx ), "=c"( *ecx ), "=d"( *edx ) : "a"( *eax ) );
64#endif
65}
66
67static inline uint64_t xgetbv(uint32_t xcr)
68{
69  uint32_t a, d;
70  __asm__ __volatile__(
71    "xgetbv"
72    :  "=a"(a),"=d"(d)
73    : "c"(xcr)
74  );
75  return ((uint64_t)d << 32) | a;
76}
77
78#elif defined(_MSC_VER)
79#include <intrin.h>
80static inline void cpuid( uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx )
81{
82  int regs[4];
83  __cpuid( regs, *eax );
84  *eax = regs[0];
85  *ebx = regs[1];
86  *ecx = regs[2];
87  *edx = regs[3];
88}
89#else
90#error "Don't know how to call cpuid on this compiler!"
91#endif
92
93#endif /* HAVE_X86 */
94
95static inline cpu_feature_t get_cpu_features( void )
96{
97#if defined(HAVE_X86)
98  static volatile int initialized = 0;
99  static cpu_feature_t feature = NONE; // Safe default
100  uint32_t eax, ecx, edx, ebx;
101
102  if( initialized )
103    return feature;
104
105  eax = 1;
106  cpuid( &eax, &ebx, &ecx, &edx );
107
108  if( 1 & ( edx >> 26 ) )
109    feature = SSE2;
110
111  if( 1 & ( ecx >> 9 ) )
112    feature = SSSE3;
113
114  if( 1 & ( ecx >> 19 ) )
115    feature = SSE41;
116
117#if defined(WIN32) /* Work around the fact that Windows <7 does NOT support AVX... */
118  if( IsProcessorFeaturePresent(17) ) /* Some environments don't know about PF_XSAVE_ENABLED */
119#endif
120  {
121    /* check for AVX and OSXSAVE bits */
122    if( 1 & ( ecx >> 28 ) & (ecx >> 27) ) {
123#if !defined(WIN32) /* Already checked for this in WIN32 */
124    if( (xgetbv(0) & 6) == 6 ) /* XCR0 */
125#endif
126      feature = AVX;
127    }
128
129
130    eax = 0x80000001;
131    cpuid( &eax, &ebx, &ecx, &edx );
132
133    if( 1 & ( ecx >> 11 ) )
134      feature = XOP;
135  }
136
137  /* For future architectures */
138  /*
139      eax = 7; ecx = 0;
140      cpuid(&eax, &ebx, &ecx, &edx);
141
142      if(1&(ebx >> 5))
143        feature = AVX2;
144  */
145  /* fprintf( stderr, "Using %s engine\n", feature_names[feature] ); */
146  initialized = 1;
147  return feature;
148#else
149  return NONE;
150#endif
151}
152
153
154
155#if defined(__cplusplus)
156extern "C" {
157#endif
158  int blake2b_init_ref( blake2b_state *S, size_t outlen );
159  int blake2b_init_key_ref( blake2b_state *S, size_t outlen, const void *key, size_t keylen );
160  int blake2b_init_param_ref( blake2b_state *S, const blake2b_param *P );
161  int blake2b_update_ref( blake2b_state *S, const uint8_t *in, size_t inlen );
162  int blake2b_final_ref( blake2b_state *S, uint8_t *out, size_t outlen );
163  int blake2b_ref( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen );
164
165#if defined(HAVE_X86)
166
167  int blake2b_init_sse2( blake2b_state *S, size_t outlen );
168  int blake2b_init_key_sse2( blake2b_state *S, size_t outlen, const void *key, size_t keylen );
169  int blake2b_init_param_sse2( blake2b_state *S, const blake2b_param *P );
170  int blake2b_update_sse2( blake2b_state *S, const uint8_t *in, size_t inlen );
171  int blake2b_final_sse2( blake2b_state *S, uint8_t *out, size_t outlen );
172  int blake2b_sse2( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen );
173
174  int blake2b_init_ssse3( blake2b_state *S, size_t outlen );
175  int blake2b_init_key_ssse3( blake2b_state *S, size_t outlen, const void *key, size_t keylen );
176  int blake2b_init_param_ssse3( blake2b_state *S, const blake2b_param *P );
177  int blake2b_update_ssse3( blake2b_state *S, const uint8_t *in, size_t inlen );
178  int blake2b_final_ssse3( blake2b_state *S, uint8_t *out, size_t outlen );
179  int blake2b_ssse3( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen );
180
181  int blake2b_init_sse41( blake2b_state *S, size_t outlen );
182  int blake2b_init_key_sse41( blake2b_state *S, size_t outlen, const void *key, size_t keylen );
183  int blake2b_init_param_sse41( blake2b_state *S, const blake2b_param *P );
184  int blake2b_update_sse41( blake2b_state *S, const uint8_t *in, size_t inlen );
185  int blake2b_final_sse41( blake2b_state *S, uint8_t *out, size_t outlen );
186  int blake2b_sse41( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen );
187
188  int blake2b_init_avx( blake2b_state *S, size_t outlen );
189  int blake2b_init_key_avx( blake2b_state *S, size_t outlen, const void *key, size_t keylen );
190  int blake2b_init_param_avx( blake2b_state *S, const blake2b_param *P );
191  int blake2b_update_avx( blake2b_state *S, const uint8_t *in, size_t inlen );
192  int blake2b_final_avx( blake2b_state *S, uint8_t *out, size_t outlen );
193  int blake2b_avx( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen );
194
195  int blake2b_init_xop( blake2b_state *S, size_t outlen );
196  int blake2b_init_key_xop( blake2b_state *S, size_t outlen, const void *key, size_t keylen );
197  int blake2b_init_param_xop( blake2b_state *S, const blake2b_param *P );
198  int blake2b_update_xop( blake2b_state *S, const uint8_t *in, size_t inlen );
199  int blake2b_final_xop( blake2b_state *S, uint8_t *out, size_t outlen );
200  int blake2b_xop( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen );
201
202#endif /* HAVE_X86 */
203
204  int blake2s_init_ref( blake2s_state *S, size_t outlen );
205  int blake2s_init_key_ref( blake2s_state *S, size_t outlen, const void *key, size_t keylen );
206  int blake2s_init_param_ref( blake2s_state *S, const blake2s_param *P );
207  int blake2s_update_ref( blake2s_state *S, const uint8_t *in, size_t inlen );
208  int blake2s_final_ref( blake2s_state *S, uint8_t *out, size_t outlen );
209  int blake2s_ref( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen );
210
211#if defined(HAVE_X86)
212
213  int blake2s_init_sse2( blake2s_state *S, size_t outlen );
214  int blake2s_init_key_sse2( blake2s_state *S, size_t outlen, const void *key, size_t keylen );
215  int blake2s_init_param_sse2( blake2s_state *S, const blake2s_param *P );
216  int blake2s_update_sse2( blake2s_state *S, const uint8_t *in, size_t inlen );
217  int blake2s_final_sse2( blake2s_state *S, uint8_t *out, size_t outlen );
218  int blake2s_sse2( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen );
219
220  int blake2s_init_ssse3( blake2s_state *S, size_t outlen );
221  int blake2s_init_key_ssse3( blake2s_state *S, size_t outlen, const void *key, size_t keylen );
222  int blake2s_init_param_ssse3( blake2s_state *S, const blake2s_param *P );
223  int blake2s_update_ssse3( blake2s_state *S, const uint8_t *in, size_t inlen );
224  int blake2s_final_ssse3( blake2s_state *S, uint8_t *out, size_t outlen );
225  int blake2s_ssse3( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen );
226
227  int blake2s_init_sse41( blake2s_state *S, size_t outlen );
228  int blake2s_init_key_sse41( blake2s_state *S, size_t outlen, const void *key, size_t keylen );
229  int blake2s_init_param_sse41( blake2s_state *S, const blake2s_param *P );
230  int blake2s_update_sse41( blake2s_state *S, const uint8_t *in, size_t inlen );
231  int blake2s_final_sse41( blake2s_state *S, uint8_t *out, size_t outlen );
232  int blake2s_sse41( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen );
233
234  int blake2s_init_avx( blake2s_state *S, size_t outlen );
235  int blake2s_init_key_avx( blake2s_state *S, size_t outlen, const void *key, size_t keylen );
236  int blake2s_init_param_avx( blake2s_state *S, const blake2s_param *P );
237  int blake2s_update_avx( blake2s_state *S, const uint8_t *in, size_t inlen );
238  int blake2s_final_avx( blake2s_state *S, uint8_t *out, size_t outlen );
239  int blake2s_avx( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen );
240
241  int blake2s_init_xop( blake2s_state *S, size_t outlen );
242  int blake2s_init_key_xop( blake2s_state *S, size_t outlen, const void *key, size_t keylen );
243  int blake2s_init_param_xop( blake2s_state *S, const blake2s_param *P );
244  int blake2s_update_xop( blake2s_state *S, const uint8_t *in, size_t inlen );
245  int blake2s_final_xop( blake2s_state *S, uint8_t *out, size_t outlen );
246  int blake2s_xop( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen );
247
248#endif /* HAVE_X86 */
249
250#if defined(__cplusplus)
251}
252#endif
253
254typedef int ( *blake2b_init_fn )( blake2b_state *, size_t );
255typedef int ( *blake2b_init_key_fn )( blake2b_state *, size_t, const void *, size_t );
256typedef int ( *blake2b_init_param_fn )( blake2b_state *, const blake2b_param * );
257typedef int ( *blake2b_update_fn )( blake2b_state *, const uint8_t *, size_t );
258typedef int ( *blake2b_final_fn )( blake2b_state *, uint8_t *, size_t );
259typedef int ( *blake2b_fn )( uint8_t *, const void *, const void *, size_t, size_t, size_t );
260
261typedef int ( *blake2s_init_fn )( blake2s_state *, size_t );
262typedef int ( *blake2s_init_key_fn )( blake2s_state *, size_t, const void *, size_t );
263typedef int ( *blake2s_init_param_fn )( blake2s_state *, const blake2s_param * );
264typedef int ( *blake2s_update_fn )( blake2s_state *, const uint8_t *, size_t );
265typedef int ( *blake2s_final_fn )( blake2s_state *, uint8_t *, size_t );
266typedef int ( *blake2s_fn )( uint8_t *, const void *, const void *, size_t, size_t, size_t );
267
268static const blake2b_init_fn blake2b_init_table[] =
269{
270  blake2b_init_ref,
271#if defined(HAVE_X86)
272  blake2b_init_sse2,
273  blake2b_init_ssse3,
274  blake2b_init_sse41,
275  blake2b_init_avx,
276  blake2b_init_xop
277#endif
278};
279
280static const blake2b_init_key_fn blake2b_init_key_table[] =
281{
282  blake2b_init_key_ref,
283#if defined(HAVE_X86)
284  blake2b_init_key_sse2,
285  blake2b_init_key_ssse3,
286  blake2b_init_key_sse41,
287  blake2b_init_key_avx,
288  blake2b_init_key_xop
289#endif
290};
291
292static const blake2b_init_param_fn blake2b_init_param_table[] =
293{
294  blake2b_init_param_ref,
295#if defined(HAVE_X86)
296  blake2b_init_param_sse2,
297  blake2b_init_param_ssse3,
298  blake2b_init_param_sse41,
299  blake2b_init_param_avx,
300  blake2b_init_param_xop
301#endif
302};
303
304static const blake2b_update_fn blake2b_update_table[] =
305{
306  blake2b_update_ref,
307#if defined(HAVE_X86)
308  blake2b_update_sse2,
309  blake2b_update_ssse3,
310  blake2b_update_sse41,
311  blake2b_update_avx,
312  blake2b_update_xop
313#endif
314};
315
316static const blake2b_final_fn blake2b_final_table[] =
317{
318  blake2b_final_ref,
319#if defined(HAVE_X86)
320  blake2b_final_sse2,
321  blake2b_final_ssse3,
322  blake2b_final_sse41,
323  blake2b_final_avx,
324  blake2b_final_xop
325#endif
326};
327
328static const blake2b_fn blake2b_table[] =
329{
330  blake2b_ref,
331#if defined(HAVE_X86)
332  blake2b_sse2,
333  blake2b_ssse3,
334  blake2b_sse41,
335  blake2b_avx,
336  blake2b_xop
337#endif
338};
339
340static const blake2s_init_fn blake2s_init_table[] =
341{
342  blake2s_init_ref,
343#if defined(HAVE_X86)
344  blake2s_init_sse2,
345  blake2s_init_ssse3,
346  blake2s_init_sse41,
347  blake2s_init_avx,
348  blake2s_init_xop
349#endif
350};
351
352static const blake2s_init_key_fn blake2s_init_key_table[] =
353{
354  blake2s_init_key_ref,
355#if defined(HAVE_X86)
356  blake2s_init_key_sse2,
357  blake2s_init_key_ssse3,
358  blake2s_init_key_sse41,
359  blake2s_init_key_avx,
360  blake2s_init_key_xop
361#endif
362};
363
364static const blake2s_init_param_fn blake2s_init_param_table[] =
365{
366  blake2s_init_param_ref,
367#if defined(HAVE_X86)
368  blake2s_init_param_sse2,
369  blake2s_init_param_ssse3,
370  blake2s_init_param_sse41,
371  blake2s_init_param_avx,
372  blake2s_init_param_xop
373#endif
374};
375
376static const blake2s_update_fn blake2s_update_table[] =
377{
378  blake2s_update_ref,
379#if defined(HAVE_X86)
380  blake2s_update_sse2,
381  blake2s_update_ssse3,
382  blake2s_update_sse41,
383  blake2s_update_avx,
384  blake2s_update_xop
385#endif
386};
387
388static const blake2s_final_fn blake2s_final_table[] =
389{
390  blake2s_final_ref,
391#if defined(HAVE_X86)
392  blake2s_final_sse2,
393  blake2s_final_ssse3,
394  blake2s_final_sse41,
395  blake2s_final_avx,
396  blake2s_final_xop
397#endif
398};
399
400static const blake2s_fn blake2s_table[] =
401{
402  blake2s_ref,
403#if defined(HAVE_X86)
404  blake2s_sse2,
405  blake2s_ssse3,
406  blake2s_sse41,
407  blake2s_avx,
408  blake2s_xop
409#endif
410};
411
412#if defined(__cplusplus)
413extern "C" {
414#endif
415  int blake2b_init_dispatch( blake2b_state *S, size_t outlen );
416  int blake2b_init_key_dispatch( blake2b_state *S, size_t outlen, const void *key, size_t keylen );
417  int blake2b_init_param_dispatch( blake2b_state *S, const blake2b_param *P );
418  int blake2b_update_dispatch( blake2b_state *S, const uint8_t *in, size_t inlen );
419  int blake2b_final_dispatch( blake2b_state *S, uint8_t *out, size_t outlen );
420  int blake2b_dispatch( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen );
421
422  int blake2s_init_dispatch( blake2s_state *S, size_t outlen );
423  int blake2s_init_key_dispatch( blake2s_state *S, size_t outlen, const void *key, size_t keylen );
424  int blake2s_init_param_dispatch( blake2s_state *S, const blake2s_param *P );
425  int blake2s_update_dispatch( blake2s_state *S, const uint8_t *in, size_t inlen );
426  int blake2s_final_dispatch( blake2s_state *S, uint8_t *out, size_t outlen );
427  int blake2s_dispatch( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen );
428#if defined(__cplusplus)
429}
430#endif
431
432static blake2b_init_fn blake2b_init_ptr = blake2b_init_dispatch;
433static blake2b_init_key_fn blake2b_init_key_ptr = blake2b_init_key_dispatch;
434static blake2b_init_param_fn blake2b_init_param_ptr = blake2b_init_param_dispatch;
435static blake2b_update_fn blake2b_update_ptr = blake2b_update_dispatch;
436static blake2b_final_fn blake2b_final_ptr = blake2b_final_dispatch;
437static blake2b_fn blake2b_ptr = blake2b_dispatch;
438
439static blake2s_init_fn blake2s_init_ptr = blake2s_init_dispatch;
440static blake2s_init_key_fn blake2s_init_key_ptr = blake2s_init_key_dispatch;
441static blake2s_init_param_fn blake2s_init_param_ptr = blake2s_init_param_dispatch;
442static blake2s_update_fn blake2s_update_ptr = blake2s_update_dispatch;
443static blake2s_final_fn blake2s_final_ptr = blake2s_final_dispatch;
444static blake2s_fn blake2s_ptr = blake2s_dispatch;
445
446int blake2b_init_dispatch( blake2b_state *S, size_t outlen )
447{
448  blake2b_init_ptr = blake2b_init_table[get_cpu_features()];
449  return blake2b_init_ptr( S, outlen );
450}
451
452int blake2b_init_key_dispatch( blake2b_state *S, size_t outlen, const void *key, size_t keylen )
453{
454  blake2b_init_key_ptr = blake2b_init_key_table[get_cpu_features()];
455  return blake2b_init_key_ptr( S, outlen, key, keylen );
456}
457
458int blake2b_init_param_dispatch( blake2b_state *S, const blake2b_param *P )
459{
460  blake2b_init_param_ptr = blake2b_init_param_table[get_cpu_features()];
461  return blake2b_init_param_ptr( S, P );
462}
463
464int blake2b_update_dispatch( blake2b_state *S, const uint8_t *in, size_t inlen )
465{
466  blake2b_update_ptr = blake2b_update_table[get_cpu_features()];
467  return blake2b_update_ptr( S, in, inlen );
468}
469
470int blake2b_final_dispatch( blake2b_state *S, uint8_t *out, size_t outlen )
471{
472  blake2b_final_ptr = blake2b_final_table[get_cpu_features()];
473  return blake2b_final_ptr( S, out, outlen );
474}
475
476int blake2b_dispatch( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen )
477{
478  blake2b_ptr = blake2b_table[get_cpu_features()];
479  return blake2b_ptr( out, in, key, outlen, inlen, keylen );
480}
481
482BLAKE2_API int blake2b_init( blake2b_state *S, size_t outlen )
483{
484  return blake2b_init_ptr( S, outlen );
485}
486
487BLAKE2_API int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen )
488{
489  return blake2b_init_key_ptr( S, outlen, key, keylen );
490}
491
492BLAKE2_API int blake2b_init_param( blake2b_state *S, const blake2b_param *P )
493{
494  return blake2b_init_param_ptr( S, P );
495}
496
497BLAKE2_API int blake2b_update( blake2b_state *S, const uint8_t *in, size_t inlen )
498{
499  return blake2b_update_ptr( S, in, inlen );
500}
501
502BLAKE2_API int blake2b_final( blake2b_state *S, uint8_t *out, size_t outlen )
503{
504  return blake2b_final_ptr( S, out, outlen );
505}
506
507BLAKE2_API int blake2b( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen )
508{
509  return blake2b_ptr( out, in, key, outlen, inlen, keylen );
510}
511
512int blake2s_init_dispatch( blake2s_state *S, size_t outlen )
513{
514  blake2s_init_ptr = blake2s_init_table[get_cpu_features()];
515  return blake2s_init_ptr( S, outlen );
516}
517
518int blake2s_init_key_dispatch( blake2s_state *S, size_t outlen, const void *key, size_t keylen )
519{
520  blake2s_init_key_ptr = blake2s_init_key_table[get_cpu_features()];
521  return blake2s_init_key_ptr( S, outlen, key, keylen );
522}
523
524int blake2s_init_param_dispatch( blake2s_state *S, const blake2s_param *P )
525{
526  blake2s_init_param_ptr = blake2s_init_param_table[get_cpu_features()];
527  return blake2s_init_param_ptr( S, P );
528}
529
530int blake2s_update_dispatch( blake2s_state *S, const uint8_t *in, size_t inlen )
531{
532  blake2s_update_ptr = blake2s_update_table[get_cpu_features()];
533  return blake2s_update_ptr( S, in, inlen );
534}
535
536int blake2s_final_dispatch( blake2s_state *S, uint8_t *out, size_t outlen )
537{
538  blake2s_final_ptr = blake2s_final_table[get_cpu_features()];
539  return blake2s_final_ptr( S, out, outlen );
540}
541
542int blake2s_dispatch( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen )
543{
544  blake2s_ptr = blake2s_table[get_cpu_features()];
545  return blake2s_ptr( out, in, key, outlen, inlen, keylen );
546}
547
548BLAKE2_API int blake2s_init( blake2s_state *S, size_t outlen )
549{
550  return blake2s_init_ptr( S, outlen );
551}
552
553BLAKE2_API int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen )
554{
555  return blake2s_init_key_ptr( S, outlen, key, keylen );
556}
557
558BLAKE2_API int blake2s_init_param( blake2s_state *S, const blake2s_param *P )
559{
560  return blake2s_init_param_ptr( S, P );
561}
562
563BLAKE2_API int blake2s_update( blake2s_state *S, const uint8_t *in, size_t inlen )
564{
565  return blake2s_update_ptr( S, in, inlen );
566}
567
568BLAKE2_API int blake2s_final( blake2s_state *S, uint8_t *out, size_t outlen )
569{
570  return blake2s_final_ptr( S, out, outlen );
571}
572
573BLAKE2_API int blake2s( uint8_t *out, const void *in, const void *key, size_t outlen, size_t inlen, size_t keylen )
574{
575  return blake2s_ptr( out, in, key, outlen, inlen, keylen );
576}
577
578