#include <arm/arch.h>
#if defined(_ARM_ARCH_7)
#include <stdio.h>
#include "vng_neon_sha1.h"
#include "ltc_hashcommon.h"
#include "tomcrypt_cfg.h"
#include "tomcrypt_macros.h"
#include "tomcrypt_argchk.h"
#include "ccDescriptors.h"
#include "ccErrors.h"
#include "ccMemory.h"
#include "CommonDigest.h"
const ccDescriptor vng_neon_sha1_desc =
{
.implementation_info = &cc_sha1_impinfo,
.dtype.digest.hashsize = CC_SHA1_DIGEST_LENGTH,
.dtype.digest.blocksize = CC_SHA1_BLOCK_BYTES,
.dtype.digest.digest_info = NULL,
.dtype.digest.init = &vng_neon_sha1_init,
.dtype.digest.process = &vng_neon_sha1_process,
.dtype.digest.done = &vng_neon_sha1_done,
};
int vng_neon_sha1_init(vng_neon_sha1_ctx *ctx)
{
LTC_ARGCHK(ctx != NULL);
ctx->state[0] = 0x67452301UL;
ctx->state[1] = 0xefcdab89UL;
ctx->state[2] = 0x98badcfeUL;
ctx->state[3] = 0x10325476UL;
ctx->state[4] = 0xc3d2e1f0UL;
ctx->curlen = 0;
ctx->length = 0;
return CRYPT_OK;
}
int vng_neon_sha1_process(vng_neon_sha1_ctx *ctx, const unsigned char *in, unsigned long inlen)
{
unsigned long n;
int err;
int fullblocks, remainder, processed;
LTC_ARGCHK(ctx != NULL);
LTC_ARGCHK(in != NULL);
if (ctx->curlen > sizeof(ctx->buf)) {
return CRYPT_INVALID_ARG;
}
if ((ctx->length + inlen) < ctx->length) {
return CRYPT_HASH_OVERFLOW;
}
while (inlen > 0) {
if (ctx->curlen == 0 && inlen >= VNG_NEON_SHA1_BLOCKSIZE && CC_XALIGNED(in, 4)) {
fullblocks = inlen / VNG_NEON_SHA1_BLOCKSIZE;
remainder = inlen % VNG_NEON_SHA1_BLOCKSIZE;
processed = fullblocks * VNG_NEON_SHA1_BLOCKSIZE;
sha1_vng_armv7neon_compress (ctx->state, fullblocks, in);
ctx->length += VNG_NEON_SHA1_BLOCKSIZE * 8 * fullblocks;
in += processed;
inlen -= processed;
} else {
n = MIN(inlen, (VNG_NEON_SHA1_BLOCKSIZE - ctx->curlen));
memcpy(ctx->buf + ctx->curlen, in, (size_t)n);
ctx->curlen += n; in += n; inlen -= n;
if (ctx->curlen == VNG_NEON_SHA1_BLOCKSIZE) {
sha1_vng_armv7neon_compress (ctx->state, 1, ctx->buf);
ctx->length += 8*VNG_NEON_SHA1_BLOCKSIZE;
ctx->curlen = 0;
}
}
}
return CRYPT_OK;
}
int vng_neon_sha1_done(vng_neon_sha1_ctx *ctx, unsigned char *out)
{
int i;
LTC_ARGCHK(ctx != NULL);
LTC_ARGCHK(out != NULL);
if (ctx->curlen >= sizeof(ctx->buf)) {
return CRYPT_INVALID_ARG;
}
ctx->length += ctx->curlen * 8;
ctx->buf[ctx->curlen++] = (unsigned char)0x80;
if (ctx->curlen > 56) {
while (ctx->curlen < 64) {
ctx->buf[ctx->curlen++] = (unsigned char)0;
}
sha1_vng_armv7neon_compress(ctx->state, 1, ctx->buf);
ctx->curlen = 0;
}
while (ctx->curlen < 56) {
ctx->buf[ctx->curlen++] = (unsigned char)0;
}
LTC_STORE64H(ctx->length, ctx->buf+56);
sha1_vng_armv7neon_compress(ctx->state, 1, ctx->buf);
for (i = 0; i < 5; i++) {
LTC_STORE32H(ctx->state[i], out+(4*i));
}
#ifdef LTC_CLEAN_STACK
ltc_zeromem(md, sizeof(ltc_hash_state));
#endif
return CRYPT_OK;
}
int vng_neon_test(void)
{
#ifndef LTC_TEST
return CRYPT_NOP;
#else
static const struct {
const char *msg;
unsigned char hash[20];
} tests[] = {
{ "abc",
{ 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a,
0xba, 0x3e, 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c,
0x9c, 0xd0, 0xd8, 0x9d }
},
{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
{ 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E,
0xBA, 0xAE, 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5,
0xE5, 0x46, 0x70, 0xF1 }
}
};
int i;
unsigned char tmp[20];
ltc_hash_state md;
for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
vng_neon_sha1_init(&md);
vng_neon_sha1_process(&md, (const unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg));
vng_neon_sha1_done(&md, tmp);
if (LTC_XMEMCMP(tmp, tests[i].hash, 20) != 0) {
return CRYPT_FAIL_TESTVECTOR;
}
}
return CRYPT_OK;
#endif
}
#endif