Files
cpuminer-opt-gpu/algo/groestl/aes_ni/hash-groestl.c
Jay D Dee 7af5b7cf80 v3.5.2
2017-01-27 12:39:55 -05:00

345 lines
8.8 KiB
C

/* hash.c Aug 2011
*
* Groestl implementation for different versions.
* Author: Krystian Matusiewicz, Günther A. Roland, Martin Schläffer
*
* This code is placed in the public domain
*/
#include "hash-groestl.h"
#include "miner.h"
#ifndef NO_AES_NI
#include "groestl-version.h"
#ifdef TASM
#ifdef VAES
#include "groestl-asm-aes.h"
#else
#ifdef VAVX
#include "groestl-asm-avx.h"
#else
#ifdef VVPERM
#include "groestl-asm-vperm.h"
#else
#error NO VERSION SPECIFIED (-DV[AES/AVX/VVPERM])
#endif
#endif
#endif
#else
#ifdef TINTR
#ifdef VAES
#include "groestl-intr-aes.h"
#else
#ifdef VAVX
#include "groestl-intr-avx.h"
#else
#ifdef VVPERM
#include "groestl-intr-vperm.h"
#else
#error NO VERSION SPECIFIED (-DV[AES/AVX/VVPERM])
#endif
#endif
#endif
#else
#error NO TYPE SPECIFIED (-DT[ASM/INTR])
#endif
#endif
/* digest up to len bytes of input (full blocks only) */
void Transform(hashState_groestl *ctx,
const u8 *in,
unsigned long long len) {
/* increment block counter */
ctx->block_counter += len/SIZE;
/* digest message, one block at a time */
for (; len >= SIZE; len -= SIZE, in += SIZE)
#if LENGTH<=256
TF512((u64*)ctx->chaining, (u64*)in);
#else
TF1024((u64*)ctx->chaining, (u64*)in);
#endif
asm volatile ("emms");
}
/* given state h, do h <- P(h)+h */
void OutputTransformation(hashState_groestl *ctx) {
/* determine variant */
#if (LENGTH <= 256)
OF512((u64*)ctx->chaining);
#else
OF1024((u64*)ctx->chaining);
#endif
asm volatile ("emms");
}
/* initialise context */
HashReturn_gr init_groestl(hashState_groestl* ctx) {
u8 i = 0;
/* output size (in bits) must be a positive integer less than or
equal to 512, and divisible by 8 */
if (LENGTH <= 0 || (LENGTH%8) || LENGTH > 512)
return BAD_HASHBITLEN_GR;
/* set number of state columns and state size depending on
variant */
ctx->columns = COLS;
ctx->statesize = SIZE;
#if (LENGTH <= 256)
ctx->v = SHoRT;
#else
ctx->v = LoNG;
#endif
SET_CONSTANTS();
for (i=0; i<SIZE/8; i++)
ctx->chaining[i] = 0;
for (i=0; i<SIZE; i++)
ctx->buffer[i] = 0;
if (ctx->chaining == NULL || ctx->buffer == NULL)
return FAIL_GR;
/* set initial value */
ctx->chaining[ctx->columns-1] = U64BIG((u64)LENGTH);
INIT(ctx->chaining);
/* set other variables */
ctx->buf_ptr = 0;
ctx->block_counter = 0;
ctx->bits_in_last_byte = 0;
return SUCCESS_GR;
}
HashReturn_gr reinit_groestl(hashState_groestl* ctx)
{
int i;
for (i=0; i<SIZE/8; i++)
ctx->chaining[i] = 0;
for (i=0; i<SIZE; i++)
ctx->buffer[i] = 0;
if (ctx->chaining == NULL || ctx->buffer == NULL)
return FAIL_GR;
/* set initial value */
ctx->chaining[ctx->columns-1] = U64BIG((u64)LENGTH);
INIT(ctx->chaining);
/* set other variables */
ctx->buf_ptr = 0;
ctx->block_counter = 0;
// not used
ctx->bits_in_last_byte = 0;
return SUCCESS_GR;
}
/* update state with databitlen bits of input */
HashReturn_gr update_groestl(hashState_groestl* ctx,
const BitSequence_gr* input,
DataLength_gr databitlen) {
int index = 0;
int msglen = (int)(databitlen/8);
int rem = (int)(databitlen%8); // not used
// The only data length used is either 64 bytes (512 bits,
// or 80 bytes (640 bits). The sph version of groestl used a byte
// size for the data length, so odd bits aren't supported there.
// No need to support them here either, change the arg to bytes
// for consistency.
/* non-integral number of message bytes can only be supplied in the
last call to this function */
if (ctx->bits_in_last_byte) return FAIL_GR;
/* if the buffer contains data that has not yet been digested, first
add data to buffer until full */
//// This code can never run, it is indeed dead. buf_ptr is initialized
//// to 0 in init_groestl and hasn't been changed yet
// The following block of code never gets hit when hashing x11 or quark
// leave it here in case it might be needed.
// if (ctx->buf_ptr)
// {
// while (ctx->buf_ptr < ctx->statesize && index < msglen)
// {
// ctx->buffer[(int)ctx->buf_ptr++] = input[index++];
// }
// if (ctx->buf_ptr < ctx->statesize)
// {
// /* buffer still not full, return */
// if (rem)
// {
// ctx->bits_in_last_byte = rem;
// ctx->buffer[(int)ctx->buf_ptr++] = input[index];
// }
// return SUCCESS_GR;
// }
// /* digest buffer */
// ctx->buf_ptr = 0;
// printf("error\n");
// Transform(ctx, ctx->buffer, ctx->statesize);
// end dead code
// }
/* digest bulk of message */
Transform(ctx, input+index, msglen-index);
// index is always zero here, the following line sets it == msglen
// meaning the next while test will always fail. it's all part of
// supporting odd bits.
index += ((msglen-index)/ctx->statesize)*ctx->statesize;
/* store remaining data in buffer */
while (index < msglen)
{
ctx->buffer[(int)ctx->buf_ptr++] = input[index++];
}
// buf_ptr should be msglen now.
//// This code isn't quite dead but but would only run if datalen
/// is not a multiple of 8. As a result bits_in_last_byte is never
//// modified from its initial zero.
// Another block that doesn't get used by x11 or quark
// /* if non-integral number of bytes have been supplied, store
// remaining bits in last byte, together with information about
// number of bits */
// if (rem)
// {
// ctx->bits_in_last_byte = rem;
// ctx->buffer[(int)ctx->buf_ptr++] = input[index];
// }
return SUCCESS_GR;
}
#define BILB ctx->bits_in_last_byte
/* finalise: process remaining data (including padding), perform
output transformation, and write hash result to 'output' */
HashReturn_gr final_groestl(hashState_groestl* ctx,
BitSequence_gr* output) {
int i, j = 0, hashbytelen = LENGTH/8;
u8 *s = (BitSequence_gr*)ctx->chaining;
/* pad with '1'-bit and first few '0'-bits */
if (BILB) {
ctx->buffer[(int)ctx->buf_ptr-1] &= ((1<<BILB)-1)<<(8-BILB);
ctx->buffer[(int)ctx->buf_ptr-1] ^= 0x1<<(7-BILB);
BILB = 0;
}
//This sets the first pad byte
else ctx->buffer[(int)ctx->buf_ptr++] = 0x80;
// buf_ptr is left == msglen after update_groestl, 64 (bytes).
// It has now been incrememnted to 65. The test below should fail
// with 64 and 80 and require 1 pad block. Why does 64 bit need a pad block?
// length padding?
/* pad with '0'-bits */
if (ctx->buf_ptr > ctx->statesize-LENGTHFIELDLEN) {
/* padding requires two blocks */
while (ctx->buf_ptr < ctx->statesize) {
ctx->buffer[(int)ctx->buf_ptr++] = 0;
}
/* digest first padding block */
Transform(ctx, ctx->buffer, ctx->statesize);
ctx->buf_ptr = 0;
}
// the padding can be vectorized, including the first pad byte above
// 64 bit: buffer[64..79] = {0x80000000,0,0,0}
// buffer[80..95] = {0,0,0,0}
// buffer[96..111] = {0,0,0,0}
// buffer[112..128 = {0,0,length padding}
// 80 bit: buffer[64..79] = unchanged
// buffer[80..95] = {0x800000000,0,0,0}
// buffer[96..111] = {0,0,0,0}
// buffer[112..128 = {0,0,length padding}
// this will pad up to 120 bytes
while (ctx->buf_ptr < ctx->statesize-LENGTHFIELDLEN) {
ctx->buffer[(int)ctx->buf_ptr++] = 0;
}
/* length padding */
ctx->block_counter++;
ctx->buf_ptr = ctx->statesize;
while (ctx->buf_ptr > ctx->statesize-LENGTHFIELDLEN) {
ctx->buffer[(int)--ctx->buf_ptr] = (u8)ctx->block_counter;
ctx->block_counter >>= 8;
}
/* digest final padding block */
Transform(ctx, ctx->buffer, ctx->statesize);
/* perform output transformation */
OutputTransformation(ctx);
/* store hash result in output */
for (i = ctx->statesize-hashbytelen; i < ctx->statesize; i++,j++) {
output[j] = s[i];
}
// the following is redundant as init_groestl will reset to zero.
/* zeroise relevant variables and deallocate memory */
for (i = 0; i < ctx->columns; i++) {
ctx->chaining[i] = 0;
}
for (i = 0; i < ctx->statesize; i++) {
ctx->buffer[i] = 0;
}
// free(ctx->chaining);
// free(ctx->buffer);
return SUCCESS_GR;
}
/* hash bit sequence */
HashReturn_gr hash_groestl(int hashbitlen,
const BitSequence_gr* data,
DataLength_gr databitlen,
BitSequence_gr* hashval) {
HashReturn_gr ret;
hashState_groestl context;
/* initialise */
if ((ret = init_groestl(&context)) != SUCCESS_GR)
return ret;
/* process message */
if ((ret = update_groestl(&context, data, databitlen)) != SUCCESS_GR)
return ret;
/* finalise */
ret = final_groestl(&context, hashval);
return ret;
}
/* eBash API */
#ifdef crypto_hash_BYTES
int crypto_hash(unsigned char *out, const unsigned char *in, unsigned long long inlen)
{
if (hash_groestl(crypto_hash_BYTES * 8, in, inlen * 8,out) == SUCCESS_GR) return 0;
return -1;
}
#endif
#endif