]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/staging/skein/skein_base.c
Merge remote-tracking branches 'asoc/topic/txx9', 'asoc/topic/wm8750', 'asoc/topic...
[mirror_ubuntu-artful-kernel.git] / drivers / staging / skein / skein_base.c
CommitLineData
449bb812
JC
1/***********************************************************************
2**
3** Implementation of the Skein hash function.
4**
5** Source code author: Doug Whiting, 2008.
6**
7** This algorithm and source code is released to the public domain.
8**
9************************************************************************/
10
c2c7426b 11#include <linux/string.h> /* get the memcpy/memset functions */
c17cdeb4
ER
12#include <linux/export.h>
13#include "skein_base.h" /* get the Skein API definitions */
85dfd522
JE
14#include "skein_iv.h" /* get precomputed IVs */
15#include "skein_block.h"
449bb812
JC
16
17/*****************************************************************/
18/* 256-bit Skein */
19/*****************************************************************/
20
21/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
22/* init the context for a straight hashing operation */
95f1840a 23int skein_256_init(struct skein_256_ctx *ctx, size_t hash_bit_len)
449bb812 24{
161a2afd 25 union {
95f1840a
AS
26 u8 b[SKEIN_256_STATE_BYTES];
27 u64 w[SKEIN_256_STATE_WORDS];
39bd42b0
JC
28 } cfg; /* config block */
29
0264b7b7 30 skein_assert_ret(hash_bit_len > 0, SKEIN_BAD_HASHLEN);
95f1840a 31 ctx->h.hash_bit_len = hash_bit_len; /* output hash bit count */
39bd42b0 32
95f1840a 33 switch (hash_bit_len) { /* use pre-computed values, where available */
39bd42b0 34 case 256:
007dfe5a 35 memcpy(ctx->x, SKEIN_256_IV_256, sizeof(ctx->x));
39bd42b0
JC
36 break;
37 case 224:
007dfe5a 38 memcpy(ctx->x, SKEIN_256_IV_224, sizeof(ctx->x));
39bd42b0
JC
39 break;
40 case 160:
007dfe5a 41 memcpy(ctx->x, SKEIN_256_IV_160, sizeof(ctx->x));
39bd42b0
JC
42 break;
43 case 128:
007dfe5a 44 memcpy(ctx->x, SKEIN_256_IV_128, sizeof(ctx->x));
39bd42b0
JC
45 break;
46 default:
47 /* here if there is no precomputed IV value available */
60eb8175
JC
48 /*
49 * build/process the config block, type == CONFIG (could be
50 * precomputed)
51 */
52 /* set tweaks: T0=0; T1=CFG | FINAL */
0264b7b7 53 skein_start_new_type(ctx, CFG_FINAL);
60eb8175
JC
54
55 /* set the schema, version */
0264b7b7 56 cfg.w[0] = skein_swap64(SKEIN_SCHEMA_VER);
60eb8175 57 /* hash result length in bits */
0264b7b7
AS
58 cfg.w[1] = skein_swap64(hash_bit_len);
59 cfg.w[2] = skein_swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
60eb8175
JC
60 /* zero pad config block */
61 memset(&cfg.w[3], 0, sizeof(cfg) - 3*sizeof(cfg.w[0]));
39bd42b0
JC
62
63 /* compute the initial chaining values from config block */
60eb8175 64 /* zero the chaining variables */
007dfe5a 65 memset(ctx->x, 0, sizeof(ctx->x));
68ace624 66 skein_256_process_block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);
39bd42b0
JC
67 break;
68 }
007dfe5a 69 /* The chaining vars ctx->x are now initialized for hash_bit_len. */
39bd42b0 70 /* Set up to process the data message portion of the hash (default) */
0264b7b7 71 skein_start_new_type(ctx, MSG); /* T0=0, T1= MSG type */
39bd42b0
JC
72
73 return SKEIN_SUCCESS;
449bb812
JC
74}
75
76/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
77/* init the context for a MAC and/or tree hash operation */
95f1840a
AS
78/* [identical to skein_256_init() when key_bytes == 0 && \
79 * tree_info == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */
80int skein_256_init_ext(struct skein_256_ctx *ctx, size_t hash_bit_len,
81 u64 tree_info, const u8 *key, size_t key_bytes)
449bb812 82{
161a2afd 83 union {
39bd42b0 84 u8 b[SKEIN_256_STATE_BYTES];
95f1840a 85 u64 w[SKEIN_256_STATE_WORDS];
60eb8175 86 } cfg; /* config block */
39bd42b0 87
0264b7b7
AS
88 skein_assert_ret(hash_bit_len > 0, SKEIN_BAD_HASHLEN);
89 skein_assert_ret(key_bytes == 0 || key != NULL, SKEIN_FAIL);
39bd42b0 90
007dfe5a 91 /* compute the initial chaining values ctx->x[], based on key */
95f1840a 92 if (key_bytes == 0) { /* is there a key? */
60eb8175 93 /* no key: use all zeroes as key for config block */
007dfe5a 94 memset(ctx->x, 0, sizeof(ctx->x));
161a2afd 95 } else { /* here to pre-process a key */
007dfe5a 96 skein_assert(sizeof(cfg.b) >= sizeof(ctx->x));
39bd42b0 97 /* do a mini-Init right here */
60eb8175 98 /* set output hash bit count = state size */
007dfe5a 99 ctx->h.hash_bit_len = 8*sizeof(ctx->x);
60eb8175 100 /* set tweaks: T0 = 0; T1 = KEY type */
0264b7b7 101 skein_start_new_type(ctx, KEY);
60eb8175 102 /* zero the initial chaining variables */
007dfe5a 103 memset(ctx->x, 0, sizeof(ctx->x));
60eb8175 104 /* hash the key */
95f1840a 105 skein_256_update(ctx, key, key_bytes);
60eb8175 106 /* put result into cfg.b[] */
68ace624 107 skein_256_final_pad(ctx, cfg.b);
007dfe5a
JE
108 /* copy over into ctx->x[] */
109 memcpy(ctx->x, cfg.b, sizeof(cfg.b));
39bd42b0 110 }
60eb8175
JC
111 /*
112 * build/process the config block, type == CONFIG (could be
113 * precomputed for each key)
114 */
115 /* output hash bit count */
95f1840a 116 ctx->h.hash_bit_len = hash_bit_len;
0264b7b7 117 skein_start_new_type(ctx, CFG_FINAL);
39bd42b0 118
60eb8175
JC
119 /* pre-pad cfg.w[] with zeroes */
120 memset(&cfg.w, 0, sizeof(cfg.w));
0264b7b7 121 cfg.w[0] = skein_swap64(SKEIN_SCHEMA_VER);
60eb8175 122 /* hash result length in bits */
0264b7b7 123 cfg.w[1] = skein_swap64(hash_bit_len);
60eb8175 124 /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
0264b7b7 125 cfg.w[2] = skein_swap64(tree_info);
39bd42b0 126
39bd42b0 127 /* compute the initial chaining values from config block */
68ace624 128 skein_256_process_block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);
39bd42b0 129
007dfe5a 130 /* The chaining vars ctx->x are now initialized */
39bd42b0 131 /* Set up to process the data message portion of the hash (default) */
0264b7b7 132 skein_start_new_type(ctx, MSG);
39bd42b0
JC
133
134 return SKEIN_SUCCESS;
449bb812
JC
135}
136
137/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
138/* process the input bytes */
68ace624 139int skein_256_update(struct skein_256_ctx *ctx, const u8 *msg,
95f1840a 140 size_t msg_byte_cnt)
449bb812 141{
39bd42b0
JC
142 size_t n;
143
60eb8175 144 /* catch uninitialized context */
0264b7b7 145 skein_assert_ret(ctx->h.b_cnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL);
39bd42b0
JC
146
147 /* process full blocks, if any */
95f1840a 148 if (msg_byte_cnt + ctx->h.b_cnt > SKEIN_256_BLOCK_BYTES) {
60eb8175 149 /* finish up any buffered message data */
95f1840a 150 if (ctx->h.b_cnt) {
60eb8175 151 /* # bytes free in buffer b[] */
95f1840a 152 n = SKEIN_256_BLOCK_BYTES - ctx->h.b_cnt;
161a2afd 153 if (n) {
60eb8175 154 /* check on our logic here */
0264b7b7 155 skein_assert(n < msg_byte_cnt);
95f1840a
AS
156 memcpy(&ctx->b[ctx->h.b_cnt], msg, n);
157 msg_byte_cnt -= n;
39bd42b0 158 msg += n;
95f1840a 159 ctx->h.b_cnt += n;
39bd42b0 160 }
0264b7b7 161 skein_assert(ctx->h.b_cnt == SKEIN_256_BLOCK_BYTES);
68ace624 162 skein_256_process_block(ctx, ctx->b, 1,
60eb8175 163 SKEIN_256_BLOCK_BYTES);
95f1840a 164 ctx->h.b_cnt = 0;
39bd42b0 165 }
60eb8175
JC
166 /*
167 * now process any remaining full blocks, directly from input
168 * message data
169 */
95f1840a 170 if (msg_byte_cnt > SKEIN_256_BLOCK_BYTES) {
60eb8175 171 /* number of full blocks to process */
95f1840a 172 n = (msg_byte_cnt-1) / SKEIN_256_BLOCK_BYTES;
68ace624 173 skein_256_process_block(ctx, msg, n,
60eb8175 174 SKEIN_256_BLOCK_BYTES);
95f1840a 175 msg_byte_cnt -= n * SKEIN_256_BLOCK_BYTES;
39bd42b0
JC
176 msg += n * SKEIN_256_BLOCK_BYTES;
177 }
0264b7b7 178 skein_assert(ctx->h.b_cnt == 0);
39bd42b0
JC
179 }
180
181 /* copy any remaining source message data bytes into b[] */
95f1840a 182 if (msg_byte_cnt) {
0264b7b7 183 skein_assert(msg_byte_cnt + ctx->h.b_cnt <=
95f1840a
AS
184 SKEIN_256_BLOCK_BYTES);
185 memcpy(&ctx->b[ctx->h.b_cnt], msg, msg_byte_cnt);
186 ctx->h.b_cnt += msg_byte_cnt;
39bd42b0
JC
187 }
188
189 return SKEIN_SUCCESS;
449bb812
JC
190}
191
192/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
193/* finalize the hash computation and output the result */
95f1840a 194int skein_256_final(struct skein_256_ctx *ctx, u8 *hash_val)
449bb812 195{
95f1840a 196 size_t i, n, byte_cnt;
007dfe5a 197 u64 x[SKEIN_256_STATE_WORDS];
60eb8175 198 /* catch uninitialized context */
0264b7b7 199 skein_assert_ret(ctx->h.b_cnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL);
39bd42b0 200
60eb8175 201 /* tag as the final block */
007dfe5a 202 ctx->h.tweak[1] |= SKEIN_T1_FLAG_FINAL;
60eb8175 203 /* zero pad b[] if necessary */
95f1840a
AS
204 if (ctx->h.b_cnt < SKEIN_256_BLOCK_BYTES)
205 memset(&ctx->b[ctx->h.b_cnt], 0,
206 SKEIN_256_BLOCK_BYTES - ctx->h.b_cnt);
39bd42b0 207
60eb8175 208 /* process the final block */
95f1840a 209 skein_256_process_block(ctx, ctx->b, 1, ctx->h.b_cnt);
39bd42b0
JC
210
211 /* now output the result */
60eb8175 212 /* total number of output bytes */
95f1840a 213 byte_cnt = (ctx->h.hash_bit_len + 7) >> 3;
39bd42b0
JC
214
215 /* run Threefish in "counter mode" to generate output */
60eb8175
JC
216 /* zero out b[], so it can hold the counter */
217 memset(ctx->b, 0, sizeof(ctx->b));
218 /* keep a local copy of counter mode "key" */
007dfe5a 219 memcpy(x, ctx->x, sizeof(x));
95f1840a 220 for (i = 0; i*SKEIN_256_BLOCK_BYTES < byte_cnt; i++) {
60eb8175 221 /* build the counter block */
0264b7b7
AS
222 ((u64 *)ctx->b)[0] = skein_swap64((u64) i);
223 skein_start_new_type(ctx, OUT_FINAL);
60eb8175 224 /* run "counter mode" */
68ace624 225 skein_256_process_block(ctx, ctx->b, 1, sizeof(u64));
60eb8175 226 /* number of output bytes left to go */
95f1840a 227 n = byte_cnt - i*SKEIN_256_BLOCK_BYTES;
39bd42b0
JC
228 if (n >= SKEIN_256_BLOCK_BYTES)
229 n = SKEIN_256_BLOCK_BYTES;
60eb8175 230 /* "output" the ctr mode bytes */
007dfe5a 231 skein_put64_lsb_first(hash_val+i*SKEIN_256_BLOCK_BYTES, ctx->x,
60eb8175 232 n);
60eb8175 233 /* restore the counter mode key for next time */
007dfe5a 234 memcpy(ctx->x, x, sizeof(x));
39bd42b0
JC
235 }
236 return SKEIN_SUCCESS;
449bb812
JC
237}
238
239/*****************************************************************/
240/* 512-bit Skein */
241/*****************************************************************/
242
243/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
244/* init the context for a straight hashing operation */
95f1840a 245int skein_512_init(struct skein_512_ctx *ctx, size_t hash_bit_len)
449bb812 246{
161a2afd 247 union {
95f1840a
AS
248 u8 b[SKEIN_512_STATE_BYTES];
249 u64 w[SKEIN_512_STATE_WORDS];
39bd42b0
JC
250 } cfg; /* config block */
251
0264b7b7 252 skein_assert_ret(hash_bit_len > 0, SKEIN_BAD_HASHLEN);
95f1840a 253 ctx->h.hash_bit_len = hash_bit_len; /* output hash bit count */
39bd42b0 254
95f1840a 255 switch (hash_bit_len) { /* use pre-computed values, where available */
39bd42b0 256 case 512:
007dfe5a 257 memcpy(ctx->x, SKEIN_512_IV_512, sizeof(ctx->x));
39bd42b0
JC
258 break;
259 case 384:
007dfe5a 260 memcpy(ctx->x, SKEIN_512_IV_384, sizeof(ctx->x));
39bd42b0
JC
261 break;
262 case 256:
007dfe5a 263 memcpy(ctx->x, SKEIN_512_IV_256, sizeof(ctx->x));
39bd42b0
JC
264 break;
265 case 224:
007dfe5a 266 memcpy(ctx->x, SKEIN_512_IV_224, sizeof(ctx->x));
39bd42b0
JC
267 break;
268 default:
269 /* here if there is no precomputed IV value available */
60eb8175
JC
270 /*
271 * build/process the config block, type == CONFIG (could be
272 * precomputed)
273 */
274 /* set tweaks: T0=0; T1=CFG | FINAL */
0264b7b7 275 skein_start_new_type(ctx, CFG_FINAL);
60eb8175
JC
276
277 /* set the schema, version */
0264b7b7 278 cfg.w[0] = skein_swap64(SKEIN_SCHEMA_VER);
60eb8175 279 /* hash result length in bits */
0264b7b7
AS
280 cfg.w[1] = skein_swap64(hash_bit_len);
281 cfg.w[2] = skein_swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
60eb8175
JC
282 /* zero pad config block */
283 memset(&cfg.w[3], 0, sizeof(cfg) - 3*sizeof(cfg.w[0]));
39bd42b0
JC
284
285 /* compute the initial chaining values from config block */
60eb8175 286 /* zero the chaining variables */
007dfe5a 287 memset(ctx->x, 0, sizeof(ctx->x));
68ace624 288 skein_512_process_block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);
39bd42b0
JC
289 break;
290 }
291
60eb8175 292 /*
007dfe5a 293 * The chaining vars ctx->x are now initialized for the given
95f1840a 294 * hash_bit_len.
60eb8175 295 */
39bd42b0 296 /* Set up to process the data message portion of the hash (default) */
0264b7b7 297 skein_start_new_type(ctx, MSG); /* T0=0, T1= MSG type */
39bd42b0
JC
298
299 return SKEIN_SUCCESS;
449bb812
JC
300}
301
302/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
303/* init the context for a MAC and/or tree hash operation */
95f1840a
AS
304/* [identical to skein_512_init() when key_bytes == 0 && \
305 * tree_info == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */
306int skein_512_init_ext(struct skein_512_ctx *ctx, size_t hash_bit_len,
307 u64 tree_info, const u8 *key, size_t key_bytes)
449bb812 308{
161a2afd 309 union {
95f1840a
AS
310 u8 b[SKEIN_512_STATE_BYTES];
311 u64 w[SKEIN_512_STATE_WORDS];
39bd42b0
JC
312 } cfg; /* config block */
313
0264b7b7
AS
314 skein_assert_ret(hash_bit_len > 0, SKEIN_BAD_HASHLEN);
315 skein_assert_ret(key_bytes == 0 || key != NULL, SKEIN_FAIL);
39bd42b0 316
007dfe5a 317 /* compute the initial chaining values ctx->x[], based on key */
95f1840a 318 if (key_bytes == 0) { /* is there a key? */
60eb8175 319 /* no key: use all zeroes as key for config block */
007dfe5a 320 memset(ctx->x, 0, sizeof(ctx->x));
161a2afd 321 } else { /* here to pre-process a key */
007dfe5a 322 skein_assert(sizeof(cfg.b) >= sizeof(ctx->x));
39bd42b0 323 /* do a mini-Init right here */
60eb8175 324 /* set output hash bit count = state size */
007dfe5a 325 ctx->h.hash_bit_len = 8*sizeof(ctx->x);
60eb8175 326 /* set tweaks: T0 = 0; T1 = KEY type */
0264b7b7 327 skein_start_new_type(ctx, KEY);
60eb8175 328 /* zero the initial chaining variables */
007dfe5a 329 memset(ctx->x, 0, sizeof(ctx->x));
60eb8175 330 /* hash the key */
95f1840a 331 skein_512_update(ctx, key, key_bytes);
60eb8175 332 /* put result into cfg.b[] */
68ace624 333 skein_512_final_pad(ctx, cfg.b);
007dfe5a
JE
334 /* copy over into ctx->x[] */
335 memcpy(ctx->x, cfg.b, sizeof(cfg.b));
39bd42b0 336 }
60eb8175
JC
337 /*
338 * build/process the config block, type == CONFIG (could be
339 * precomputed for each key)
340 */
95f1840a 341 ctx->h.hash_bit_len = hash_bit_len; /* output hash bit count */
0264b7b7 342 skein_start_new_type(ctx, CFG_FINAL);
39bd42b0 343
60eb8175
JC
344 /* pre-pad cfg.w[] with zeroes */
345 memset(&cfg.w, 0, sizeof(cfg.w));
0264b7b7 346 cfg.w[0] = skein_swap64(SKEIN_SCHEMA_VER);
60eb8175 347 /* hash result length in bits */
0264b7b7 348 cfg.w[1] = skein_swap64(hash_bit_len);
60eb8175 349 /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
0264b7b7 350 cfg.w[2] = skein_swap64(tree_info);
39bd42b0 351
39bd42b0 352 /* compute the initial chaining values from config block */
68ace624 353 skein_512_process_block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);
39bd42b0 354
007dfe5a 355 /* The chaining vars ctx->x are now initialized */
39bd42b0 356 /* Set up to process the data message portion of the hash (default) */
0264b7b7 357 skein_start_new_type(ctx, MSG);
39bd42b0
JC
358
359 return SKEIN_SUCCESS;
449bb812
JC
360}
361
362/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
363/* process the input bytes */
68ace624 364int skein_512_update(struct skein_512_ctx *ctx, const u8 *msg,
95f1840a 365 size_t msg_byte_cnt)
449bb812 366{
39bd42b0
JC
367 size_t n;
368
60eb8175 369 /* catch uninitialized context */
0264b7b7 370 skein_assert_ret(ctx->h.b_cnt <= SKEIN_512_BLOCK_BYTES, SKEIN_FAIL);
39bd42b0
JC
371
372 /* process full blocks, if any */
95f1840a 373 if (msg_byte_cnt + ctx->h.b_cnt > SKEIN_512_BLOCK_BYTES) {
60eb8175 374 /* finish up any buffered message data */
95f1840a 375 if (ctx->h.b_cnt) {
60eb8175 376 /* # bytes free in buffer b[] */
95f1840a 377 n = SKEIN_512_BLOCK_BYTES - ctx->h.b_cnt;
161a2afd 378 if (n) {
60eb8175 379 /* check on our logic here */
0264b7b7 380 skein_assert(n < msg_byte_cnt);
95f1840a
AS
381 memcpy(&ctx->b[ctx->h.b_cnt], msg, n);
382 msg_byte_cnt -= n;
39bd42b0 383 msg += n;
95f1840a 384 ctx->h.b_cnt += n;
39bd42b0 385 }
0264b7b7 386 skein_assert(ctx->h.b_cnt == SKEIN_512_BLOCK_BYTES);
68ace624 387 skein_512_process_block(ctx, ctx->b, 1,
60eb8175 388 SKEIN_512_BLOCK_BYTES);
95f1840a 389 ctx->h.b_cnt = 0;
39bd42b0 390 }
60eb8175
JC
391 /*
392 * now process any remaining full blocks, directly from input
393 * message data
394 */
95f1840a 395 if (msg_byte_cnt > SKEIN_512_BLOCK_BYTES) {
60eb8175 396 /* number of full blocks to process */
95f1840a 397 n = (msg_byte_cnt-1) / SKEIN_512_BLOCK_BYTES;
68ace624 398 skein_512_process_block(ctx, msg, n,
60eb8175 399 SKEIN_512_BLOCK_BYTES);
95f1840a 400 msg_byte_cnt -= n * SKEIN_512_BLOCK_BYTES;
39bd42b0
JC
401 msg += n * SKEIN_512_BLOCK_BYTES;
402 }
0264b7b7 403 skein_assert(ctx->h.b_cnt == 0);
39bd42b0
JC
404 }
405
406 /* copy any remaining source message data bytes into b[] */
95f1840a 407 if (msg_byte_cnt) {
0264b7b7 408 skein_assert(msg_byte_cnt + ctx->h.b_cnt <=
95f1840a
AS
409 SKEIN_512_BLOCK_BYTES);
410 memcpy(&ctx->b[ctx->h.b_cnt], msg, msg_byte_cnt);
411 ctx->h.b_cnt += msg_byte_cnt;
39bd42b0
JC
412 }
413
414 return SKEIN_SUCCESS;
449bb812
JC
415}
416
417/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
418/* finalize the hash computation and output the result */
95f1840a 419int skein_512_final(struct skein_512_ctx *ctx, u8 *hash_val)
449bb812 420{
95f1840a 421 size_t i, n, byte_cnt;
007dfe5a 422 u64 x[SKEIN_512_STATE_WORDS];
60eb8175 423 /* catch uninitialized context */
0264b7b7 424 skein_assert_ret(ctx->h.b_cnt <= SKEIN_512_BLOCK_BYTES, SKEIN_FAIL);
39bd42b0 425
60eb8175 426 /* tag as the final block */
007dfe5a 427 ctx->h.tweak[1] |= SKEIN_T1_FLAG_FINAL;
60eb8175 428 /* zero pad b[] if necessary */
95f1840a
AS
429 if (ctx->h.b_cnt < SKEIN_512_BLOCK_BYTES)
430 memset(&ctx->b[ctx->h.b_cnt], 0,
431 SKEIN_512_BLOCK_BYTES - ctx->h.b_cnt);
39bd42b0 432
60eb8175 433 /* process the final block */
95f1840a 434 skein_512_process_block(ctx, ctx->b, 1, ctx->h.b_cnt);
39bd42b0
JC
435
436 /* now output the result */
60eb8175 437 /* total number of output bytes */
95f1840a 438 byte_cnt = (ctx->h.hash_bit_len + 7) >> 3;
39bd42b0
JC
439
440 /* run Threefish in "counter mode" to generate output */
60eb8175
JC
441 /* zero out b[], so it can hold the counter */
442 memset(ctx->b, 0, sizeof(ctx->b));
443 /* keep a local copy of counter mode "key" */
007dfe5a 444 memcpy(x, ctx->x, sizeof(x));
95f1840a 445 for (i = 0; i*SKEIN_512_BLOCK_BYTES < byte_cnt; i++) {
60eb8175 446 /* build the counter block */
0264b7b7
AS
447 ((u64 *)ctx->b)[0] = skein_swap64((u64) i);
448 skein_start_new_type(ctx, OUT_FINAL);
60eb8175 449 /* run "counter mode" */
68ace624 450 skein_512_process_block(ctx, ctx->b, 1, sizeof(u64));
60eb8175 451 /* number of output bytes left to go */
95f1840a 452 n = byte_cnt - i*SKEIN_512_BLOCK_BYTES;
39bd42b0
JC
453 if (n >= SKEIN_512_BLOCK_BYTES)
454 n = SKEIN_512_BLOCK_BYTES;
60eb8175 455 /* "output" the ctr mode bytes */
007dfe5a 456 skein_put64_lsb_first(hash_val+i*SKEIN_512_BLOCK_BYTES, ctx->x,
60eb8175 457 n);
60eb8175 458 /* restore the counter mode key for next time */
007dfe5a 459 memcpy(ctx->x, x, sizeof(x));
39bd42b0
JC
460 }
461 return SKEIN_SUCCESS;
449bb812
JC
462}
463
464/*****************************************************************/
465/* 1024-bit Skein */
466/*****************************************************************/
467
468/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
469/* init the context for a straight hashing operation */
3201b7f2 470int skein_1024_init(struct skein_1024_ctx *ctx, size_t hash_bit_len)
449bb812 471{
161a2afd 472 union {
0264b7b7
AS
473 u8 b[SKEIN_1024_STATE_BYTES];
474 u64 w[SKEIN_1024_STATE_WORDS];
39bd42b0
JC
475 } cfg; /* config block */
476
0264b7b7 477 skein_assert_ret(hash_bit_len > 0, SKEIN_BAD_HASHLEN);
95f1840a 478 ctx->h.hash_bit_len = hash_bit_len; /* output hash bit count */
39bd42b0 479
95f1840a 480 switch (hash_bit_len) { /* use pre-computed values, where available */
39bd42b0 481 case 512:
007dfe5a 482 memcpy(ctx->x, SKEIN_1024_IV_512, sizeof(ctx->x));
39bd42b0
JC
483 break;
484 case 384:
007dfe5a 485 memcpy(ctx->x, SKEIN_1024_IV_384, sizeof(ctx->x));
39bd42b0
JC
486 break;
487 case 1024:
007dfe5a 488 memcpy(ctx->x, SKEIN_1024_IV_1024, sizeof(ctx->x));
39bd42b0
JC
489 break;
490 default:
491 /* here if there is no precomputed IV value available */
60eb8175
JC
492 /*
493 * build/process the config block, type == CONFIG
494 * (could be precomputed)
495 */
496 /* set tweaks: T0=0; T1=CFG | FINAL */
0264b7b7 497 skein_start_new_type(ctx, CFG_FINAL);
60eb8175
JC
498
499 /* set the schema, version */
0264b7b7 500 cfg.w[0] = skein_swap64(SKEIN_SCHEMA_VER);
60eb8175 501 /* hash result length in bits */
0264b7b7
AS
502 cfg.w[1] = skein_swap64(hash_bit_len);
503 cfg.w[2] = skein_swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
60eb8175
JC
504 /* zero pad config block */
505 memset(&cfg.w[3], 0, sizeof(cfg) - 3*sizeof(cfg.w[0]));
39bd42b0
JC
506
507 /* compute the initial chaining values from config block */
60eb8175 508 /* zero the chaining variables */
007dfe5a 509 memset(ctx->x, 0, sizeof(ctx->x));
68ace624 510 skein_1024_process_block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);
39bd42b0
JC
511 break;
512 }
513
007dfe5a 514 /* The chaining vars ctx->x are now initialized for the hash_bit_len. */
39bd42b0 515 /* Set up to process the data message portion of the hash (default) */
0264b7b7 516 skein_start_new_type(ctx, MSG); /* T0=0, T1= MSG type */
39bd42b0
JC
517
518 return SKEIN_SUCCESS;
449bb812
JC
519}
520
521/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
522/* init the context for a MAC and/or tree hash operation */
95f1840a
AS
523/* [identical to skein_1024_init() when key_bytes == 0 && \
524 * tree_info == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */
3201b7f2 525int skein_1024_init_ext(struct skein_1024_ctx *ctx, size_t hash_bit_len,
95f1840a 526 u64 tree_info, const u8 *key, size_t key_bytes)
449bb812 527{
161a2afd 528 union {
0264b7b7
AS
529 u8 b[SKEIN_1024_STATE_BYTES];
530 u64 w[SKEIN_1024_STATE_WORDS];
39bd42b0
JC
531 } cfg; /* config block */
532
0264b7b7
AS
533 skein_assert_ret(hash_bit_len > 0, SKEIN_BAD_HASHLEN);
534 skein_assert_ret(key_bytes == 0 || key != NULL, SKEIN_FAIL);
39bd42b0 535
007dfe5a 536 /* compute the initial chaining values ctx->x[], based on key */
95f1840a 537 if (key_bytes == 0) { /* is there a key? */
60eb8175 538 /* no key: use all zeroes as key for config block */
007dfe5a 539 memset(ctx->x, 0, sizeof(ctx->x));
161a2afd 540 } else { /* here to pre-process a key */
007dfe5a 541 skein_assert(sizeof(cfg.b) >= sizeof(ctx->x));
39bd42b0 542 /* do a mini-Init right here */
60eb8175 543 /* set output hash bit count = state size */
007dfe5a 544 ctx->h.hash_bit_len = 8*sizeof(ctx->x);
60eb8175 545 /* set tweaks: T0 = 0; T1 = KEY type */
0264b7b7 546 skein_start_new_type(ctx, KEY);
60eb8175 547 /* zero the initial chaining variables */
007dfe5a 548 memset(ctx->x, 0, sizeof(ctx->x));
60eb8175 549 /* hash the key */
95f1840a 550 skein_1024_update(ctx, key, key_bytes);
60eb8175 551 /* put result into cfg.b[] */
68ace624 552 skein_1024_final_pad(ctx, cfg.b);
007dfe5a
JE
553 /* copy over into ctx->x[] */
554 memcpy(ctx->x, cfg.b, sizeof(cfg.b));
39bd42b0 555 }
60eb8175
JC
556 /*
557 * build/process the config block, type == CONFIG (could be
558 * precomputed for each key)
559 */
560 /* output hash bit count */
95f1840a 561 ctx->h.hash_bit_len = hash_bit_len;
0264b7b7 562 skein_start_new_type(ctx, CFG_FINAL);
39bd42b0 563
60eb8175
JC
564 /* pre-pad cfg.w[] with zeroes */
565 memset(&cfg.w, 0, sizeof(cfg.w));
0264b7b7 566 cfg.w[0] = skein_swap64(SKEIN_SCHEMA_VER);
60eb8175 567 /* hash result length in bits */
0264b7b7 568 cfg.w[1] = skein_swap64(hash_bit_len);
60eb8175 569 /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
0264b7b7 570 cfg.w[2] = skein_swap64(tree_info);
39bd42b0 571
39bd42b0 572 /* compute the initial chaining values from config block */
68ace624 573 skein_1024_process_block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);
39bd42b0 574
007dfe5a 575 /* The chaining vars ctx->x are now initialized */
39bd42b0 576 /* Set up to process the data message portion of the hash (default) */
0264b7b7 577 skein_start_new_type(ctx, MSG);
39bd42b0
JC
578
579 return SKEIN_SUCCESS;
449bb812
JC
580}
581
582/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
583/* process the input bytes */
3201b7f2 584int skein_1024_update(struct skein_1024_ctx *ctx, const u8 *msg,
95f1840a 585 size_t msg_byte_cnt)
449bb812 586{
39bd42b0
JC
587 size_t n;
588
60eb8175 589 /* catch uninitialized context */
0264b7b7 590 skein_assert_ret(ctx->h.b_cnt <= SKEIN_1024_BLOCK_BYTES, SKEIN_FAIL);
39bd42b0
JC
591
592 /* process full blocks, if any */
0264b7b7 593 if (msg_byte_cnt + ctx->h.b_cnt > SKEIN_1024_BLOCK_BYTES) {
60eb8175 594 /* finish up any buffered message data */
95f1840a 595 if (ctx->h.b_cnt) {
60eb8175 596 /* # bytes free in buffer b[] */
0264b7b7 597 n = SKEIN_1024_BLOCK_BYTES - ctx->h.b_cnt;
161a2afd 598 if (n) {
60eb8175 599 /* check on our logic here */
0264b7b7 600 skein_assert(n < msg_byte_cnt);
95f1840a
AS
601 memcpy(&ctx->b[ctx->h.b_cnt], msg, n);
602 msg_byte_cnt -= n;
39bd42b0 603 msg += n;
95f1840a 604 ctx->h.b_cnt += n;
39bd42b0 605 }
0264b7b7 606 skein_assert(ctx->h.b_cnt == SKEIN_1024_BLOCK_BYTES);
68ace624 607 skein_1024_process_block(ctx, ctx->b, 1,
0264b7b7 608 SKEIN_1024_BLOCK_BYTES);
95f1840a 609 ctx->h.b_cnt = 0;
39bd42b0 610 }
60eb8175
JC
611 /*
612 * now process any remaining full blocks, directly from input
613 * message data
614 */
0264b7b7 615 if (msg_byte_cnt > SKEIN_1024_BLOCK_BYTES) {
60eb8175 616 /* number of full blocks to process */
0264b7b7 617 n = (msg_byte_cnt-1) / SKEIN_1024_BLOCK_BYTES;
68ace624 618 skein_1024_process_block(ctx, msg, n,
0264b7b7
AS
619 SKEIN_1024_BLOCK_BYTES);
620 msg_byte_cnt -= n * SKEIN_1024_BLOCK_BYTES;
621 msg += n * SKEIN_1024_BLOCK_BYTES;
39bd42b0 622 }
0264b7b7 623 skein_assert(ctx->h.b_cnt == 0);
39bd42b0
JC
624 }
625
626 /* copy any remaining source message data bytes into b[] */
95f1840a 627 if (msg_byte_cnt) {
0264b7b7
AS
628 skein_assert(msg_byte_cnt + ctx->h.b_cnt <=
629 SKEIN_1024_BLOCK_BYTES);
95f1840a
AS
630 memcpy(&ctx->b[ctx->h.b_cnt], msg, msg_byte_cnt);
631 ctx->h.b_cnt += msg_byte_cnt;
39bd42b0
JC
632 }
633
634 return SKEIN_SUCCESS;
449bb812
JC
635}
636
637/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
638/* finalize the hash computation and output the result */
3201b7f2 639int skein_1024_final(struct skein_1024_ctx *ctx, u8 *hash_val)
449bb812 640{
95f1840a 641 size_t i, n, byte_cnt;
007dfe5a 642 u64 x[SKEIN_1024_STATE_WORDS];
60eb8175 643 /* catch uninitialized context */
0264b7b7 644 skein_assert_ret(ctx->h.b_cnt <= SKEIN_1024_BLOCK_BYTES, SKEIN_FAIL);
39bd42b0 645
60eb8175 646 /* tag as the final block */
007dfe5a 647 ctx->h.tweak[1] |= SKEIN_T1_FLAG_FINAL;
60eb8175 648 /* zero pad b[] if necessary */
0264b7b7 649 if (ctx->h.b_cnt < SKEIN_1024_BLOCK_BYTES)
95f1840a 650 memset(&ctx->b[ctx->h.b_cnt], 0,
0264b7b7 651 SKEIN_1024_BLOCK_BYTES - ctx->h.b_cnt);
39bd42b0 652
60eb8175 653 /* process the final block */
95f1840a 654 skein_1024_process_block(ctx, ctx->b, 1, ctx->h.b_cnt);
39bd42b0
JC
655
656 /* now output the result */
60eb8175 657 /* total number of output bytes */
95f1840a 658 byte_cnt = (ctx->h.hash_bit_len + 7) >> 3;
39bd42b0
JC
659
660 /* run Threefish in "counter mode" to generate output */
60eb8175
JC
661 /* zero out b[], so it can hold the counter */
662 memset(ctx->b, 0, sizeof(ctx->b));
663 /* keep a local copy of counter mode "key" */
007dfe5a 664 memcpy(x, ctx->x, sizeof(x));
0264b7b7 665 for (i = 0; i*SKEIN_1024_BLOCK_BYTES < byte_cnt; i++) {
60eb8175 666 /* build the counter block */
0264b7b7
AS
667 ((u64 *)ctx->b)[0] = skein_swap64((u64) i);
668 skein_start_new_type(ctx, OUT_FINAL);
60eb8175 669 /* run "counter mode" */
68ace624 670 skein_1024_process_block(ctx, ctx->b, 1, sizeof(u64));
60eb8175 671 /* number of output bytes left to go */
0264b7b7
AS
672 n = byte_cnt - i*SKEIN_1024_BLOCK_BYTES;
673 if (n >= SKEIN_1024_BLOCK_BYTES)
674 n = SKEIN_1024_BLOCK_BYTES;
60eb8175 675 /* "output" the ctr mode bytes */
007dfe5a 676 skein_put64_lsb_first(hash_val+i*SKEIN_1024_BLOCK_BYTES, ctx->x,
60eb8175 677 n);
60eb8175 678 /* restore the counter mode key for next time */
007dfe5a 679 memcpy(ctx->x, x, sizeof(x));
39bd42b0
JC
680 }
681 return SKEIN_SUCCESS;
449bb812
JC
682}
683
684/**************** Functions to support MAC/tree hashing ***************/
685/* (this code is identical for Optimized and Reference versions) */
686
687/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
688/* finalize the hash computation and output the block, no OUTPUT stage */
95f1840a 689int skein_256_final_pad(struct skein_256_ctx *ctx, u8 *hash_val)
449bb812 690{
60eb8175 691 /* catch uninitialized context */
0264b7b7 692 skein_assert_ret(ctx->h.b_cnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL);
449bb812 693
60eb8175 694 /* tag as the final block */
007dfe5a 695 ctx->h.tweak[1] |= SKEIN_T1_FLAG_FINAL;
60eb8175 696 /* zero pad b[] if necessary */
95f1840a
AS
697 if (ctx->h.b_cnt < SKEIN_256_BLOCK_BYTES)
698 memset(&ctx->b[ctx->h.b_cnt], 0,
699 SKEIN_256_BLOCK_BYTES - ctx->h.b_cnt);
60eb8175 700 /* process the final block */
95f1840a 701 skein_256_process_block(ctx, ctx->b, 1, ctx->h.b_cnt);
449bb812 702
60eb8175 703 /* "output" the state bytes */
007dfe5a 704 skein_put64_lsb_first(hash_val, ctx->x, SKEIN_256_BLOCK_BYTES);
449bb812 705
39bd42b0 706 return SKEIN_SUCCESS;
449bb812
JC
707}
708
709/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
710/* finalize the hash computation and output the block, no OUTPUT stage */
95f1840a 711int skein_512_final_pad(struct skein_512_ctx *ctx, u8 *hash_val)
449bb812 712{
60eb8175 713 /* catch uninitialized context */
0264b7b7 714 skein_assert_ret(ctx->h.b_cnt <= SKEIN_512_BLOCK_BYTES, SKEIN_FAIL);
449bb812 715
60eb8175 716 /* tag as the final block */
007dfe5a 717 ctx->h.tweak[1] |= SKEIN_T1_FLAG_FINAL;
60eb8175 718 /* zero pad b[] if necessary */
95f1840a
AS
719 if (ctx->h.b_cnt < SKEIN_512_BLOCK_BYTES)
720 memset(&ctx->b[ctx->h.b_cnt], 0,
721 SKEIN_512_BLOCK_BYTES - ctx->h.b_cnt);
60eb8175 722 /* process the final block */
95f1840a 723 skein_512_process_block(ctx, ctx->b, 1, ctx->h.b_cnt);
449bb812 724
60eb8175 725 /* "output" the state bytes */
007dfe5a 726 skein_put64_lsb_first(hash_val, ctx->x, SKEIN_512_BLOCK_BYTES);
449bb812 727
39bd42b0 728 return SKEIN_SUCCESS;
449bb812
JC
729}
730
731/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
732/* finalize the hash computation and output the block, no OUTPUT stage */
3201b7f2 733int skein_1024_final_pad(struct skein_1024_ctx *ctx, u8 *hash_val)
449bb812 734{
60eb8175 735 /* catch uninitialized context */
0264b7b7 736 skein_assert_ret(ctx->h.b_cnt <= SKEIN_1024_BLOCK_BYTES, SKEIN_FAIL);
449bb812 737
60eb8175 738 /* tag as the final block */
007dfe5a 739 ctx->h.tweak[1] |= SKEIN_T1_FLAG_FINAL;
60eb8175 740 /* zero pad b[] if necessary */
0264b7b7 741 if (ctx->h.b_cnt < SKEIN_1024_BLOCK_BYTES)
95f1840a 742 memset(&ctx->b[ctx->h.b_cnt], 0,
0264b7b7 743 SKEIN_1024_BLOCK_BYTES - ctx->h.b_cnt);
60eb8175 744 /* process the final block */
95f1840a 745 skein_1024_process_block(ctx, ctx->b, 1, ctx->h.b_cnt);
449bb812 746
60eb8175 747 /* "output" the state bytes */
007dfe5a 748 skein_put64_lsb_first(hash_val, ctx->x, SKEIN_1024_BLOCK_BYTES);
449bb812 749
39bd42b0 750 return SKEIN_SUCCESS;
449bb812
JC
751}
752
753#if SKEIN_TREE_HASH
754/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
755/* just do the OUTPUT stage */
95f1840a 756int skein_256_output(struct skein_256_ctx *ctx, u8 *hash_val)
449bb812 757{
95f1840a 758 size_t i, n, byte_cnt;
007dfe5a 759 u64 x[SKEIN_256_STATE_WORDS];
60eb8175 760 /* catch uninitialized context */
0264b7b7 761 skein_assert_ret(ctx->h.b_cnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL);
39bd42b0
JC
762
763 /* now output the result */
60eb8175 764 /* total number of output bytes */
95f1840a 765 byte_cnt = (ctx->h.hash_bit_len + 7) >> 3;
39bd42b0
JC
766
767 /* run Threefish in "counter mode" to generate output */
60eb8175
JC
768 /* zero out b[], so it can hold the counter */
769 memset(ctx->b, 0, sizeof(ctx->b));
770 /* keep a local copy of counter mode "key" */
007dfe5a 771 memcpy(x, ctx->x, sizeof(x));
95f1840a 772 for (i = 0; i*SKEIN_256_BLOCK_BYTES < byte_cnt; i++) {
60eb8175 773 /* build the counter block */
0264b7b7
AS
774 ((u64 *)ctx->b)[0] = skein_swap64((u64) i);
775 skein_start_new_type(ctx, OUT_FINAL);
60eb8175 776 /* run "counter mode" */
68ace624 777 skein_256_process_block(ctx, ctx->b, 1, sizeof(u64));
60eb8175 778 /* number of output bytes left to go */
95f1840a 779 n = byte_cnt - i*SKEIN_256_BLOCK_BYTES;
39bd42b0
JC
780 if (n >= SKEIN_256_BLOCK_BYTES)
781 n = SKEIN_256_BLOCK_BYTES;
60eb8175 782 /* "output" the ctr mode bytes */
007dfe5a 783 skein_put64_lsb_first(hash_val+i*SKEIN_256_BLOCK_BYTES, ctx->x,
60eb8175 784 n);
60eb8175 785 /* restore the counter mode key for next time */
007dfe5a 786 memcpy(ctx->x, x, sizeof(x));
39bd42b0
JC
787 }
788 return SKEIN_SUCCESS;
449bb812
JC
789}
790
791/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
792/* just do the OUTPUT stage */
95f1840a 793int skein_512_output(struct skein_512_ctx *ctx, u8 *hash_val)
449bb812 794{
95f1840a 795 size_t i, n, byte_cnt;
007dfe5a 796 u64 x[SKEIN_512_STATE_WORDS];
60eb8175 797 /* catch uninitialized context */
0264b7b7 798 skein_assert_ret(ctx->h.b_cnt <= SKEIN_512_BLOCK_BYTES, SKEIN_FAIL);
39bd42b0
JC
799
800 /* now output the result */
60eb8175 801 /* total number of output bytes */
95f1840a 802 byte_cnt = (ctx->h.hash_bit_len + 7) >> 3;
39bd42b0
JC
803
804 /* run Threefish in "counter mode" to generate output */
60eb8175
JC
805 /* zero out b[], so it can hold the counter */
806 memset(ctx->b, 0, sizeof(ctx->b));
807 /* keep a local copy of counter mode "key" */
007dfe5a 808 memcpy(x, ctx->x, sizeof(x));
95f1840a 809 for (i = 0; i*SKEIN_512_BLOCK_BYTES < byte_cnt; i++) {
60eb8175 810 /* build the counter block */
0264b7b7
AS
811 ((u64 *)ctx->b)[0] = skein_swap64((u64) i);
812 skein_start_new_type(ctx, OUT_FINAL);
60eb8175 813 /* run "counter mode" */
68ace624 814 skein_512_process_block(ctx, ctx->b, 1, sizeof(u64));
60eb8175 815 /* number of output bytes left to go */
95f1840a 816 n = byte_cnt - i*SKEIN_512_BLOCK_BYTES;
39bd42b0
JC
817 if (n >= SKEIN_512_BLOCK_BYTES)
818 n = SKEIN_512_BLOCK_BYTES;
60eb8175 819 /* "output" the ctr mode bytes */
007dfe5a 820 skein_put64_lsb_first(hash_val+i*SKEIN_512_BLOCK_BYTES, ctx->x,
60eb8175 821 n);
60eb8175 822 /* restore the counter mode key for next time */
007dfe5a 823 memcpy(ctx->x, x, sizeof(x));
39bd42b0
JC
824 }
825 return SKEIN_SUCCESS;
449bb812
JC
826}
827
828/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
829/* just do the OUTPUT stage */
3201b7f2 830int skein_1024_output(struct skein_1024_ctx *ctx, u8 *hash_val)
449bb812 831{
95f1840a 832 size_t i, n, byte_cnt;
007dfe5a 833 u64 x[SKEIN_1024_STATE_WORDS];
60eb8175 834 /* catch uninitialized context */
0264b7b7 835 skein_assert_ret(ctx->h.b_cnt <= SKEIN_1024_BLOCK_BYTES, SKEIN_FAIL);
39bd42b0
JC
836
837 /* now output the result */
60eb8175 838 /* total number of output bytes */
95f1840a 839 byte_cnt = (ctx->h.hash_bit_len + 7) >> 3;
39bd42b0
JC
840
841 /* run Threefish in "counter mode" to generate output */
60eb8175
JC
842 /* zero out b[], so it can hold the counter */
843 memset(ctx->b, 0, sizeof(ctx->b));
844 /* keep a local copy of counter mode "key" */
007dfe5a 845 memcpy(x, ctx->x, sizeof(x));
0264b7b7 846 for (i = 0; i*SKEIN_1024_BLOCK_BYTES < byte_cnt; i++) {
60eb8175 847 /* build the counter block */
0264b7b7
AS
848 ((u64 *)ctx->b)[0] = skein_swap64((u64) i);
849 skein_start_new_type(ctx, OUT_FINAL);
60eb8175 850 /* run "counter mode" */
68ace624 851 skein_1024_process_block(ctx, ctx->b, 1, sizeof(u64));
60eb8175 852 /* number of output bytes left to go */
0264b7b7
AS
853 n = byte_cnt - i*SKEIN_1024_BLOCK_BYTES;
854 if (n >= SKEIN_1024_BLOCK_BYTES)
855 n = SKEIN_1024_BLOCK_BYTES;
60eb8175 856 /* "output" the ctr mode bytes */
007dfe5a 857 skein_put64_lsb_first(hash_val+i*SKEIN_1024_BLOCK_BYTES, ctx->x,
60eb8175 858 n);
60eb8175 859 /* restore the counter mode key for next time */
007dfe5a 860 memcpy(ctx->x, x, sizeof(x));
39bd42b0
JC
861 }
862 return SKEIN_SUCCESS;
449bb812
JC
863}
864#endif