/*
 * Copyright (c) 2010 Werner Dittmann
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include <linux/string.h>
#include "skein_api.h"

int skein_ctx_prepare(struct skein_ctx *ctx, enum skein_size size)
{
	skein_assert_ret(ctx && size, SKEIN_FAIL);

	memset(ctx, 0, sizeof(struct skein_ctx));
	ctx->skein_size = size;

	return SKEIN_SUCCESS;
}

int skein_init(struct skein_ctx *ctx, size_t hash_bit_len)
{
	int ret = SKEIN_FAIL;
	size_t x_len = 0;
	u64 *x = NULL;
	u64 tree_info = SKEIN_CFG_TREE_INFO_SEQUENTIAL;

	skein_assert_ret(ctx, SKEIN_FAIL);
	/*
	 * The following two lines rely of the fact that the real Skein
	 * contexts are a union in out context and thus have tha maximum
	 * memory available.  The beauty of C :-) .
	 */
	x = ctx->m.s256.x;
	x_len = ctx->skein_size / 8;
	/*
	 * If size is the same and hash bit length is zero then reuse
	 * the save chaining variables.
	 */
	switch (ctx->skein_size) {
	case SKEIN_256:
		ret = skein_256_init_ext(&ctx->m.s256, hash_bit_len,
					 tree_info, NULL, 0);
		break;
	case SKEIN_512:
		ret = skein_512_init_ext(&ctx->m.s512, hash_bit_len,
					 tree_info, NULL, 0);
		break;
	case SKEIN_1024:
		ret = skein_1024_init_ext(&ctx->m.s1024, hash_bit_len,
					  tree_info, NULL, 0);
		break;
	}

	if (ret == SKEIN_SUCCESS) {
		/*
		 * Save chaining variables for this combination of size and
		 * hash_bit_len
		 */
		memcpy(ctx->x_save, x, x_len);
	}
	return ret;
}

int skein_mac_init(struct skein_ctx *ctx, const u8 *key, size_t key_len,
		   size_t hash_bit_len)
{
	int ret = SKEIN_FAIL;
	u64 *x = NULL;
	size_t x_len = 0;
	u64 tree_info = SKEIN_CFG_TREE_INFO_SEQUENTIAL;

	skein_assert_ret(ctx, SKEIN_FAIL);

	x = ctx->m.s256.x;
	x_len = ctx->skein_size / 8;

	skein_assert_ret(hash_bit_len, SKEIN_BAD_HASHLEN);

	switch (ctx->skein_size) {
	case SKEIN_256:
		ret = skein_256_init_ext(&ctx->m.s256, hash_bit_len,
					 tree_info, key, key_len);

		break;
	case SKEIN_512:
		ret = skein_512_init_ext(&ctx->m.s512, hash_bit_len,
					 tree_info, key, key_len);
		break;
	case SKEIN_1024:
		ret = skein_1024_init_ext(&ctx->m.s1024, hash_bit_len,
					  tree_info, key, key_len);

		break;
	}
	if (ret == SKEIN_SUCCESS) {
		/*
		 * Save chaining variables for this combination of key,
		 * key_len, hash_bit_len
		 */
		memcpy(ctx->x_save, x, x_len);
	}
	return ret;
}

void skein_reset(struct skein_ctx *ctx)
{
	size_t x_len = 0;
	u64 *x;

	/*
	 * The following two lines rely of the fact that the real Skein
	 * contexts are a union in out context and thus have tha maximum
	 * memory available.  The beautiy of C :-) .
	 */
	x = ctx->m.s256.x;
	x_len = ctx->skein_size / 8;
	/* Restore the chaing variable, reset byte counter */
	memcpy(x, ctx->x_save, x_len);

	/* Setup context to process the message */
	skein_start_new_type(&ctx->m, MSG);
}

int skein_update(struct skein_ctx *ctx, const u8 *msg,
		 size_t msg_byte_cnt)
{
	int ret = SKEIN_FAIL;

	skein_assert_ret(ctx, SKEIN_FAIL);

	switch (ctx->skein_size) {
	case SKEIN_256:
		ret = skein_256_update(&ctx->m.s256, msg, msg_byte_cnt);
		break;
	case SKEIN_512:
		ret = skein_512_update(&ctx->m.s512, msg, msg_byte_cnt);
		break;
	case SKEIN_1024:
		ret = skein_1024_update(&ctx->m.s1024, msg, msg_byte_cnt);
		break;
	}
	return ret;
}

int skein_update_bits(struct skein_ctx *ctx, const u8 *msg,
		      size_t msg_bit_cnt)
{
	/*
	 * I've used the bit pad implementation from skein_test.c (see NIST CD)
	 * and modified it to use the convenience functions and added some
	 * pointer arithmetic.
	 */
	size_t length;
	u8 mask;
	u8 *up;

	/*
	 * only the final Update() call is allowed do partial bytes, else
	 * assert an error
	 */
	skein_assert_ret((ctx->m.h.T[1] & SKEIN_T1_FLAG_BIT_PAD) == 0 ||
			 msg_bit_cnt == 0, SKEIN_FAIL);

	/* if number of bits is a multiple of bytes - that's easy */
	if ((msg_bit_cnt & 0x7) == 0)
		return skein_update(ctx, msg, msg_bit_cnt >> 3);

	skein_update(ctx, msg, (msg_bit_cnt >> 3) + 1);

	/*
	 * The next line rely on the fact that the real Skein contexts
	 * are a union in our context. After the addition the pointer points to
	 * Skein's real partial block buffer.
	 * If this layout ever changes we have to adapt this as well.
	 */
	up = (u8 *)ctx->m.s256.x + ctx->skein_size / 8;

	/* set tweak flag for the skein_final call */
	skein_set_bit_pad_flag(ctx->m.h);

	/* now "pad" the final partial byte the way NIST likes */
	/* get the b_cnt value (same location for all block sizes) */
	length = ctx->m.h.b_cnt;
	/* internal sanity check: there IS a partial byte in the buffer! */
	skein_assert(length != 0);
	/* partial byte bit mask */
	mask = (u8)(1u << (7 - (msg_bit_cnt & 7)));
	/* apply bit padding on final byte (in the buffer) */
	up[length - 1]  = (up[length - 1] & (0 - mask)) | mask;

	return SKEIN_SUCCESS;
}

int skein_final(struct skein_ctx *ctx, u8 *hash)
{
	int ret = SKEIN_FAIL;

	skein_assert_ret(ctx, SKEIN_FAIL);

	switch (ctx->skein_size) {
	case SKEIN_256:
		ret = skein_256_final(&ctx->m.s256, hash);
		break;
	case SKEIN_512:
		ret = skein_512_final(&ctx->m.s512, hash);
		break;
	case SKEIN_1024:
		ret = skein_1024_final(&ctx->m.s1024, hash);
		break;
	}
	return ret;
}
