#include "bee2/core/blob.h"
#include "bee2/core/err.h"
#include "bee2/core/mem.h"
#include "bee2/core/u32.h"
#include "bee2/core/util.h"
#include "bee2/crypto/belt.h"
#include "belt_lcl.h"
typedef struct {
u32 ls[8];
u32 s1[4];
u32 h[8];
u32 h1[8];
octet block[32];
size_t filled;
octet stack[];
} belt_hash_st;
size_t beltHash_keep()
{
return sizeof(belt_hash_st) + beltCompr_deep();
}
void beltHashStart(void* state)
{
belt_hash_st* st = (belt_hash_st*)state;
ASSERT(memIsValid(state, beltHash_keep()));
beltBlockSetZero(st->ls);
beltBlockSetZero(st->ls + 4);
u32From(st->h, beltH(), 32);
st->filled = 0;
}
void beltHashStepH(const void* buf, size_t count, void* state)
{
belt_hash_st* st = (belt_hash_st*)state;
ASSERT(memIsDisjoint2(buf, count, state, beltHash_keep()));
beltBlockAddBitSizeU32(st->ls, count);
if (st->filled)
{
if (count < 32 - st->filled)
{
memCopy(st->block + st->filled, buf, count);
st->filled += count;
return;
}
memCopy(st->block + st->filled, buf, 32 - st->filled);
count -= 32 - st->filled;
buf = (const octet*)buf + (32 - st->filled);
#if (OCTET_ORDER == BIG_ENDIAN)
beltBlockRevU32(st->block);
beltBlockRevU32(st->block + 16);
#endif
beltCompr2(st->ls + 4, st->h, (u32*)st->block, st->stack);
st->filled = 0;
}
while (count >= 32)
{
beltBlockCopy(st->block, buf);
beltBlockCopy(st->block + 16, (const octet*)buf + 16);
#if (OCTET_ORDER == BIG_ENDIAN)
beltBlockRevU32(st->block);
beltBlockRevU32(st->block + 16);
#endif
beltCompr2(st->ls + 4, st->h, (u32*)st->block, st->stack);
buf = (const octet*)buf + 32;
count -= 32;
}
if (count)
memCopy(st->block, buf, st->filled = count);
}
static void beltHashStepG_internal(void* state)
{
belt_hash_st* st = (belt_hash_st*)state;
ASSERT(memIsValid(state, beltHash_keep()));
beltBlockCopy(st->s1, st->ls + 4);
beltBlockCopy(st->h1, st->h);
beltBlockCopy(st->h1 + 4, st->h + 4);
if (st->filled)
{
memSetZero(st->block + st->filled, 32 - st->filled);
#if (OCTET_ORDER == BIG_ENDIAN)
beltBlockRevU32(st->block);
beltBlockRevU32(st->block + 16);
#endif
beltCompr2(st->ls + 4, st->h1, (u32*)st->block, st->stack);
#if (OCTET_ORDER == BIG_ENDIAN)
beltBlockRevU32(st->block + 16);
beltBlockRevU32(st->block);
#endif
}
beltCompr(st->h1, st->ls, st->stack);
beltBlockCopy(st->ls + 4, st->s1);
}
void beltHashStepG(octet hash[32], void* state)
{
belt_hash_st* st = (belt_hash_st*)state;
ASSERT(memIsValid(hash, 32));
beltHashStepG_internal(state);
u32To(hash, 32, st->h1);
}
void beltHashStepG2(octet hash[], size_t hash_len, void* state)
{
belt_hash_st* st = (belt_hash_st*)state;
ASSERT(hash_len <= 32);
ASSERT(memIsValid(hash, hash_len));
beltHashStepG_internal(state);
u32To(hash, hash_len, st->h1);
}
bool_t beltHashStepV(const octet hash[32], void* state)
{
belt_hash_st* st = (belt_hash_st*)state;
ASSERT(memIsValid(hash, 32));
beltHashStepG_internal(state);
#if (OCTET_ORDER == BIG_ENDIAN)
beltBlockRevU32(st->h1);
beltBlockRevU32(st->h1 + 4);
#endif
return memEq(hash, st->h1, 32);
}
bool_t beltHashStepV2(const octet hash[], size_t hash_len, void* state)
{
belt_hash_st* st = (belt_hash_st*)state;
ASSERT(hash_len <= 32);
ASSERT(memIsValid(hash, hash_len));
beltHashStepG_internal(state);
#if (OCTET_ORDER == BIG_ENDIAN)
beltBlockRevU32(st->h1);
beltBlockRevU32(st->h1 + 4);
#endif
return memEq(hash, st->h1, hash_len);
}
err_t beltHash(octet hash[32], const void* src, size_t count)
{
void* state;
if (!memIsValid(src, count) || !memIsValid(hash, 32))
return ERR_BAD_INPUT;
state = blobCreate(beltHash_keep());
if (state == 0)
return ERR_OUTOFMEMORY;
beltHashStart(state);
beltHashStepH(src, count, state);
beltHashStepG(hash, state);
blobClose(state);
return ERR_OK;
}