1300819Sallanjude/***********************************************************************
2300819Sallanjude**
3300819Sallanjude** Implementation of the Skein hash function.
4300819Sallanjude**
5300819Sallanjude** Source code author: Doug Whiting, 2008.
6300819Sallanjude**
7300819Sallanjude** This algorithm and source code is released to the public domain.
8300819Sallanjude**
9300819Sallanjude************************************************************************/
10300819Sallanjude
11300921Sallanjude#include <sys/cdefs.h>
12300921Sallanjude__FBSDID("$FreeBSD: releng/11.0/sys/crypto/skein/skein.c 300921 2016-05-29 01:15:36Z allanjude $");
13300921Sallanjude
14300921Sallanjude#include <sys/endian.h>
15300921Sallanjude#include <sys/types.h>
16300921Sallanjude
17300921Sallanjude/* get the memcpy/memset functions */
18300921Sallanjude#ifdef _KERNEL
19300921Sallanjude#include <sys/systm.h>
20300921Sallanjude#else
21300921Sallanjude#include <string.h>
22300921Sallanjude#endif
23300921Sallanjude
24300819Sallanjude#define  SKEIN_PORT_CODE /* instantiate any code in skein_port.h */
25300819Sallanjude
26300819Sallanjude#include "skein.h"       /* get the Skein API definitions   */
27300819Sallanjude#include "skein_iv.h"    /* get precomputed IVs */
28300819Sallanjude
29300819Sallanjude/*****************************************************************/
30300819Sallanjude/* External function to process blkCnt (nonzero) full block(s) of data. */
31300819Sallanjudevoid    Skein_256_Process_Block(Skein_256_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd);
32300819Sallanjudevoid    Skein_512_Process_Block(Skein_512_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd);
33300819Sallanjudevoid    Skein1024_Process_Block(Skein1024_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd);
34300819Sallanjude
35300819Sallanjude/*****************************************************************/
36300819Sallanjude/*     256-bit Skein                                             */
37300819Sallanjude/*****************************************************************/
38300819Sallanjude
39300819Sallanjude/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
40300819Sallanjude/* init the context for a straight hashing operation  */
41300819Sallanjudeint Skein_256_Init(Skein_256_Ctxt_t *ctx, size_t hashBitLen)
42300819Sallanjude    {
43300819Sallanjude    union
44300819Sallanjude        {
45300819Sallanjude        u08b_t  b[SKEIN_256_STATE_BYTES];
46300819Sallanjude        u64b_t  w[SKEIN_256_STATE_WORDS];
47300819Sallanjude        } cfg;                              /* config block */
48300819Sallanjude
49300819Sallanjude    Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
50300819Sallanjude    ctx->h.hashBitLen = hashBitLen;         /* output hash bit count */
51300819Sallanjude
52300819Sallanjude    switch (hashBitLen)
53300819Sallanjude        {             /* use pre-computed values, where available */
54300819Sallanjude#ifndef SKEIN_NO_PRECOMP
55300819Sallanjude        case  256: memcpy(ctx->X,SKEIN_256_IV_256,sizeof(ctx->X));  break;
56300819Sallanjude        case  224: memcpy(ctx->X,SKEIN_256_IV_224,sizeof(ctx->X));  break;
57300819Sallanjude        case  160: memcpy(ctx->X,SKEIN_256_IV_160,sizeof(ctx->X));  break;
58300819Sallanjude        case  128: memcpy(ctx->X,SKEIN_256_IV_128,sizeof(ctx->X));  break;
59300819Sallanjude#endif
60300819Sallanjude        default:
61300819Sallanjude            /* here if there is no precomputed IV value available */
62300819Sallanjude            /* build/process the config block, type == CONFIG (could be precomputed) */
63300819Sallanjude            Skein_Start_New_Type(ctx,CFG_FINAL);        /* set tweaks: T0=0; T1=CFG | FINAL */
64300819Sallanjude
65300819Sallanjude            cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);  /* set the schema, version */
66300819Sallanjude            cfg.w[1] = Skein_Swap64(hashBitLen);        /* hash result length in bits */
67300819Sallanjude            cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
68300819Sallanjude            memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */
69300819Sallanjude
70300819Sallanjude            /* compute the initial chaining values from config block */
71300819Sallanjude            memset(ctx->X,0,sizeof(ctx->X));            /* zero the chaining variables */
72300819Sallanjude            Skein_256_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
73300819Sallanjude            break;
74300819Sallanjude        }
75300819Sallanjude    /* The chaining vars ctx->X are now initialized for the given hashBitLen. */
76300819Sallanjude    /* Set up to process the data message portion of the hash (default) */
77300819Sallanjude    Skein_Start_New_Type(ctx,MSG);              /* T0=0, T1= MSG type */
78300819Sallanjude
79300819Sallanjude    return SKEIN_SUCCESS;
80300819Sallanjude    }
81300819Sallanjude
82300819Sallanjude/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
83300819Sallanjude/* init the context for a MAC and/or tree hash operation */
84300819Sallanjude/* [identical to Skein_256_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */
85300819Sallanjudeint Skein_256_InitExt(Skein_256_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes)
86300819Sallanjude    {
87300819Sallanjude    union
88300819Sallanjude        {
89300819Sallanjude        u08b_t  b[SKEIN_256_STATE_BYTES];
90300819Sallanjude        u64b_t  w[SKEIN_256_STATE_WORDS];
91300819Sallanjude        } cfg;                              /* config block */
92300819Sallanjude
93300819Sallanjude    Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
94300819Sallanjude    Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL);
95300819Sallanjude
96300819Sallanjude    /* compute the initial chaining values ctx->X[], based on key */
97300819Sallanjude    if (keyBytes == 0)                          /* is there a key? */
98300819Sallanjude        {
99300819Sallanjude        memset(ctx->X,0,sizeof(ctx->X));        /* no key: use all zeroes as key for config block */
100300819Sallanjude        }
101300819Sallanjude    else                                        /* here to pre-process a key */
102300819Sallanjude        {
103300819Sallanjude        Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X));
104300819Sallanjude        /* do a mini-Init right here */
105300819Sallanjude        ctx->h.hashBitLen=8*sizeof(ctx->X);     /* set output hash bit count = state size */
106300819Sallanjude        Skein_Start_New_Type(ctx,KEY);          /* set tweaks: T0 = 0; T1 = KEY type */
107300819Sallanjude        memset(ctx->X,0,sizeof(ctx->X));        /* zero the initial chaining variables */
108300819Sallanjude        Skein_256_Update(ctx,key,keyBytes);     /* hash the key */
109300819Sallanjude        Skein_256_Final_Pad(ctx,cfg.b);         /* put result into cfg.b[] */
110300819Sallanjude        memcpy(ctx->X,cfg.b,sizeof(cfg.b));     /* copy over into ctx->X[] */
111300819Sallanjude#if SKEIN_NEED_SWAP
112300819Sallanjude        {
113300819Sallanjude        uint_t i;
114300819Sallanjude        for (i=0;i<SKEIN_256_STATE_WORDS;i++)   /* convert key bytes to context words */
115300819Sallanjude            ctx->X[i] = Skein_Swap64(ctx->X[i]);
116300819Sallanjude        }
117300819Sallanjude#endif
118300819Sallanjude        }
119300819Sallanjude    /* build/process the config block, type == CONFIG (could be precomputed for each key) */
120300819Sallanjude    ctx->h.hashBitLen = hashBitLen;             /* output hash bit count */
121300819Sallanjude    Skein_Start_New_Type(ctx,CFG_FINAL);
122300819Sallanjude
123300819Sallanjude    memset(&cfg.w,0,sizeof(cfg.w));             /* pre-pad cfg.w[] with zeroes */
124300819Sallanjude    cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
125300819Sallanjude    cfg.w[1] = Skein_Swap64(hashBitLen);        /* hash result length in bits */
126300819Sallanjude    cfg.w[2] = Skein_Swap64(treeInfo);          /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
127300819Sallanjude
128300819Sallanjude    Skein_Show_Key(256,&ctx->h,key,keyBytes);
129300819Sallanjude
130300819Sallanjude    /* compute the initial chaining values from config block */
131300819Sallanjude    Skein_256_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
132300819Sallanjude
133300819Sallanjude    /* The chaining vars ctx->X are now initialized */
134300819Sallanjude    /* Set up to process the data message portion of the hash (default) */
135300819Sallanjude    ctx->h.bCnt = 0;                            /* buffer b[] starts out empty */
136300819Sallanjude    Skein_Start_New_Type(ctx,MSG);
137300819Sallanjude
138300819Sallanjude    return SKEIN_SUCCESS;
139300819Sallanjude    }
140300819Sallanjude
141300819Sallanjude/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
142300819Sallanjude/* process the input bytes */
143300819Sallanjudeint Skein_256_Update(Skein_256_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt)
144300819Sallanjude    {
145300819Sallanjude    size_t n;
146300819Sallanjude
147300819Sallanjude    Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
148300819Sallanjude
149300819Sallanjude    /* process full blocks, if any */
150300819Sallanjude    if (msgByteCnt + ctx->h.bCnt > SKEIN_256_BLOCK_BYTES)
151300819Sallanjude        {
152300819Sallanjude        if (ctx->h.bCnt)                              /* finish up any buffered message data */
153300819Sallanjude            {
154300819Sallanjude            n = SKEIN_256_BLOCK_BYTES - ctx->h.bCnt;  /* # bytes free in buffer b[] */
155300819Sallanjude            if (n)
156300819Sallanjude                {
157300819Sallanjude                Skein_assert(n < msgByteCnt);         /* check on our logic here */
158300819Sallanjude                memcpy(&ctx->b[ctx->h.bCnt],msg,n);
159300819Sallanjude                msgByteCnt  -= n;
160300819Sallanjude                msg         += n;
161300819Sallanjude                ctx->h.bCnt += n;
162300819Sallanjude                }
163300819Sallanjude            Skein_assert(ctx->h.bCnt == SKEIN_256_BLOCK_BYTES);
164300819Sallanjude            Skein_256_Process_Block(ctx,ctx->b,1,SKEIN_256_BLOCK_BYTES);
165300819Sallanjude            ctx->h.bCnt = 0;
166300819Sallanjude            }
167300819Sallanjude        /* now process any remaining full blocks, directly from input message data */
168300819Sallanjude        if (msgByteCnt > SKEIN_256_BLOCK_BYTES)
169300819Sallanjude            {
170300819Sallanjude            n = (msgByteCnt-1) / SKEIN_256_BLOCK_BYTES;   /* number of full blocks to process */
171300819Sallanjude            Skein_256_Process_Block(ctx,msg,n,SKEIN_256_BLOCK_BYTES);
172300819Sallanjude            msgByteCnt -= n * SKEIN_256_BLOCK_BYTES;
173300819Sallanjude            msg        += n * SKEIN_256_BLOCK_BYTES;
174300819Sallanjude            }
175300819Sallanjude        Skein_assert(ctx->h.bCnt == 0);
176300819Sallanjude        }
177300819Sallanjude
178300819Sallanjude    /* copy any remaining source message data bytes into b[] */
179300819Sallanjude    if (msgByteCnt)
180300819Sallanjude        {
181300819Sallanjude        Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES);
182300819Sallanjude        memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt);
183300819Sallanjude        ctx->h.bCnt += msgByteCnt;
184300819Sallanjude        }
185300819Sallanjude
186300819Sallanjude    return SKEIN_SUCCESS;
187300819Sallanjude    }
188300819Sallanjude
189300819Sallanjude/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
190300819Sallanjude/* finalize the hash computation and output the result */
191300819Sallanjudeint Skein_256_Final(Skein_256_Ctxt_t *ctx, u08b_t *hashVal)
192300819Sallanjude    {
193300819Sallanjude    size_t i,n,byteCnt;
194300819Sallanjude    u64b_t X[SKEIN_256_STATE_WORDS];
195300819Sallanjude    Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
196300819Sallanjude
197300819Sallanjude    ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;                 /* tag as the final block */
198300819Sallanjude    if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES)            /* zero pad b[] if necessary */
199300819Sallanjude        memset(&ctx->b[ctx->h.bCnt],0,SKEIN_256_BLOCK_BYTES - ctx->h.bCnt);
200300819Sallanjude
201300819Sallanjude    Skein_256_Process_Block(ctx,ctx->b,1,ctx->h.bCnt);  /* process the final block */
202300819Sallanjude
203300819Sallanjude    /* now output the result */
204300819Sallanjude    byteCnt = (ctx->h.hashBitLen + 7) >> 3;             /* total number of output bytes */
205300819Sallanjude
206300819Sallanjude    /* run Threefish in "counter mode" to generate output */
207300819Sallanjude    memset(ctx->b,0,sizeof(ctx->b));  /* zero out b[], so it can hold the counter */
208300819Sallanjude    memcpy(X,ctx->X,sizeof(X));       /* keep a local copy of counter mode "key" */
209300819Sallanjude    for (i=0;i*SKEIN_256_BLOCK_BYTES < byteCnt;i++)
210300819Sallanjude        {
211300819Sallanjude        ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
212300819Sallanjude        Skein_Start_New_Type(ctx,OUT_FINAL);
213300819Sallanjude        Skein_256_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
214300819Sallanjude        n = byteCnt - i*SKEIN_256_BLOCK_BYTES;   /* number of output bytes left to go */
215300819Sallanjude        if (n >= SKEIN_256_BLOCK_BYTES)
216300819Sallanjude            n  = SKEIN_256_BLOCK_BYTES;
217300819Sallanjude        Skein_Put64_LSB_First(hashVal+i*SKEIN_256_BLOCK_BYTES,ctx->X,n);   /* "output" the ctr mode bytes */
218300819Sallanjude        Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_256_BLOCK_BYTES);
219300819Sallanjude        memcpy(ctx->X,X,sizeof(X));   /* restore the counter mode key for next time */
220300819Sallanjude        }
221300819Sallanjude    return SKEIN_SUCCESS;
222300819Sallanjude    }
223300819Sallanjude
224300819Sallanjude#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
225300819Sallanjudesize_t Skein_256_API_CodeSize(void)
226300819Sallanjude    {
227300819Sallanjude    return ((u08b_t *) Skein_256_API_CodeSize) -
228300819Sallanjude           ((u08b_t *) Skein_256_Init);
229300819Sallanjude    }
230300819Sallanjude#endif
231300819Sallanjude
232300819Sallanjude/*****************************************************************/
233300819Sallanjude/*     512-bit Skein                                             */
234300819Sallanjude/*****************************************************************/
235300819Sallanjude
236300819Sallanjude/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
237300819Sallanjude/* init the context for a straight hashing operation  */
238300819Sallanjudeint Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen)
239300819Sallanjude    {
240300819Sallanjude    union
241300819Sallanjude        {
242300819Sallanjude        u08b_t  b[SKEIN_512_STATE_BYTES];
243300819Sallanjude        u64b_t  w[SKEIN_512_STATE_WORDS];
244300819Sallanjude        } cfg;                              /* config block */
245300819Sallanjude
246300819Sallanjude    Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
247300819Sallanjude    ctx->h.hashBitLen = hashBitLen;         /* output hash bit count */
248300819Sallanjude
249300819Sallanjude    switch (hashBitLen)
250300819Sallanjude        {             /* use pre-computed values, where available */
251300819Sallanjude#ifndef SKEIN_NO_PRECOMP
252300819Sallanjude        case  512: memcpy(ctx->X,SKEIN_512_IV_512,sizeof(ctx->X));  break;
253300819Sallanjude        case  384: memcpy(ctx->X,SKEIN_512_IV_384,sizeof(ctx->X));  break;
254300819Sallanjude        case  256: memcpy(ctx->X,SKEIN_512_IV_256,sizeof(ctx->X));  break;
255300819Sallanjude        case  224: memcpy(ctx->X,SKEIN_512_IV_224,sizeof(ctx->X));  break;
256300819Sallanjude#endif
257300819Sallanjude        default:
258300819Sallanjude            /* here if there is no precomputed IV value available */
259300819Sallanjude            /* build/process the config block, type == CONFIG (could be precomputed) */
260300819Sallanjude            Skein_Start_New_Type(ctx,CFG_FINAL);        /* set tweaks: T0=0; T1=CFG | FINAL */
261300819Sallanjude
262300819Sallanjude            cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);  /* set the schema, version */
263300819Sallanjude            cfg.w[1] = Skein_Swap64(hashBitLen);        /* hash result length in bits */
264300819Sallanjude            cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
265300819Sallanjude            memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */
266300819Sallanjude
267300819Sallanjude            /* compute the initial chaining values from config block */
268300819Sallanjude            memset(ctx->X,0,sizeof(ctx->X));            /* zero the chaining variables */
269300819Sallanjude            Skein_512_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
270300819Sallanjude            break;
271300819Sallanjude        }
272300819Sallanjude
273300819Sallanjude    /* The chaining vars ctx->X are now initialized for the given hashBitLen. */
274300819Sallanjude    /* Set up to process the data message portion of the hash (default) */
275300819Sallanjude    Skein_Start_New_Type(ctx,MSG);              /* T0=0, T1= MSG type */
276300819Sallanjude
277300819Sallanjude    return SKEIN_SUCCESS;
278300819Sallanjude    }
279300819Sallanjude
280300819Sallanjude/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
281300819Sallanjude/* init the context for a MAC and/or tree hash operation */
282300819Sallanjude/* [identical to Skein_512_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */
283300819Sallanjudeint Skein_512_InitExt(Skein_512_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes)
284300819Sallanjude    {
285300819Sallanjude    union
286300819Sallanjude        {
287300819Sallanjude        u08b_t  b[SKEIN_512_STATE_BYTES];
288300819Sallanjude        u64b_t  w[SKEIN_512_STATE_WORDS];
289300819Sallanjude        } cfg;                              /* config block */
290300819Sallanjude
291300819Sallanjude    Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
292300819Sallanjude    Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL);
293300819Sallanjude
294300819Sallanjude    /* compute the initial chaining values ctx->X[], based on key */
295300819Sallanjude    if (keyBytes == 0)                          /* is there a key? */
296300819Sallanjude        {
297300819Sallanjude        memset(ctx->X,0,sizeof(ctx->X));        /* no key: use all zeroes as key for config block */
298300819Sallanjude        }
299300819Sallanjude    else                                        /* here to pre-process a key */
300300819Sallanjude        {
301300819Sallanjude        Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X));
302300819Sallanjude        /* do a mini-Init right here */
303300819Sallanjude        ctx->h.hashBitLen=8*sizeof(ctx->X);     /* set output hash bit count = state size */
304300819Sallanjude        Skein_Start_New_Type(ctx,KEY);          /* set tweaks: T0 = 0; T1 = KEY type */
305300819Sallanjude        memset(ctx->X,0,sizeof(ctx->X));        /* zero the initial chaining variables */
306300819Sallanjude        Skein_512_Update(ctx,key,keyBytes);     /* hash the key */
307300819Sallanjude        Skein_512_Final_Pad(ctx,cfg.b);         /* put result into cfg.b[] */
308300819Sallanjude        memcpy(ctx->X,cfg.b,sizeof(cfg.b));     /* copy over into ctx->X[] */
309300819Sallanjude#if SKEIN_NEED_SWAP
310300819Sallanjude        {
311300819Sallanjude        uint_t i;
312300819Sallanjude        for (i=0;i<SKEIN_512_STATE_WORDS;i++)   /* convert key bytes to context words */
313300819Sallanjude            ctx->X[i] = Skein_Swap64(ctx->X[i]);
314300819Sallanjude        }
315300819Sallanjude#endif
316300819Sallanjude        }
317300819Sallanjude    /* build/process the config block, type == CONFIG (could be precomputed for each key) */
318300819Sallanjude    ctx->h.hashBitLen = hashBitLen;             /* output hash bit count */
319300819Sallanjude    Skein_Start_New_Type(ctx,CFG_FINAL);
320300819Sallanjude
321300819Sallanjude    memset(&cfg.w,0,sizeof(cfg.w));             /* pre-pad cfg.w[] with zeroes */
322300819Sallanjude    cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
323300819Sallanjude    cfg.w[1] = Skein_Swap64(hashBitLen);        /* hash result length in bits */
324300819Sallanjude    cfg.w[2] = Skein_Swap64(treeInfo);          /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
325300819Sallanjude
326300819Sallanjude    Skein_Show_Key(512,&ctx->h,key,keyBytes);
327300819Sallanjude
328300819Sallanjude    /* compute the initial chaining values from config block */
329300819Sallanjude    Skein_512_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
330300819Sallanjude
331300819Sallanjude    /* The chaining vars ctx->X are now initialized */
332300819Sallanjude    /* Set up to process the data message portion of the hash (default) */
333300819Sallanjude    ctx->h.bCnt = 0;                            /* buffer b[] starts out empty */
334300819Sallanjude    Skein_Start_New_Type(ctx,MSG);
335300819Sallanjude
336300819Sallanjude    return SKEIN_SUCCESS;
337300819Sallanjude    }
338300819Sallanjude
339300819Sallanjude/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
340300819Sallanjude/* process the input bytes */
341300819Sallanjudeint Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt)
342300819Sallanjude    {
343300819Sallanjude    size_t n;
344300819Sallanjude
345300819Sallanjude    Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
346300819Sallanjude
347300819Sallanjude    /* process full blocks, if any */
348300819Sallanjude    if (msgByteCnt + ctx->h.bCnt > SKEIN_512_BLOCK_BYTES)
349300819Sallanjude        {
350300819Sallanjude        if (ctx->h.bCnt)                              /* finish up any buffered message data */
351300819Sallanjude            {
352300819Sallanjude            n = SKEIN_512_BLOCK_BYTES - ctx->h.bCnt;  /* # bytes free in buffer b[] */
353300819Sallanjude            if (n)
354300819Sallanjude                {
355300819Sallanjude                Skein_assert(n < msgByteCnt);         /* check on our logic here */
356300819Sallanjude                memcpy(&ctx->b[ctx->h.bCnt],msg,n);
357300819Sallanjude                msgByteCnt  -= n;
358300819Sallanjude                msg         += n;
359300819Sallanjude                ctx->h.bCnt += n;
360300819Sallanjude                }
361300819Sallanjude            Skein_assert(ctx->h.bCnt == SKEIN_512_BLOCK_BYTES);
362300819Sallanjude            Skein_512_Process_Block(ctx,ctx->b,1,SKEIN_512_BLOCK_BYTES);
363300819Sallanjude            ctx->h.bCnt = 0;
364300819Sallanjude            }
365300819Sallanjude        /* now process any remaining full blocks, directly from input message data */
366300819Sallanjude        if (msgByteCnt > SKEIN_512_BLOCK_BYTES)
367300819Sallanjude            {
368300819Sallanjude            n = (msgByteCnt-1) / SKEIN_512_BLOCK_BYTES;   /* number of full blocks to process */
369300819Sallanjude            Skein_512_Process_Block(ctx,msg,n,SKEIN_512_BLOCK_BYTES);
370300819Sallanjude            msgByteCnt -= n * SKEIN_512_BLOCK_BYTES;
371300819Sallanjude            msg        += n * SKEIN_512_BLOCK_BYTES;
372300819Sallanjude            }
373300819Sallanjude        Skein_assert(ctx->h.bCnt == 0);
374300819Sallanjude        }
375300819Sallanjude
376300819Sallanjude    /* copy any remaining source message data bytes into b[] */
377300819Sallanjude    if (msgByteCnt)
378300819Sallanjude        {
379300819Sallanjude        Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES);
380300819Sallanjude        memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt);
381300819Sallanjude        ctx->h.bCnt += msgByteCnt;
382300819Sallanjude        }
383300819Sallanjude
384300819Sallanjude    return SKEIN_SUCCESS;
385300819Sallanjude    }
386300819Sallanjude
387300819Sallanjude/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
388300819Sallanjude/* finalize the hash computation and output the result */
389300819Sallanjudeint Skein_512_Final(Skein_512_Ctxt_t *ctx, u08b_t *hashVal)
390300819Sallanjude    {
391300819Sallanjude    size_t i,n,byteCnt;
392300819Sallanjude    u64b_t X[SKEIN_512_STATE_WORDS];
393300819Sallanjude    Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
394300819Sallanjude
395300819Sallanjude    ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;                 /* tag as the final block */
396300819Sallanjude    if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES)            /* zero pad b[] if necessary */
397300819Sallanjude        memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt);
398300819Sallanjude
399300819Sallanjude    Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt);  /* process the final block */
400300819Sallanjude
401300819Sallanjude    /* now output the result */
402300819Sallanjude    byteCnt = (ctx->h.hashBitLen + 7) >> 3;             /* total number of output bytes */
403300819Sallanjude
404300819Sallanjude    /* run Threefish in "counter mode" to generate output */
405300819Sallanjude    memset(ctx->b,0,sizeof(ctx->b));  /* zero out b[], so it can hold the counter */
406300819Sallanjude    memcpy(X,ctx->X,sizeof(X));       /* keep a local copy of counter mode "key" */
407300819Sallanjude    for (i=0;i*SKEIN_512_BLOCK_BYTES < byteCnt;i++)
408300819Sallanjude        {
409300819Sallanjude        ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
410300819Sallanjude        Skein_Start_New_Type(ctx,OUT_FINAL);
411300819Sallanjude        Skein_512_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
412300819Sallanjude        n = byteCnt - i*SKEIN_512_BLOCK_BYTES;   /* number of output bytes left to go */
413300819Sallanjude        if (n >= SKEIN_512_BLOCK_BYTES)
414300819Sallanjude            n  = SKEIN_512_BLOCK_BYTES;
415300819Sallanjude        Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES,ctx->X,n);   /* "output" the ctr mode bytes */
416300819Sallanjude        Skein_Show_Final(512,&ctx->h,n,hashVal+i*SKEIN_512_BLOCK_BYTES);
417300819Sallanjude        memcpy(ctx->X,X,sizeof(X));   /* restore the counter mode key for next time */
418300819Sallanjude        }
419300819Sallanjude    return SKEIN_SUCCESS;
420300819Sallanjude    }
421300819Sallanjude
422300819Sallanjude#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
423300819Sallanjudesize_t Skein_512_API_CodeSize(void)
424300819Sallanjude    {
425300819Sallanjude    return ((u08b_t *) Skein_512_API_CodeSize) -
426300819Sallanjude           ((u08b_t *) Skein_512_Init);
427300819Sallanjude    }
428300819Sallanjude#endif
429300819Sallanjude
430300819Sallanjude/*****************************************************************/
431300819Sallanjude/*    1024-bit Skein                                             */
432300819Sallanjude/*****************************************************************/
433300819Sallanjude
434300819Sallanjude/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
435300819Sallanjude/* init the context for a straight hashing operation  */
436300819Sallanjudeint Skein1024_Init(Skein1024_Ctxt_t *ctx, size_t hashBitLen)
437300819Sallanjude    {
438300819Sallanjude    union
439300819Sallanjude        {
440300819Sallanjude        u08b_t  b[SKEIN1024_STATE_BYTES];
441300819Sallanjude        u64b_t  w[SKEIN1024_STATE_WORDS];
442300819Sallanjude        } cfg;                              /* config block */
443300819Sallanjude
444300819Sallanjude    Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
445300819Sallanjude    ctx->h.hashBitLen = hashBitLen;         /* output hash bit count */
446300819Sallanjude
447300819Sallanjude    switch (hashBitLen)
448300819Sallanjude        {              /* use pre-computed values, where available */
449300819Sallanjude#ifndef SKEIN_NO_PRECOMP
450300819Sallanjude        case  512: memcpy(ctx->X,SKEIN1024_IV_512 ,sizeof(ctx->X)); break;
451300819Sallanjude        case  384: memcpy(ctx->X,SKEIN1024_IV_384 ,sizeof(ctx->X)); break;
452300819Sallanjude        case 1024: memcpy(ctx->X,SKEIN1024_IV_1024,sizeof(ctx->X)); break;
453300819Sallanjude#endif
454300819Sallanjude        default:
455300819Sallanjude            /* here if there is no precomputed IV value available */
456300819Sallanjude            /* build/process the config block, type == CONFIG (could be precomputed) */
457300819Sallanjude            Skein_Start_New_Type(ctx,CFG_FINAL);        /* set tweaks: T0=0; T1=CFG | FINAL */
458300819Sallanjude
459300819Sallanjude            cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);  /* set the schema, version */
460300819Sallanjude            cfg.w[1] = Skein_Swap64(hashBitLen);        /* hash result length in bits */
461300819Sallanjude            cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
462300819Sallanjude            memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */
463300819Sallanjude
464300819Sallanjude            /* compute the initial chaining values from config block */
465300819Sallanjude            memset(ctx->X,0,sizeof(ctx->X));            /* zero the chaining variables */
466300819Sallanjude            Skein1024_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
467300819Sallanjude            break;
468300819Sallanjude        }
469300819Sallanjude
470300819Sallanjude    /* The chaining vars ctx->X are now initialized for the given hashBitLen. */
471300819Sallanjude    /* Set up to process the data message portion of the hash (default) */
472300819Sallanjude    Skein_Start_New_Type(ctx,MSG);              /* T0=0, T1= MSG type */
473300819Sallanjude
474300819Sallanjude    return SKEIN_SUCCESS;
475300819Sallanjude    }
476300819Sallanjude
477300819Sallanjude/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
478300819Sallanjude/* init the context for a MAC and/or tree hash operation */
479300819Sallanjude/* [identical to Skein1024_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */
480300819Sallanjudeint Skein1024_InitExt(Skein1024_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes)
481300819Sallanjude    {
482300819Sallanjude    union
483300819Sallanjude        {
484300819Sallanjude        u08b_t  b[SKEIN1024_STATE_BYTES];
485300819Sallanjude        u64b_t  w[SKEIN1024_STATE_WORDS];
486300819Sallanjude        } cfg;                              /* config block */
487300819Sallanjude
488300819Sallanjude    Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
489300819Sallanjude    Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL);
490300819Sallanjude
491300819Sallanjude    /* compute the initial chaining values ctx->X[], based on key */
492300819Sallanjude    if (keyBytes == 0)                          /* is there a key? */
493300819Sallanjude        {
494300819Sallanjude        memset(ctx->X,0,sizeof(ctx->X));        /* no key: use all zeroes as key for config block */
495300819Sallanjude        }
496300819Sallanjude    else                                        /* here to pre-process a key */
497300819Sallanjude        {
498300819Sallanjude        Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X));
499300819Sallanjude        /* do a mini-Init right here */
500300819Sallanjude        ctx->h.hashBitLen=8*sizeof(ctx->X);     /* set output hash bit count = state size */
501300819Sallanjude        Skein_Start_New_Type(ctx,KEY);          /* set tweaks: T0 = 0; T1 = KEY type */
502300819Sallanjude        memset(ctx->X,0,sizeof(ctx->X));        /* zero the initial chaining variables */
503300819Sallanjude        Skein1024_Update(ctx,key,keyBytes);     /* hash the key */
504300819Sallanjude        Skein1024_Final_Pad(ctx,cfg.b);         /* put result into cfg.b[] */
505300819Sallanjude        memcpy(ctx->X,cfg.b,sizeof(cfg.b));     /* copy over into ctx->X[] */
506300819Sallanjude#if SKEIN_NEED_SWAP
507300819Sallanjude        {
508300819Sallanjude        uint_t i;
509300819Sallanjude        for (i=0;i<SKEIN1024_STATE_WORDS;i++)   /* convert key bytes to context words */
510300819Sallanjude            ctx->X[i] = Skein_Swap64(ctx->X[i]);
511300819Sallanjude        }
512300819Sallanjude#endif
513300819Sallanjude        }
514300819Sallanjude    /* build/process the config block, type == CONFIG (could be precomputed for each key) */
515300819Sallanjude    ctx->h.hashBitLen = hashBitLen;             /* output hash bit count */
516300819Sallanjude    Skein_Start_New_Type(ctx,CFG_FINAL);
517300819Sallanjude
518300819Sallanjude    memset(&cfg.w,0,sizeof(cfg.w));             /* pre-pad cfg.w[] with zeroes */
519300819Sallanjude    cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
520300819Sallanjude    cfg.w[1] = Skein_Swap64(hashBitLen);        /* hash result length in bits */
521300819Sallanjude    cfg.w[2] = Skein_Swap64(treeInfo);          /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
522300819Sallanjude
523300819Sallanjude    Skein_Show_Key(1024,&ctx->h,key,keyBytes);
524300819Sallanjude
525300819Sallanjude    /* compute the initial chaining values from config block */
526300819Sallanjude    Skein1024_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
527300819Sallanjude
528300819Sallanjude    /* The chaining vars ctx->X are now initialized */
529300819Sallanjude    /* Set up to process the data message portion of the hash (default) */
530300819Sallanjude    ctx->h.bCnt = 0;                            /* buffer b[] starts out empty */
531300819Sallanjude    Skein_Start_New_Type(ctx,MSG);
532300819Sallanjude
533300819Sallanjude    return SKEIN_SUCCESS;
534300819Sallanjude    }
535300819Sallanjude
536300819Sallanjude/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
537300819Sallanjude/* process the input bytes */
538300819Sallanjudeint Skein1024_Update(Skein1024_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt)
539300819Sallanjude    {
540300819Sallanjude    size_t n;
541300819Sallanjude
542300819Sallanjude    Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
543300819Sallanjude
544300819Sallanjude    /* process full blocks, if any */
545300819Sallanjude    if (msgByteCnt + ctx->h.bCnt > SKEIN1024_BLOCK_BYTES)
546300819Sallanjude        {
547300819Sallanjude        if (ctx->h.bCnt)                              /* finish up any buffered message data */
548300819Sallanjude            {
549300819Sallanjude            n = SKEIN1024_BLOCK_BYTES - ctx->h.bCnt;  /* # bytes free in buffer b[] */
550300819Sallanjude            if (n)
551300819Sallanjude                {
552300819Sallanjude                Skein_assert(n < msgByteCnt);         /* check on our logic here */
553300819Sallanjude                memcpy(&ctx->b[ctx->h.bCnt],msg,n);
554300819Sallanjude                msgByteCnt  -= n;
555300819Sallanjude                msg         += n;
556300819Sallanjude                ctx->h.bCnt += n;
557300819Sallanjude                }
558300819Sallanjude            Skein_assert(ctx->h.bCnt == SKEIN1024_BLOCK_BYTES);
559300819Sallanjude            Skein1024_Process_Block(ctx,ctx->b,1,SKEIN1024_BLOCK_BYTES);
560300819Sallanjude            ctx->h.bCnt = 0;
561300819Sallanjude            }
562300819Sallanjude        /* now process any remaining full blocks, directly from input message data */
563300819Sallanjude        if (msgByteCnt > SKEIN1024_BLOCK_BYTES)
564300819Sallanjude            {
565300819Sallanjude            n = (msgByteCnt-1) / SKEIN1024_BLOCK_BYTES;   /* number of full blocks to process */
566300819Sallanjude            Skein1024_Process_Block(ctx,msg,n,SKEIN1024_BLOCK_BYTES);
567300819Sallanjude            msgByteCnt -= n * SKEIN1024_BLOCK_BYTES;
568300819Sallanjude            msg        += n * SKEIN1024_BLOCK_BYTES;
569300819Sallanjude            }
570300819Sallanjude        Skein_assert(ctx->h.bCnt == 0);
571300819Sallanjude        }
572300819Sallanjude
573300819Sallanjude    /* copy any remaining source message data bytes into b[] */
574300819Sallanjude    if (msgByteCnt)
575300819Sallanjude        {
576300819Sallanjude        Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES);
577300819Sallanjude        memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt);
578300819Sallanjude        ctx->h.bCnt += msgByteCnt;
579300819Sallanjude        }
580300819Sallanjude
581300819Sallanjude    return SKEIN_SUCCESS;
582300819Sallanjude    }
583300819Sallanjude
584300819Sallanjude/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
585300819Sallanjude/* finalize the hash computation and output the result */
586300819Sallanjudeint Skein1024_Final(Skein1024_Ctxt_t *ctx, u08b_t *hashVal)
587300819Sallanjude    {
588300819Sallanjude    size_t i,n,byteCnt;
589300819Sallanjude    u64b_t X[SKEIN1024_STATE_WORDS];
590300819Sallanjude    Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
591300819Sallanjude
592300819Sallanjude    ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;                 /* tag as the final block */
593300819Sallanjude    if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES)            /* zero pad b[] if necessary */
594300819Sallanjude        memset(&ctx->b[ctx->h.bCnt],0,SKEIN1024_BLOCK_BYTES - ctx->h.bCnt);
595300819Sallanjude
596300819Sallanjude    Skein1024_Process_Block(ctx,ctx->b,1,ctx->h.bCnt);  /* process the final block */
597300819Sallanjude
598300819Sallanjude    /* now output the result */
599300819Sallanjude    byteCnt = (ctx->h.hashBitLen + 7) >> 3;             /* total number of output bytes */
600300819Sallanjude
601300819Sallanjude    /* run Threefish in "counter mode" to generate output */
602300819Sallanjude    memset(ctx->b,0,sizeof(ctx->b));  /* zero out b[], so it can hold the counter */
603300819Sallanjude    memcpy(X,ctx->X,sizeof(X));       /* keep a local copy of counter mode "key" */
604300819Sallanjude    for (i=0;i*SKEIN1024_BLOCK_BYTES < byteCnt;i++)
605300819Sallanjude        {
606300819Sallanjude        ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
607300819Sallanjude        Skein_Start_New_Type(ctx,OUT_FINAL);
608300819Sallanjude        Skein1024_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
609300819Sallanjude        n = byteCnt - i*SKEIN1024_BLOCK_BYTES;   /* number of output bytes left to go */
610300819Sallanjude        if (n >= SKEIN1024_BLOCK_BYTES)
611300819Sallanjude            n  = SKEIN1024_BLOCK_BYTES;
612300819Sallanjude        Skein_Put64_LSB_First(hashVal+i*SKEIN1024_BLOCK_BYTES,ctx->X,n);   /* "output" the ctr mode bytes */
613300819Sallanjude        Skein_Show_Final(1024,&ctx->h,n,hashVal+i*SKEIN1024_BLOCK_BYTES);
614300819Sallanjude        memcpy(ctx->X,X,sizeof(X));   /* restore the counter mode key for next time */
615300819Sallanjude        }
616300819Sallanjude    return SKEIN_SUCCESS;
617300819Sallanjude    }
618300819Sallanjude
619300819Sallanjude#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
620300819Sallanjudesize_t Skein1024_API_CodeSize(void)
621300819Sallanjude    {
622300819Sallanjude    return ((u08b_t *) Skein1024_API_CodeSize) -
623300819Sallanjude           ((u08b_t *) Skein1024_Init);
624300819Sallanjude    }
625300819Sallanjude#endif
626300819Sallanjude
627300819Sallanjude/**************** Functions to support MAC/tree hashing ***************/
628300819Sallanjude/*   (this code is identical for Optimized and Reference versions)    */
629300819Sallanjude
630300819Sallanjude/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
631300819Sallanjude/* finalize the hash computation and output the block, no OUTPUT stage */
632300819Sallanjudeint Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, u08b_t *hashVal)
633300819Sallanjude    {
634300819Sallanjude    Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
635300819Sallanjude
636300819Sallanjude    ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;        /* tag as the final block */
637300819Sallanjude    if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES)   /* zero pad b[] if necessary */
638300819Sallanjude        memset(&ctx->b[ctx->h.bCnt],0,SKEIN_256_BLOCK_BYTES - ctx->h.bCnt);
639300819Sallanjude    Skein_256_Process_Block(ctx,ctx->b,1,ctx->h.bCnt);    /* process the final block */
640300819Sallanjude
641300819Sallanjude    Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN_256_BLOCK_BYTES);   /* "output" the state bytes */
642300819Sallanjude
643300819Sallanjude    return SKEIN_SUCCESS;
644300819Sallanjude    }
645300819Sallanjude
646300819Sallanjude/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
647300819Sallanjude/* finalize the hash computation and output the block, no OUTPUT stage */
648300819Sallanjudeint Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, u08b_t *hashVal)
649300819Sallanjude    {
650300819Sallanjude    Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
651300819Sallanjude
652300819Sallanjude    ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;        /* tag as the final block */
653300819Sallanjude    if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES)   /* zero pad b[] if necessary */
654300819Sallanjude        memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt);
655300819Sallanjude    Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt);    /* process the final block */
656300819Sallanjude
657300819Sallanjude    Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN_512_BLOCK_BYTES);   /* "output" the state bytes */
658300819Sallanjude
659300819Sallanjude    return SKEIN_SUCCESS;
660300819Sallanjude    }
661300819Sallanjude
662300819Sallanjude/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
663300819Sallanjude/* finalize the hash computation and output the block, no OUTPUT stage */
664300819Sallanjudeint Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, u08b_t *hashVal)
665300819Sallanjude    {
666300819Sallanjude    Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
667300819Sallanjude
668300819Sallanjude    ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;        /* tag as the final block */
669300819Sallanjude    if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES)   /* zero pad b[] if necessary */
670300819Sallanjude        memset(&ctx->b[ctx->h.bCnt],0,SKEIN1024_BLOCK_BYTES - ctx->h.bCnt);
671300819Sallanjude    Skein1024_Process_Block(ctx,ctx->b,1,ctx->h.bCnt);    /* process the final block */
672300819Sallanjude
673300819Sallanjude    Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN1024_BLOCK_BYTES);   /* "output" the state bytes */
674300819Sallanjude
675300819Sallanjude    return SKEIN_SUCCESS;
676300819Sallanjude    }
677300819Sallanjude
678300819Sallanjude#if SKEIN_TREE_HASH
679300819Sallanjude/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
680300819Sallanjude/* just do the OUTPUT stage                                       */
681300819Sallanjudeint Skein_256_Output(Skein_256_Ctxt_t *ctx, u08b_t *hashVal)
682300819Sallanjude    {
683300819Sallanjude    size_t i,n,byteCnt;
684300819Sallanjude    u64b_t X[SKEIN_256_STATE_WORDS];
685300819Sallanjude    Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
686300819Sallanjude
687300819Sallanjude    /* now output the result */
688300819Sallanjude    byteCnt = (ctx->h.hashBitLen + 7) >> 3;    /* total number of output bytes */
689300819Sallanjude
690300819Sallanjude    /* run Threefish in "counter mode" to generate output */
691300819Sallanjude    memset(ctx->b,0,sizeof(ctx->b));  /* zero out b[], so it can hold the counter */
692300819Sallanjude    memcpy(X,ctx->X,sizeof(X));       /* keep a local copy of counter mode "key" */
693300819Sallanjude    for (i=0;i*SKEIN_256_BLOCK_BYTES < byteCnt;i++)
694300819Sallanjude        {
695300819Sallanjude        ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
696300819Sallanjude        Skein_Start_New_Type(ctx,OUT_FINAL);
697300819Sallanjude        Skein_256_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
698300819Sallanjude        n = byteCnt - i*SKEIN_256_BLOCK_BYTES;   /* number of output bytes left to go */
699300819Sallanjude        if (n >= SKEIN_256_BLOCK_BYTES)
700300819Sallanjude            n  = SKEIN_256_BLOCK_BYTES;
701300819Sallanjude        Skein_Put64_LSB_First(hashVal+i*SKEIN_256_BLOCK_BYTES,ctx->X,n);   /* "output" the ctr mode bytes */
702300819Sallanjude        Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_256_BLOCK_BYTES);
703300819Sallanjude        memcpy(ctx->X,X,sizeof(X));   /* restore the counter mode key for next time */
704300819Sallanjude        }
705300819Sallanjude    return SKEIN_SUCCESS;
706300819Sallanjude    }
707300819Sallanjude
708300819Sallanjude/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
709300819Sallanjude/* just do the OUTPUT stage                                       */
710300819Sallanjudeint Skein_512_Output(Skein_512_Ctxt_t *ctx, u08b_t *hashVal)
711300819Sallanjude    {
712300819Sallanjude    size_t i,n,byteCnt;
713300819Sallanjude    u64b_t X[SKEIN_512_STATE_WORDS];
714300819Sallanjude    Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
715300819Sallanjude
716300819Sallanjude    /* now output the result */
717300819Sallanjude    byteCnt = (ctx->h.hashBitLen + 7) >> 3;    /* total number of output bytes */
718300819Sallanjude
719300819Sallanjude    /* run Threefish in "counter mode" to generate output */
720300819Sallanjude    memset(ctx->b,0,sizeof(ctx->b));  /* zero out b[], so it can hold the counter */
721300819Sallanjude    memcpy(X,ctx->X,sizeof(X));       /* keep a local copy of counter mode "key" */
722300819Sallanjude    for (i=0;i*SKEIN_512_BLOCK_BYTES < byteCnt;i++)
723300819Sallanjude        {
724300819Sallanjude        ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
725300819Sallanjude        Skein_Start_New_Type(ctx,OUT_FINAL);
726300819Sallanjude        Skein_512_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
727300819Sallanjude        n = byteCnt - i*SKEIN_512_BLOCK_BYTES;   /* number of output bytes left to go */
728300819Sallanjude        if (n >= SKEIN_512_BLOCK_BYTES)
729300819Sallanjude            n  = SKEIN_512_BLOCK_BYTES;
730300819Sallanjude        Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES,ctx->X,n);   /* "output" the ctr mode bytes */
731300819Sallanjude        Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_512_BLOCK_BYTES);
732300819Sallanjude        memcpy(ctx->X,X,sizeof(X));   /* restore the counter mode key for next time */
733300819Sallanjude        }
734300819Sallanjude    return SKEIN_SUCCESS;
735300819Sallanjude    }
736300819Sallanjude
737300819Sallanjude/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
738300819Sallanjude/* just do the OUTPUT stage                                       */
739300819Sallanjudeint Skein1024_Output(Skein1024_Ctxt_t *ctx, u08b_t *hashVal)
740300819Sallanjude    {
741300819Sallanjude    size_t i,n,byteCnt;
742300819Sallanjude    u64b_t X[SKEIN1024_STATE_WORDS];
743300819Sallanjude    Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
744300819Sallanjude
745300819Sallanjude    /* now output the result */
746300819Sallanjude    byteCnt = (ctx->h.hashBitLen + 7) >> 3;    /* total number of output bytes */
747300819Sallanjude
748300819Sallanjude    /* run Threefish in "counter mode" to generate output */
749300819Sallanjude    memset(ctx->b,0,sizeof(ctx->b));  /* zero out b[], so it can hold the counter */
750300819Sallanjude    memcpy(X,ctx->X,sizeof(X));       /* keep a local copy of counter mode "key" */
751300819Sallanjude    for (i=0;i*SKEIN1024_BLOCK_BYTES < byteCnt;i++)
752300819Sallanjude        {
753300819Sallanjude        ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
754300819Sallanjude        Skein_Start_New_Type(ctx,OUT_FINAL);
755300819Sallanjude        Skein1024_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
756300819Sallanjude        n = byteCnt - i*SKEIN1024_BLOCK_BYTES;   /* number of output bytes left to go */
757300819Sallanjude        if (n >= SKEIN1024_BLOCK_BYTES)
758300819Sallanjude            n  = SKEIN1024_BLOCK_BYTES;
759300819Sallanjude        Skein_Put64_LSB_First(hashVal+i*SKEIN1024_BLOCK_BYTES,ctx->X,n);   /* "output" the ctr mode bytes */
760300819Sallanjude        Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN1024_BLOCK_BYTES);
761300819Sallanjude        memcpy(ctx->X,X,sizeof(X));   /* restore the counter mode key for next time */
762300819Sallanjude        }
763300819Sallanjude    return SKEIN_SUCCESS;
764300819Sallanjude    }
765300921Sallanjude
766300921Sallanjude
767300921Sallanjude/* Adapt the functions to match the prototype expected by libmd */
768300921Sallanjudevoid
769300921SallanjudeSKEIN256_Init(SKEIN256_CTX * ctx)
770300921Sallanjude{
771300921Sallanjude
772300921Sallanjude	Skein_256_Init(ctx, 256);
773300921Sallanjude}
774300921Sallanjude
775300921Sallanjudevoid
776300921SallanjudeSKEIN512_Init(SKEIN512_CTX * ctx)
777300921Sallanjude{
778300921Sallanjude
779300921Sallanjude	Skein_512_Init(ctx, 512);
780300921Sallanjude}
781300921Sallanjude
782300921Sallanjudevoid
783300921SallanjudeSKEIN1024_Init(SKEIN1024_CTX * ctx)
784300921Sallanjude{
785300921Sallanjude
786300921Sallanjude	Skein1024_Init(ctx, 1024);
787300921Sallanjude}
788300921Sallanjude
789300921Sallanjudevoid
790300921SallanjudeSKEIN256_Update(SKEIN256_CTX * ctx, const void *in, size_t len)
791300921Sallanjude{
792300921Sallanjude
793300921Sallanjude	Skein_256_Update(ctx, in, len);
794300921Sallanjude}
795300921Sallanjude
796300921Sallanjudevoid
797300921SallanjudeSKEIN512_Update(SKEIN512_CTX * ctx, const void *in, size_t len)
798300921Sallanjude{
799300921Sallanjude
800300921Sallanjude	Skein_512_Update(ctx, in, len);
801300921Sallanjude}
802300921Sallanjude
803300921Sallanjudevoid
804300921SallanjudeSKEIN1024_Update(SKEIN1024_CTX * ctx, const void *in, size_t len)
805300921Sallanjude{
806300921Sallanjude
807300921Sallanjude	Skein1024_Update(ctx, in, len);
808300921Sallanjude}
809300921Sallanjude
810300921Sallanjudevoid
811300921SallanjudeSKEIN256_Final(unsigned char digest[static SKEIN_256_BLOCK_BYTES], SKEIN256_CTX *ctx)
812300921Sallanjude{
813300921Sallanjude
814300921Sallanjude	Skein_256_Final(ctx, digest);
815300921Sallanjude}
816300921Sallanjude
817300921Sallanjudevoid
818300921SallanjudeSKEIN512_Final(unsigned char digest[static SKEIN_512_BLOCK_BYTES], SKEIN512_CTX *ctx)
819300921Sallanjude{
820300921Sallanjude
821300921Sallanjude	Skein_512_Final(ctx, digest);
822300921Sallanjude}
823300921Sallanjude
824300921Sallanjudevoid
825300921SallanjudeSKEIN1024_Final(unsigned char digest[static SKEIN1024_BLOCK_BYTES], SKEIN1024_CTX *ctx)
826300921Sallanjude{
827300921Sallanjude
828300921Sallanjude	Skein1024_Final(ctx, digest);
829300921Sallanjude}
830300921Sallanjude
831300921Sallanjude#ifdef WEAK_REFS
832300921Sallanjude/* When building libmd, provide weak references. Note: this is not
833300921Sallanjude   activated in the context of compiling these sources for internal
834300921Sallanjude   use in libcrypt.
835300921Sallanjude */
836300921Sallanjude#undef SKEIN256_Init
837300921Sallanjude__weak_reference(_libmd_SKEIN256_Init, SKEIN256_Init);
838300921Sallanjude#undef SKEIN256_Update
839300921Sallanjude__weak_reference(_libmd_SKEIN256_Update, SKEIN256_Update);
840300921Sallanjude#undef SKEIN256_Final
841300921Sallanjude__weak_reference(_libmd_SKEIN256_Final, SKEIN256_Final);
842300921Sallanjude
843300921Sallanjude#undef SKEIN512_Init
844300921Sallanjude__weak_reference(_libmd_SKEIN512_Init, SKEIN512_Init);
845300921Sallanjude#undef SKEIN512_Update
846300921Sallanjude__weak_reference(_libmd_SKEIN512_Update, SKEIN512_Update);
847300921Sallanjude#undef SKEIN512_Final
848300921Sallanjude__weak_reference(_libmd_SKEIN512_Final, SKEIN512_Final);
849300921Sallanjude
850300921Sallanjude#undef SKEIN1024_Init
851300921Sallanjude__weak_reference(_libmd_SKEIN1024_Init, SKEIN1024_Init);
852300921Sallanjude#undef SKEIN1024_Update
853300921Sallanjude__weak_reference(_libmd_SKEIN1024_Update, SKEIN1024_Update);
854300921Sallanjude#undef SKEIN1024_Final
855300921Sallanjude__weak_reference(_libmd_SKEIN1024_Final, SKEIN1024_Final);
856300819Sallanjude#endif
857300921Sallanjude
858300921Sallanjude#endif
859