#include <libecc/utils/utils.h>
#include <libecc/hash/shake.h>
int _shake_init(shake_context *ctx, u8 digest_size, u8 block_size)
{
int ret;
MUST_HAVE((ctx != NULL), ret, err);
ret = local_memset(ctx->shake_state, 0, sizeof(ctx->shake_state)); EG(ret, err);
ctx->shake_idx = 0;
ctx->shake_digest_size = digest_size;
ctx->shake_block_size = block_size;
ctx->shake_endian = arch_is_big_endian() ? SHAKE_BIG : SHAKE_LITTLE;
err:
return ret;
}
int _shake_update(shake_context *ctx, const u8 *input, u32 ilen)
{
u32 i;
u8 *state;
int ret;
MUST_HAVE((ctx != NULL) && ((input != NULL) || (ilen == 0)), ret, err);
state = (u8*)(ctx->shake_state);
for(i = 0; i < ilen; i++){
u64 idx = (ctx->shake_endian == SHAKE_LITTLE) ? ctx->shake_idx : SWAP64_Idx(ctx->shake_idx);
ctx->shake_idx++;
state[idx] ^= input[i];
if(ctx->shake_idx == ctx->shake_block_size){
KECCAKF(ctx->shake_state);
ctx->shake_idx = 0;
}
}
ret = 0;
err:
return ret;
}
int _shake_finalize(shake_context *ctx, u8 *output)
{
unsigned int i;
u8 *state;
int ret;
MUST_HAVE((ctx != NULL) && (output != NULL), ret, err);
MUST_HAVE((ctx->shake_digest_size <= sizeof(ctx->shake_state)), ret, err);
state = (u8*)(ctx->shake_state);
if(ctx->shake_endian == SHAKE_LITTLE){
state[ctx->shake_idx] ^= 0x1f;
state[ctx->shake_block_size - 1] ^= 0x80;
}
else{
state[SWAP64_Idx(ctx->shake_idx)] ^= 0x1f;
state[SWAP64_Idx(ctx->shake_block_size - 1)] ^= 0x80;
}
KECCAKF(ctx->shake_state);
for(i = 0; i < ctx->shake_digest_size; i++){
output[i] = (ctx->shake_endian == SHAKE_LITTLE) ? state[i] : state[SWAP64_Idx(i)];
}
ctx->magic = WORD(0);
ret = 0;
err:
return ret;
}