1 /***********************************************************************
\r
3 ** Implementation of the Skein hash function.
\r
5 ** Source code author: Doug Whiting, 2008.
\r
7 ** This algorithm and source code is released to the public domain.
\r
9 ************************************************************************/
\r
11 #include <string.h> /* get the memcpy/memset functions */
\r
12 #include "skein.h" /* get the Skein API definitions */
\r
14 /*****************************************************************/
\r
15 /* External function to process blkCnt (nonzero) full block(s) of data. */
\r
16 void Skein_256_Process_Block(Skein_256_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd);
\r
17 void Skein_512_Process_Block(Skein_512_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd);
\r
18 void Skein1024_Process_Block(Skein1024_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd);
\r
20 /*****************************************************************/
\r
21 /* Portable (i.e., slow) endianness conversion functions */
\r
22 u64b_t Skein_Swap64(u64b_t w64)
\r
23 { /* instantiate the function body here */
\r
24 static const u64b_t ONE = 1; /* use this to check endianness */
\r
26 /* figure out endianness "on-the-fly" */
\r
27 if (1 == ((u08b_t *) & ONE)[0])
\r
28 return w64; /* little-endian is fast */
\r
30 return (( w64 & 0xFF) << 56) | /* big-endian is slow */
\r
31 (((w64 >> 8) & 0xFF) << 48) |
\r
32 (((w64 >>16) & 0xFF) << 40) |
\r
33 (((w64 >>24) & 0xFF) << 32) |
\r
34 (((w64 >>32) & 0xFF) << 24) |
\r
35 (((w64 >>40) & 0xFF) << 16) |
\r
36 (((w64 >>48) & 0xFF) << 8) |
\r
37 (((w64 >>56) & 0xFF) ) ;
\r
40 void Skein_Put64_LSB_First(u08b_t *dst,const u64b_t *src,size_t bCnt)
\r
41 { /* this version is fully portable (big-endian or little-endian), but slow */
\r
44 for (n=0;n<bCnt;n++)
\r
45 dst[n] = (u08b_t) (src[n>>3] >> (8*(n&7)));
\r
48 void Skein_Get64_LSB_First(u64b_t *dst,const u08b_t *src,size_t wCnt)
\r
49 { /* this version is fully portable (big-endian or little-endian), but slow */
\r
52 for (n=0;n<8*wCnt;n+=8)
\r
53 dst[n/8] = (((u64b_t) src[n ]) ) +
\r
54 (((u64b_t) src[n+1]) << 8) +
\r
55 (((u64b_t) src[n+2]) << 16) +
\r
56 (((u64b_t) src[n+3]) << 24) +
\r
57 (((u64b_t) src[n+4]) << 32) +
\r
58 (((u64b_t) src[n+5]) << 40) +
\r
59 (((u64b_t) src[n+6]) << 48) +
\r
60 (((u64b_t) src[n+7]) << 56) ;
\r
63 /*****************************************************************/
\r
65 /*****************************************************************/
\r
67 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
\r
68 /* init the context for a straight hashing operation */
\r
69 int Skein_256_Init(Skein_256_Ctxt_t *ctx, size_t hashBitLen)
\r
73 u08b_t b[SKEIN_256_STATE_BYTES];
\r
74 u64b_t w[SKEIN_256_STATE_WORDS];
\r
75 } cfg; /* config block */
\r
77 Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
\r
79 /* build/process config block for hashing */
\r
80 ctx->h.hashBitLen = hashBitLen; /* output hash byte count */
\r
81 Skein_Start_New_Type(ctx,CFG_FINAL); /* set tweaks: T0=0; T1=CFG | FINAL */
\r
83 memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */
\r
84 cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); /* set the schema, version */
\r
85 cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */
\r
86 cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
\r
88 /* compute the initial chaining values from config block */
\r
89 memset(ctx->X,0,sizeof(ctx->X)); /* zero the chaining variables */
\r
90 Skein_256_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
\r
92 /* The chaining vars ctx->X are now initialized for the given hashBitLen. */
\r
93 /* Set up to process the data message portion of the hash (default) */
\r
94 Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type, h.bCnt=0 */
\r
96 return SKEIN_SUCCESS;
\r
99 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
\r
100 /* init the context for a MAC and/or tree hash operation */
\r
101 /* [identical to Skein_256_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */
\r
102 int Skein_256_InitExt(Skein_256_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes)
\r
107 u08b_t b[SKEIN_256_STATE_BYTES];
\r
108 u64b_t w[SKEIN_256_STATE_WORDS];
\r
109 } cfg; /* config block */
\r
111 Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
\r
112 Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL);
\r
114 /* compute the initial chaining values ctx->X[], based on key */
\r
115 if (keyBytes == 0) /* is there a key? */
\r
117 memset(ctx->X,0,sizeof(ctx->X)); /* no key: use all zeroes as key for config block */
\r
119 else /* here to pre-process a key */
\r
121 Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X));
\r
122 /* do a mini-Init right here */
\r
123 ctx->h.hashBitLen=8*sizeof(ctx->X); /* set output hash bit count = state size */
\r
124 Skein_Start_New_Type(ctx,KEY); /* set tweaks: T0 = 0; T1 = KEY type */
\r
125 memset(ctx->X,0,sizeof(ctx->X)); /* zero the initial chaining variables */
\r
126 Skein_256_Update(ctx,key,keyBytes); /* hash the key */
\r
127 Skein_256_Final_Pad(ctx,cfg.b); /* put result into cfg.b[] */
\r
128 memcpy(ctx->X,cfg.b,sizeof(cfg.b)); /* copy over into ctx->X[] */
\r
129 for (i=0;i<SKEIN_256_STATE_WORDS;i++) /* convert key bytes to context words */
\r
130 ctx->X[i] = Skein_Swap64(ctx->X[i]);
\r
133 /* build/process the config block, type == CONFIG (could be precomputed for each key) */
\r
134 ctx->h.hashBitLen = hashBitLen; /* output hash bit count */
\r
135 Skein_Start_New_Type(ctx,CFG_FINAL);
\r
137 memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */
\r
138 cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
\r
139 cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */
\r
140 cfg.w[2] = Skein_Swap64(treeInfo); /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
\r
142 Skein_Show_Key(256,&ctx->h,key,keyBytes);
\r
144 /* compute the initial chaining values from config block */
\r
145 Skein_256_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
\r
147 /* The chaining vars ctx->X are now initialized */
\r
148 /* Set up to process the data message portion of the hash */
\r
149 Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type, h.bCnt=0 */
\r
151 return SKEIN_SUCCESS;
\r
154 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
\r
155 /* process the input bytes */
\r
156 int Skein_256_Update(Skein_256_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt)
\r
160 Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
\r
162 /* process full blocks, if any */
\r
163 if (msgByteCnt + ctx->h.bCnt > SKEIN_256_BLOCK_BYTES)
\r
165 if (ctx->h.bCnt) /* finish up any buffered message data */
\r
167 n = SKEIN_256_BLOCK_BYTES - ctx->h.bCnt; /* # bytes free in buffer b[] */
\r
170 Skein_assert(n < msgByteCnt); /* check on our logic here */
\r
171 memcpy(&ctx->b[ctx->h.bCnt],msg,n);
\r
176 Skein_assert(ctx->h.bCnt == SKEIN_256_BLOCK_BYTES);
\r
177 Skein_256_Process_Block(ctx,ctx->b,1,SKEIN_256_BLOCK_BYTES);
\r
180 /* now process any remaining full blocks, directly from input message data */
\r
181 if (msgByteCnt > SKEIN_256_BLOCK_BYTES)
\r
183 n = (msgByteCnt-1) / SKEIN_256_BLOCK_BYTES; /* number of full blocks to process */
\r
184 Skein_256_Process_Block(ctx,msg,n,SKEIN_256_BLOCK_BYTES);
\r
185 msgByteCnt -= n * SKEIN_256_BLOCK_BYTES;
\r
186 msg += n * SKEIN_256_BLOCK_BYTES;
\r
188 Skein_assert(ctx->h.bCnt == 0);
\r
191 /* copy any remaining source message data bytes into b[] */
\r
194 Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES);
\r
195 memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt);
\r
196 ctx->h.bCnt += msgByteCnt;
\r
199 return SKEIN_SUCCESS;
\r
202 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
\r
203 /* finalize the hash computation and output the result */
\r
204 int Skein_256_Final(Skein_256_Ctxt_t *ctx, u08b_t *hashVal)
\r
206 size_t i,n,byteCnt;
\r
207 u64b_t X[SKEIN_256_STATE_WORDS];
\r
208 Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
\r
210 ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */
\r
211 if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES) /* zero pad b[] if necessary */
\r
212 memset(&ctx->b[ctx->h.bCnt],0,SKEIN_256_BLOCK_BYTES - ctx->h.bCnt);
\r
213 Skein_256_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */
\r
215 /* now output the result */
\r
216 byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */
\r
218 /* run Threefish in "counter mode" to generate output */
\r
219 memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */
\r
220 memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */
\r
221 for (i=0;i*SKEIN_256_BLOCK_BYTES < byteCnt;i++)
\r
223 ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
\r
224 Skein_Start_New_Type(ctx,OUT_FINAL);
\r
225 Skein_256_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
\r
226 n = byteCnt - i*SKEIN_256_BLOCK_BYTES; /* number of output bytes left to go */
\r
227 if (n >= SKEIN_256_BLOCK_BYTES)
\r
228 n = SKEIN_256_BLOCK_BYTES;
\r
229 Skein_Put64_LSB_First(hashVal+i*SKEIN_256_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */
\r
230 Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_256_BLOCK_BYTES);
\r
231 memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */
\r
233 return SKEIN_SUCCESS;
\r
236 #if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
\r
237 size_t Skein_256_API_CodeSize(void)
\r
239 return ((u08b_t *) Skein_256_API_CodeSize) -
\r
240 ((u08b_t *) Skein_256_Init);
\r
244 /*****************************************************************/
\r
245 /* 512-bit Skein */
\r
246 /*****************************************************************/
\r
248 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
\r
249 /* init the context for a straight hashing operation */
\r
250 int Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen)
\r
254 u08b_t b[SKEIN_512_STATE_BYTES];
\r
255 u64b_t w[SKEIN_512_STATE_WORDS];
\r
256 } cfg; /* config block */
\r
258 Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
\r
260 /* build/process config block for hashing */
\r
261 ctx->h.hashBitLen = hashBitLen; /* output hash byte count */
\r
262 Skein_Start_New_Type(ctx,CFG_FINAL); /* set tweaks: T0=0; T1=CFG | FINAL */
\r
264 memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */
\r
265 cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); /* set the schema, version */
\r
266 cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */
\r
267 cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
\r
269 /* compute the initial chaining values from config block */
\r
270 memset(ctx->X,0,sizeof(ctx->X)); /* zero the chaining variables */
\r
271 Skein_512_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
\r
273 /* The chaining vars ctx->X are now initialized for the given hashBitLen. */
\r
274 /* Set up to process the data message portion of the hash (default) */
\r
275 Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type, h.bCnt=0 */
\r
277 return SKEIN_SUCCESS;
\r
280 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
\r
281 /* init the context for a MAC and/or tree hash operation */
\r
282 /* [identical to Skein_512_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */
\r
283 int Skein_512_InitExt(Skein_512_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes)
\r
288 u08b_t b[SKEIN_512_STATE_BYTES];
\r
289 u64b_t w[SKEIN_512_STATE_WORDS];
\r
290 } cfg; /* config block */
\r
292 Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
\r
293 Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL);
\r
295 /* compute the initial chaining values ctx->X[], based on key */
\r
296 if (keyBytes == 0) /* is there a key? */
\r
298 memset(ctx->X,0,sizeof(ctx->X)); /* no key: use all zeroes as key for config block */
\r
300 else /* here to pre-process a key */
\r
302 Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X));
\r
303 /* do a mini-Init right here */
\r
304 ctx->h.hashBitLen=8*sizeof(ctx->X); /* set output hash bit count = state size */
\r
305 Skein_Start_New_Type(ctx,KEY); /* set tweaks: T0 = 0; T1 = KEY type */
\r
306 memset(ctx->X,0,sizeof(ctx->X)); /* zero the initial chaining variables */
\r
307 Skein_512_Update(ctx,key,keyBytes); /* hash the key */
\r
308 Skein_512_Final_Pad(ctx,cfg.b); /* put result into cfg.b[] */
\r
309 memcpy(ctx->X,cfg.b,sizeof(cfg.b)); /* copy over into ctx->X[] */
\r
310 for (i=0;i<SKEIN_512_STATE_WORDS;i++) /* convert key bytes to context words */
\r
311 ctx->X[i] = Skein_Swap64(ctx->X[i]);
\r
314 /* build/process the config block, type == CONFIG (could be precomputed for each key) */
\r
315 ctx->h.hashBitLen = hashBitLen; /* output hash bit count */
\r
316 Skein_Start_New_Type(ctx,CFG_FINAL);
\r
318 memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */
\r
319 cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
\r
320 cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */
\r
321 cfg.w[2] = Skein_Swap64(treeInfo); /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
\r
323 Skein_Show_Key(512,&ctx->h,key,keyBytes);
\r
325 /* compute the initial chaining values from config block */
\r
326 Skein_512_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
\r
328 /* The chaining vars ctx->X are now initialized */
\r
329 /* Set up to process the data message portion of the hash */
\r
330 Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type, h.bCnt=0 */
\r
332 return SKEIN_SUCCESS;
\r
335 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
\r
336 /* process the input bytes */
\r
337 int Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt)
\r
341 Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
\r
343 /* process full blocks, if any */
\r
344 if (msgByteCnt + ctx->h.bCnt > SKEIN_512_BLOCK_BYTES)
\r
346 if (ctx->h.bCnt) /* finish up any buffered message data */
\r
348 n = SKEIN_512_BLOCK_BYTES - ctx->h.bCnt; /* # bytes free in buffer b[] */
\r
351 Skein_assert(n < msgByteCnt); /* check on our logic here */
\r
352 memcpy(&ctx->b[ctx->h.bCnt],msg,n);
\r
357 Skein_assert(ctx->h.bCnt == SKEIN_512_BLOCK_BYTES);
\r
358 Skein_512_Process_Block(ctx,ctx->b,1,SKEIN_512_BLOCK_BYTES);
\r
361 /* now process any remaining full blocks, directly from input message data */
\r
362 if (msgByteCnt > SKEIN_512_BLOCK_BYTES)
\r
364 n = (msgByteCnt-1) / SKEIN_512_BLOCK_BYTES; /* number of full blocks to process */
\r
365 Skein_512_Process_Block(ctx,msg,n,SKEIN_512_BLOCK_BYTES);
\r
366 msgByteCnt -= n * SKEIN_512_BLOCK_BYTES;
\r
367 msg += n * SKEIN_512_BLOCK_BYTES;
\r
369 Skein_assert(ctx->h.bCnt == 0);
\r
372 /* copy any remaining source message data bytes into b[] */
\r
375 Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES);
\r
376 memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt);
\r
377 ctx->h.bCnt += msgByteCnt;
\r
380 return SKEIN_SUCCESS;
\r
383 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
\r
384 /* finalize the hash computation and output the result */
\r
385 int Skein_512_Final(Skein_512_Ctxt_t *ctx, u08b_t *hashVal)
\r
387 size_t i,n,byteCnt;
\r
388 u64b_t X[SKEIN_512_STATE_WORDS];
\r
389 Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
\r
391 ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */
\r
392 if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES) /* zero pad b[] if necessary */
\r
393 memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt);
\r
395 Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */
\r
397 /* now output the result */
\r
398 byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */
\r
400 /* run Threefish in "counter mode" to generate more output */
\r
401 memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */
\r
402 memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */
\r
403 for (i=0;i*SKEIN_512_BLOCK_BYTES < byteCnt;i++)
\r
405 ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
\r
406 Skein_Start_New_Type(ctx,OUT_FINAL);
\r
407 Skein_512_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
\r
408 n = byteCnt - i*SKEIN_512_BLOCK_BYTES; /* number of output bytes left to go */
\r
409 if (n >= SKEIN_512_BLOCK_BYTES)
\r
410 n = SKEIN_512_BLOCK_BYTES;
\r
411 Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */
\r
412 Skein_Show_Final(512,&ctx->h,n,hashVal+i*SKEIN_512_BLOCK_BYTES);
\r
413 memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */
\r
416 return SKEIN_SUCCESS;
\r
419 #if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
\r
420 size_t Skein_512_API_CodeSize(void)
\r
422 return ((u08b_t *) Skein_512_API_CodeSize) -
\r
423 ((u08b_t *) Skein_512_Init);
\r
427 /*****************************************************************/
\r
428 /* 1024-bit Skein */
\r
429 /*****************************************************************/
\r
431 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
\r
432 /* init the context for a straight hashing operation */
\r
433 int Skein1024_Init(Skein1024_Ctxt_t *ctx, size_t hashBitLen)
\r
437 u08b_t b[SKEIN1024_STATE_BYTES];
\r
438 u64b_t w[SKEIN1024_STATE_WORDS];
\r
439 } cfg; /* config block */
\r
441 Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
\r
443 /* build/process config block for hashing */
\r
444 ctx->h.hashBitLen = hashBitLen; /* output hash byte count */
\r
445 Skein_Start_New_Type(ctx,CFG_FINAL); /* set tweaks: T0=0; T1=CFG | FINAL */
\r
447 memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */
\r
448 cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); /* set the schema, version */
\r
449 cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */
\r
450 cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
\r
452 /* compute the initial chaining values from config block */
\r
453 memset(ctx->X,0,sizeof(ctx->X)); /* zero the chaining variables */
\r
454 Skein1024_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
\r
456 /* The chaining vars ctx->X are now initialized for the given hashBitLen. */
\r
457 /* Set up to process the data message portion of the hash (default) */
\r
458 Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type, h.bCnt=0 */
\r
460 return SKEIN_SUCCESS;
\r
463 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
\r
464 /* init the context for a MAC and/or tree hash operation */
\r
465 /* [identical to Skein1024_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */
\r
466 int Skein1024_InitExt(Skein1024_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes)
\r
471 u08b_t b[SKEIN1024_STATE_BYTES];
\r
472 u64b_t w[SKEIN1024_STATE_WORDS];
\r
473 } cfg; /* config block */
\r
475 Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
\r
476 Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL);
\r
478 /* compute the initial chaining values ctx->X[], based on key */
\r
479 if (keyBytes == 0) /* is there a key? */
\r
481 memset(ctx->X,0,sizeof(ctx->X)); /* no key: use all zeroes as key for config block */
\r
483 else /* here to pre-process a key */
\r
485 Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X));
\r
486 /* do a mini-Init right here */
\r
487 ctx->h.hashBitLen=8*sizeof(ctx->X); /* set output hash bit count = state size */
\r
488 Skein_Start_New_Type(ctx,KEY); /* set tweaks: T0 = 0; T1 = KEY type */
\r
489 memset(ctx->X,0,sizeof(ctx->X)); /* zero the initial chaining variables */
\r
490 Skein1024_Update(ctx,key,keyBytes); /* hash the key */
\r
491 Skein1024_Final_Pad(ctx,cfg.b); /* put result into cfg.b[] */
\r
492 memcpy(ctx->X,cfg.b,sizeof(cfg.b)); /* copy over into ctx->X[] */
\r
493 for (i=0;i<SKEIN1024_STATE_WORDS;i++) /* convert key bytes to context words */
\r
494 ctx->X[i] = Skein_Swap64(ctx->X[i]);
\r
497 /* build/process the config block, type == CONFIG (could be precomputed for each key) */
\r
498 ctx->h.hashBitLen = hashBitLen; /* output hash bit count */
\r
499 Skein_Start_New_Type(ctx,CFG_FINAL);
\r
501 memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */
\r
502 cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
\r
503 cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */
\r
504 cfg.w[2] = Skein_Swap64(treeInfo); /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
\r
506 Skein_Show_Key(1024,&ctx->h,key,keyBytes);
\r
508 /* compute the initial chaining values from config block */
\r
509 Skein1024_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
\r
511 /* The chaining vars ctx->X are now initialized */
\r
512 /* Set up to process the data message portion of the hash */
\r
513 Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type, h.bCnt=0 */
\r
515 return SKEIN_SUCCESS;
\r
518 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
\r
519 /* process the input bytes */
\r
520 int Skein1024_Update(Skein1024_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt)
\r
524 Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
\r
526 /* process full blocks, if any */
\r
527 if (msgByteCnt + ctx->h.bCnt > SKEIN1024_BLOCK_BYTES)
\r
529 if (ctx->h.bCnt) /* finish up any buffered message data */
\r
531 n = SKEIN1024_BLOCK_BYTES - ctx->h.bCnt; /* # bytes free in buffer b[] */
\r
534 Skein_assert(n < msgByteCnt); /* check on our logic here */
\r
535 memcpy(&ctx->b[ctx->h.bCnt],msg,n);
\r
540 Skein_assert(ctx->h.bCnt == SKEIN1024_BLOCK_BYTES);
\r
541 Skein1024_Process_Block(ctx,ctx->b,1,SKEIN1024_BLOCK_BYTES);
\r
544 /* now process any remaining full blocks, directly from input message data */
\r
545 if (msgByteCnt > SKEIN1024_BLOCK_BYTES)
\r
547 n = (msgByteCnt-1) / SKEIN1024_BLOCK_BYTES; /* number of full blocks to process */
\r
548 Skein1024_Process_Block(ctx,msg,n,SKEIN1024_BLOCK_BYTES);
\r
549 msgByteCnt -= n * SKEIN1024_BLOCK_BYTES;
\r
550 msg += n * SKEIN1024_BLOCK_BYTES;
\r
552 Skein_assert(ctx->h.bCnt == 0);
\r
555 /* copy any remaining source message data bytes into b[] */
\r
558 Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES);
\r
559 memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt);
\r
560 ctx->h.bCnt += msgByteCnt;
\r
563 return SKEIN_SUCCESS;
\r
566 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
\r
567 /* finalize the hash computation and output the result */
\r
568 int Skein1024_Final(Skein1024_Ctxt_t *ctx, u08b_t *hashVal)
\r
570 size_t i,n,byteCnt;
\r
571 u64b_t X[SKEIN1024_STATE_WORDS];
\r
572 Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
\r
574 ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */
\r
575 if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES) /* zero pad b[] if necessary */
\r
576 memset(&ctx->b[ctx->h.bCnt],0,SKEIN1024_BLOCK_BYTES - ctx->h.bCnt);
\r
578 Skein1024_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */
\r
580 /* now output the result */
\r
581 byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */
\r
583 /* run Threefish in "counter mode" to generate output */
\r
584 memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */
\r
585 memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */
\r
586 for (i=0;i*SKEIN1024_BLOCK_BYTES < byteCnt;i++)
\r
588 ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
\r
589 Skein_Start_New_Type(ctx,OUT_FINAL);
\r
590 Skein1024_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
\r
591 n = byteCnt - i*SKEIN1024_BLOCK_BYTES; /* number of output bytes left to go */
\r
592 if (n >= SKEIN1024_BLOCK_BYTES)
\r
593 n = SKEIN1024_BLOCK_BYTES;
\r
594 Skein_Put64_LSB_First(hashVal+i*SKEIN1024_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */
\r
595 Skein_Show_Final(1024,&ctx->h,n,hashVal+i*SKEIN1024_BLOCK_BYTES);
\r
596 memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */
\r
598 return SKEIN_SUCCESS;
\r
601 #if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
\r
602 size_t Skein1024_API_CodeSize(void)
\r
604 return ((u08b_t *) Skein1024_API_CodeSize) -
\r
605 ((u08b_t *) Skein1024_Init);
\r
609 /**************** Functions to support MAC/tree hashing ***************/
\r
610 /* (this code is identical for Optimized and Reference versions) */
\r
612 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
\r
613 /* finalize the hash computation and output the block, no OUTPUT stage */
\r
614 int Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, u08b_t *hashVal)
\r
616 Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
\r
618 ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */
\r
619 if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES) /* zero pad b[] if necessary */
\r
620 memset(&ctx->b[ctx->h.bCnt],0,SKEIN_256_BLOCK_BYTES - ctx->h.bCnt);
\r
621 Skein_256_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */
\r
623 Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN_256_BLOCK_BYTES); /* "output" the state bytes */
\r
625 return SKEIN_SUCCESS;
\r
628 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
\r
629 /* finalize the hash computation and output the block, no OUTPUT stage */
\r
630 int Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, u08b_t *hashVal)
\r
632 Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
\r
634 ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */
\r
635 if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES) /* zero pad b[] if necessary */
\r
636 memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt);
\r
637 Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */
\r
639 Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN_512_BLOCK_BYTES); /* "output" the state bytes */
\r
641 return SKEIN_SUCCESS;
\r
644 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
\r
645 /* finalize the hash computation and output the block, no OUTPUT stage */
\r
646 int Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, u08b_t *hashVal)
\r
648 Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
\r
650 ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */
\r
651 if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES) /* zero pad b[] if necessary */
\r
652 memset(&ctx->b[ctx->h.bCnt],0,SKEIN1024_BLOCK_BYTES - ctx->h.bCnt);
\r
653 Skein1024_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */
\r
655 Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN1024_BLOCK_BYTES); /* "output" the state bytes */
\r
657 return SKEIN_SUCCESS;
\r
660 #if SKEIN_TREE_HASH
\r
661 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
\r
662 /* just do the OUTPUT stage */
\r
663 int Skein_256_Output(Skein_256_Ctxt_t *ctx, u08b_t *hashVal)
\r
665 size_t i,n,byteCnt;
\r
666 u64b_t X[SKEIN_256_STATE_WORDS];
\r
667 Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
\r
669 /* now output the result */
\r
670 byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */
\r
672 /* run Threefish in "counter mode" to generate output */
\r
673 memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */
\r
674 memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */
\r
675 for (i=0;i*SKEIN_256_BLOCK_BYTES < byteCnt;i++)
\r
677 ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
\r
678 Skein_Start_New_Type(ctx,OUT_FINAL);
\r
679 Skein_256_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
\r
680 n = byteCnt - i*SKEIN_256_BLOCK_BYTES; /* number of output bytes left to go */
\r
681 if (n >= SKEIN_256_BLOCK_BYTES)
\r
682 n = SKEIN_256_BLOCK_BYTES;
\r
683 Skein_Put64_LSB_First(hashVal+i*SKEIN_256_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */
\r
684 Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_256_BLOCK_BYTES);
\r
685 memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */
\r
687 return SKEIN_SUCCESS;
\r
690 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
\r
691 /* just do the OUTPUT stage */
\r
692 int Skein_512_Output(Skein_512_Ctxt_t *ctx, u08b_t *hashVal)
\r
694 size_t i,n,byteCnt;
\r
695 u64b_t X[SKEIN_512_STATE_WORDS];
\r
696 Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
\r
698 /* now output the result */
\r
699 byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */
\r
701 /* run Threefish in "counter mode" to generate output */
\r
702 memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */
\r
703 memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */
\r
704 for (i=0;i*SKEIN_512_BLOCK_BYTES < byteCnt;i++)
\r
706 ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
\r
707 Skein_Start_New_Type(ctx,OUT_FINAL);
\r
708 Skein_512_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
\r
709 n = byteCnt - i*SKEIN_512_BLOCK_BYTES; /* number of output bytes left to go */
\r
710 if (n >= SKEIN_512_BLOCK_BYTES)
\r
711 n = SKEIN_512_BLOCK_BYTES;
\r
712 Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */
\r
713 Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_512_BLOCK_BYTES);
\r
714 memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */
\r
716 return SKEIN_SUCCESS;
\r
719 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
\r
720 /* just do the OUTPUT stage */
\r
721 int Skein1024_Output(Skein1024_Ctxt_t *ctx, u08b_t *hashVal)
\r
723 size_t i,n,byteCnt;
\r
724 u64b_t X[SKEIN1024_STATE_WORDS];
\r
725 Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */
\r
727 /* now output the result */
\r
728 byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */
\r
730 /* run Threefish in "counter mode" to generate output */
\r
731 memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */
\r
732 memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */
\r
733 for (i=0;i*SKEIN1024_BLOCK_BYTES < byteCnt;i++)
\r
735 ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
\r
736 Skein_Start_New_Type(ctx,OUT_FINAL);
\r
737 Skein1024_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
\r
738 n = byteCnt - i*SKEIN1024_BLOCK_BYTES; /* number of output bytes left to go */
\r
739 if (n >= SKEIN1024_BLOCK_BYTES)
\r
740 n = SKEIN1024_BLOCK_BYTES;
\r
741 Skein_Put64_LSB_First(hashVal+i*SKEIN1024_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */
\r
742 Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN1024_BLOCK_BYTES);
\r
743 memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */
\r
745 return SKEIN_SUCCESS;
\r