@ -43,99 +43,99 @@ extern uint32_t *heavy_heftyHashes[MAX_GPUS];
/* Combines top 64-bits from each hash into a single hash */
/* Combines top 64-bits from each hash into a single hash */
static void combine_hashes(uint32_t *out, const uint32_t *hash1, const uint32_t *hash2, const uint32_t *hash3, const uint32_t *hash4)
static void combine_hashes(uint32_t *out, const uint32_t *hash1, const uint32_t *hash2, const uint32_t *hash3, const uint32_t *hash4)
{
{
const uint32_t *hash[4] = { hash1, hash2, hash3, hash4 };
const uint32_t *hash[4] = { hash1, hash2, hash3, hash4 };
int bits;
int bits;
unsigned int i;
unsigned int i;
uint32_t mask;
uint32_t mask;
unsigned int k;
unsigned int k;
/* Transpose first 64 bits of each hash into out */
/* Transpose first 64 bits of each hash into out */
memset(out, 0, 32);
memset(out, 0, 32);
bits = 0;
bits = 0;
for (i = 7; i >= 6; i--) {
for (i = 7; i >= 6; i--) {
for (mask = 0x80000000; mask; mask >>= 1) {
for (mask = 0x80000000; mask; mask >>= 1) {
for (k = 0; k < 4; k++) {
for (k = 0; k < 4; k++) {
out[(255 - bits)/32] <<= 1;
out[(255 - bits)/32] <<= 1;
if ((hash[k][i] & mask) != 0)
if ((hash[k][i] & mask) != 0)
out[(255 - bits)/32] |= 1;
out[(255 - bits)/32] |= 1;
bits++;
bits++;
}
}
}
}
}
}
}
}
#ifdef _MSC_VER
#ifdef _MSC_VER
#include <intrin.h>
#include <intrin.h>
static uint32_t __inline bitsset( uint32_t x )
static uint32_t __inline bitsset( uint32_t x )
{
{
DWORD r = 0;
DWORD r = 0;
_BitScanReverse(&r, x);
_BitScanReverse(&r, x);
return r;
return r;
}
}
#else
#else
static uint32_t bitsset( uint32_t x )
static uint32_t bitsset( uint32_t x )
{
{
return 31-__builtin_clz(x);
return 31-__builtin_clz(x);
}
}
#endif
#endif
// Finde das high bit in einem Multiword-Integer.
// Finde das high bit in einem Multiword-Integer.
static int findhighbit(const uint32_t *ptarget, int words)
static int findhighbit(const uint32_t *ptarget, int words)
{
{
int i;
int i;
int highbit = 0;
int highbit = 0;
for (i=words-1; i >= 0; --i)
for (i=words-1; i >= 0; --i)
{
{
if (ptarget[i] != 0) {
if (ptarget[i] != 0) {
highbit = i*32 + bitsset(ptarget[i])+1;
highbit = i*32 + bitsset(ptarget[i])+1;
break;
break;
}
}
}
}
return highbit;
return highbit;
}
}
// Generiere ein Multiword-Integer das die Zahl
// Generiere ein Multiword-Integer das die Zahl
// (2 << highbit) - 1 repräsentiert.
// (2 << highbit) - 1 repräsentiert.
static void genmask(uint32_t *ptarget, int words, int highbit)
static void genmask(uint32_t *ptarget, int words, int highbit)
{
{
int i;
int i;
for (i=words-1; i >= 0; --i)
for (i=words-1; i >= 0; --i)
{
{
if ((i+1)*32 <= highbit)
if ((i+1)*32 <= highbit)
ptarget[i] = UINT32_MAX;
ptarget[i] = UINT32_MAX;
else if (i*32 > highbit)
else if (i*32 > highbit)
ptarget[i] = 0x00000000;
ptarget[i] = 0x00000000;
else
else
ptarget[i] = (1 << (highbit-i*32)) - 1;
ptarget[i] = (1 << (highbit-i*32)) - 1;
}
}
}
}
struct check_nonce_for_remove
struct check_nonce_for_remove
{
{
check_nonce_for_remove(uint64_t target, uint32_t *hashes, uint32_t hashlen, uint32_t startNonce) :
check_nonce_for_remove(uint64_t target, uint32_t *hashes, uint32_t hashlen, uint32_t startNonce) :
m_target(target),
m_target(target),
m_hashes(hashes),
m_hashes(hashes),
m_hashlen(hashlen),
m_hashlen(hashlen),
m_startNonce(startNonce) { }
m_startNonce(startNonce) { }
uint64_t m_target;
uint64_t m_target;
uint32_t *m_hashes;
uint32_t *m_hashes;
uint32_t m_hashlen;
uint32_t m_hashlen;
uint32_t m_startNonce;
uint32_t m_startNonce;
__device__
__device__
bool operator()(const uint32_t x)
bool operator()(const uint32_t x)
{
{
// Position im Hash Buffer
// Position im Hash Buffer
uint32_t hashIndex = x - m_startNonce;
uint32_t hashIndex = x - m_startNonce;
// Wert des Hashes (als uint64_t) auslesen.
// Wert des Hashes (als uint64_t) auslesen.
// Steht im 6. und 7. Wort des Hashes (jeder dieser Hashes hat 512 Bits)
// Steht im 6. und 7. Wort des Hashes (jeder dieser Hashes hat 512 Bits)
uint64_t hashValue = *((uint64_t*)(&m_hashes[m_hashlen*hashIndex + 6]));
uint64_t hashValue = *((uint64_t*)(&m_hashes[m_hashlen*hashIndex + 6]));
bool res = (hashValue & m_target) != hashValue;
bool res = (hashValue & m_target) != hashValue;
//printf("ndx=%x val=%08x target=%lx\n", hashIndex, hashValue, m_target);
//printf("ndx=%x val=%08x target=%lx\n", hashIndex, hashValue, m_target);
// gegen das Target prüfen. Es dürfen nur Bits aus dem Target gesetzt sein.
// gegen das Target prüfen. Es dürfen nur Bits aus dem Target gesetzt sein.
return res;
return res;
}
}
};
};
static bool init[MAX_GPUS] = { 0 };
static bool init[MAX_GPUS] = { 0 };
@ -143,245 +143,252 @@ static bool init[MAX_GPUS] = { 0 };
__host__
__host__
int scanhash_heavy(int thr_id, struct work *work, uint32_t max_nonce, unsigned long *hashes_done, uint32_t maxvote, int blocklen)
int scanhash_heavy(int thr_id, struct work *work, uint32_t max_nonce, unsigned long *hashes_done, uint32_t maxvote, int blocklen)
{
{
uint32_t *pdata = work->data;
uint32_t *pdata = work->data;
uint32_t *ptarget = work->target;
uint32_t *ptarget = work->target;
const uint32_t first_nonce = pdata[19];
const uint32_t first_nonce = pdata[19];
// CUDA will process thousands of threads.
// CUDA will process thousands of threads.
uint32_t throughput = cuda_default_throughput(thr_id, (1U << 19) - 256);
uint32_t throughput = cuda_default_throughput(thr_id, (1U << 19) - 256);
if (init[thr_id]) throughput = min(throughput, max_nonce - first_nonce);
if (init[thr_id]) throughput = min(throughput, max_nonce - first_nonce);
int rc = 0;
int rc = 0;
uint32_t *hash = NULL;
uint32_t *hash = NULL;
uint32_t *cpu_nonceVector = NULL;
uint32_t *cpu_nonceVector = NULL;
CUDA_SAFE_CALL(cudaMallocHost(&hash, throughput*8*sizeof(uint32_t)));
CUDA_SAFE_CALL(cudaMallocHost(&cpu_nonceVector, throughput*sizeof(uint32_t)));
int nrmCalls[6];
memset(nrmCalls, 0, sizeof(int) * 6);
int nrmCalls[6];
memset(nrmCalls, 0, sizeof(int) * 6);
if (opt_benchmark)
ptarget[7] = 0x000f;
if (opt_benchmark)
((uint32_t*)ptarget)[7] = 0x00ff;
// für jeden Hash ein individuelles Target erstellen basierend
// auf dem höchsten Bit, das in ptarget gesetzt ist.
// für jeden Hash ein individuelles Target erstellen basierend
int highbit = findhighbit(ptarget, 8);
// auf dem höchsten Bit, das in ptarget gesetzt ist.
uint32_t target2[2], target3[2], target4[2], target5[2];
int highbit = findhighbit(ptarget, 8);
genmask(target2, 2, highbit/4+(((highbit%4)>3)?1:0) ); // SHA256
uint32_t target2[2], target3[2], target4[2], target5[2];
genmask(target3, 2, highbit/4+(((highbit%4)>2)?1:0) ); // keccak512
genmask(target2, 2, highbit/4+(((highbit%4)>3)?1:0) ); // SHA256
genmask(target4, 2, highbit/4+(((highbit%4)>1)?1:0) ); // groestl512
genmask(target3, 2, highbit/4+(((highbit%4)>2)?1:0) ); // keccak512
genmask(target5, 2, highbit/4+(((highbit%4)>0)?1:0) ); // blake512
genmask(target4, 2, highbit/4+(((highbit%4)>1)?1:0) ); // groestl512
genmask(target5, 2, highbit/4+(((highbit%4)>0)?1:0) ); // blake512
if (!init[thr_id])
{
if (!init[thr_id])
cudaSetDevice(device_map[thr_id]);
{
hefty_cpu_init(thr_id, throughput);
hefty_cpu_init(thr_id, throughput);
sha256_cpu_init(thr_id, throughput);
sha256_cpu_init(thr_id, throughput);
keccak512_cpu_init(thr_id, throughput);
keccak512_cpu_init(thr_id, throughput);
groestl512_cpu_init(thr_id, throughput);
groestl512_cpu_init(thr_id, throughput);
blake512_cpu_init(thr_id, throughput);
blake512_cpu_init(thr_id, throughput);
combine_cpu_init(thr_id, throughput);
combine_cpu_init(thr_id, throughput);
CUDA_SAFE_CALL(cudaMalloc(&heavy_nonceVector[thr_id], sizeof(uint32_t) * throughput));
CUDA_SAFE_CALL(cudaMalloc(&heavy_nonceVector[thr_id], sizeof(uint32_t) * throughput));
init[thr_id] = true;
init[thr_id] = true;
}
}
if (blocklen == HEAVYCOIN_BLKHDR_SZ)
// weird but require at least one cudaSetDevice first
{
CUDA_SAFE_CALL(cudaMallocHost(&hash, (size_t) 32 * throughput));
uint16_t *ext = (uint16_t *)&pdata[20];
CUDA_SAFE_CALL(cudaMallocHost(&cpu_nonceVector, sizeof(uint32_t) * throughput));
if (opt_vote > maxvote && !opt_benchmark) {
if (blocklen == HEAVYCOIN_BLKHDR_SZ)
applog(LOG_WARNING, "Your block reward vote (%hu) exceeds "
{
"the maxvote reported by the pool (%hu).",
uint16_t *ext = (uint16_t*) &pdata[20];
opt_vote, maxvote);
}
if (opt_vote > maxvote && !opt_benchmark) {
applog(LOG_WARNING, "Your block reward vote (%hu) exceeds the maxvote reported by the pool (%hu).",
if (opt_trust_pool && opt_vote > maxvote) {
opt_vote, maxvote);
applog(LOG_WARNING, "Capping block reward vote to maxvote reported by pool.");
}
ext[0] = maxvote;
}
if (opt_trust_pool && opt_vote > maxvote) {
else
applog(LOG_WARNING, "Capping block reward vote to maxvote reported by pool.");
ext[0] = opt_vote;
ext[0] = maxvote;
}
}
else
// Setze die Blockdaten
ext[0] = opt_vote;
hefty_cpu_setBlock(thr_id, throughput, pdata, blocklen);
}
sha256_cpu_setBlock(pdata, blocklen);
keccak512_cpu_setBlock(pdata, blocklen);
// Setze die Blockdaten
groestl512_cpu_setBlock(pdata, blocklen);
hefty_cpu_setBlock(thr_id, throughput, pdata, blocklen);
blake512_cpu_setBlock(pdata, blocklen);
sha256_cpu_setBlock(pdata, blocklen);
keccak512_cpu_setBlock(pdata, blocklen);
do {
groestl512_cpu_setBlock(pdata, blocklen);
uint32_t actualNumberOfValuesInNonceVectorGPU = throughput;
blake512_cpu_setBlock(pdata, blocklen);
////// Compaction init
do {
uint32_t actualNumberOfValuesInNonceVectorGPU = throughput;
hefty_cpu_hash(thr_id, throughput, pdata[19]);
sha256_cpu_hash(thr_id, throughput, pdata[19]);
////// Compaction init
// Hier ist die längste CPU Wartephase. Deshalb ein strategisches MyStreamSynchronize() hier.
hefty_cpu_hash(thr_id, throughput, pdata[19]);
MyStreamSynchronize(NULL, 1, thr_id);
sha256_cpu_hash(thr_id, throughput, pdata[19]);
// Hier ist die längste CPU Wartephase. Deshalb ein strategisches MyStreamSynchronize() hier.
MyStreamSynchronize(NULL, 1, thr_id);
#if USE_THRUST
#if USE_THRUST
thrust::device_ptr<uint32_t> devNoncePtr(heavy_nonceVector[thr_id]);
thrust::device_ptr<uint32_t> devNoncePtr(heavy_nonceVector[thr_id]);
thrust::device_ptr<uint32_t> devNoncePtrEnd((heavy_nonceVector[thr_id]) + throughput);
thrust::device_ptr<uint32_t> devNoncePtrEnd((heavy_nonceVector[thr_id]) + throughput);
////// Compaction
////// Compaction
uint64_t *t = (uint64_t*) target2;
uint64_t *t = (uint64_t*) target2;
devNoncePtrEnd = thrust::remove_if(devNoncePtr, devNoncePtrEnd, check_nonce_for_remove(*t, d_hash2output[thr_id], 8, pdata[19]));
devNoncePtrEnd = thrust::remove_if(devNoncePtr, devNoncePtrEnd, check_nonce_for_remove(*t, d_hash2output[thr_id], 8, pdata[19]));
actualNumberOfValuesInNonceVectorGPU = (uint32_t)(devNoncePtrEnd - devNoncePtr);
actualNumberOfValuesInNonceVectorGPU = (uint32_t)(devNoncePtrEnd - devNoncePtr);
if(actualNumberOfValuesInNonceVectorGPU == 0)
if(actualNumberOfValuesInNonceVectorGPU == 0)
goto emptyNonceVector;
goto emptyNonceVector;
keccak512_cpu_hash(thr_id, actualNumberOfValuesInNonceVectorGPU, pdata[19]);
keccak512_cpu_hash(thr_id, actualNumberOfValuesInNonceVectorGPU, pdata[19]);
////// Compaction
////// Compaction
t = (uint64_t*) target3;
t = (uint64_t*) target3;
devNoncePtrEnd = thrust::remove_if(devNoncePtr, devNoncePtrEnd, check_nonce_for_remove(*t, d_hash3output[thr_id], 16, pdata[19]));
devNoncePtrEnd = thrust::remove_if(devNoncePtr, devNoncePtrEnd, check_nonce_for_remove(*t, d_hash3output[thr_id], 16, pdata[19]));
actualNumberOfValuesInNonceVectorGPU = (uint32_t)(devNoncePtrEnd - devNoncePtr);
actualNumberOfValuesInNonceVectorGPU = (uint32_t)(devNoncePtrEnd - devNoncePtr);
if(actualNumberOfValuesInNonceVectorGPU == 0)
if(actualNumberOfValuesInNonceVectorGPU == 0)
goto emptyNonceVector;
goto emptyNonceVector;
blake512_cpu_hash(thr_id, actualNumberOfValuesInNonceVectorGPU, pdata[19]);
blake512_cpu_hash(thr_id, actualNumberOfValuesInNonceVectorGPU, pdata[19]);
////// Compaction
////// Compaction
t = (uint64_t*) target5;
t = (uint64_t*) target5;
devNoncePtrEnd = thrust::remove_if(devNoncePtr, devNoncePtrEnd, check_nonce_for_remove(*t, d_hash5output[thr_id], 16, pdata[19]));
devNoncePtrEnd = thrust::remove_if(devNoncePtr, devNoncePtrEnd, check_nonce_for_remove(*t, d_hash5output[thr_id], 16, pdata[19]));
actualNumberOfValuesInNonceVectorGPU = (uint32_t)(devNoncePtrEnd - devNoncePtr);
actualNumberOfValuesInNonceVectorGPU = (uint32_t)(devNoncePtrEnd - devNoncePtr);
if(actualNumberOfValuesInNonceVectorGPU == 0)
if(actualNumberOfValuesInNonceVectorGPU == 0)
goto emptyNonceVector;
goto emptyNonceVector;
groestl512_cpu_hash(thr_id, actualNumberOfValuesInNonceVectorGPU, pdata[19]);
groestl512_cpu_hash(thr_id, actualNumberOfValuesInNonceVectorGPU, pdata[19]);
////// Compaction
////// Compaction
t = (uint64_t*) target4;
t = (uint64_t*) target4;
devNoncePtrEnd = thrust::remove_if(devNoncePtr, devNoncePtrEnd, check_nonce_for_remove(*t, d_hash4output[thr_id], 16, pdata[19]));
devNoncePtrEnd = thrust::remove_if(devNoncePtr, devNoncePtrEnd, check_nonce_for_remove(*t, d_hash4output[thr_id], 16, pdata[19]));
actualNumberOfValuesInNonceVectorGPU = (uint32_t)(devNoncePtrEnd - devNoncePtr);
actualNumberOfValuesInNonceVectorGPU = (uint32_t)(devNoncePtrEnd - devNoncePtr);
#else
#else
// todo
// todo (nvlabs cub ?)
actualNumberOfValuesInNonceVectorGPU = 0;
actualNumberOfValuesInNonceVectorGPU = 0;
#endif
#endif
if(actualNumberOfValuesInNonceVectorGPU == 0)
if(actualNumberOfValuesInNonceVectorGPU == 0)
goto emptyNonceVector;
goto emptyNonceVector;
// combine
// combine
combine_cpu_hash(thr_id, actualNumberOfValuesInNonceVectorGPU, pdata[19], hash);
combine_cpu_hash(thr_id, actualNumberOfValuesInNonceVectorGPU, pdata[19], hash);
if (opt_tracegpu) {
if (opt_tracegpu) {
applog(LOG_BLUE, "heavy GPU hash:");
applog(LOG_BLUE, "heavy GPU hash:");
applog_hash((uchar*)hash);
applog_hash((uchar*)hash);
}
}
// Ergebnisse kopieren
// Ergebnisse kopieren
if(actualNumberOfValuesInNonceVectorGPU > 0)
if(actualNumberOfValuesInNonceVectorGPU > 0)
{
{
size_t size = sizeof(uint32_t) * actualNumberOfValuesInNonceVectorGPU;
size_t size = sizeof(uint32_t) * actualNumberOfValuesInNonceVectorGPU;
CUDA_SAFE_CALL(cudaMemcpy(cpu_nonceVector, heavy_nonceVector[thr_id], size, cudaMemcpyDeviceToHost));
cudaMemcpy(cpu_nonceVector, heavy_nonceVector[thr_id], size, cudaMemcpyDeviceToHost);
cudaThreadSynchronize();
for (uint32_t i=0; i < actualNumberOfValuesInNonceVectorGPU; i++)
for (uint32_t i=0; i < actualNumberOfValuesInNonceVectorGPU; i++)
{
{
uint32_t nonce = cpu_nonceVector[i];
uint32_t nonce = cpu_nonceVector[i];
uint32_t *foundhash = &hash[8*i];
uint32_t *foundhash = &hash[8*i];
if (foundhash[7] <= ptarget[7] && fulltest(foundhash, ptarget)) {
if (foundhash[7] <= ptarget[7] && fulltest(foundhash, ptarget)) {
uint32_t vhash[8];
uint32_t vhash[8];
pdata[19] += nonce - pdata[19];
pdata[19] += nonce - pdata[19];
heavycoin_hash((uchar*)vhash, (uchar*)pdata, blocklen);
heavycoin_hash((uchar*)vhash, (uchar*)pdata, blocklen);
if (memcmp(vhash, foundhash, 32)) {
if (memcmp(vhash, foundhash, 32)) {
gpulog(LOG_WARNING, thr_id, "result for %08x does not validate on CPU!", nonce);
gpulog(LOG_WARNING, thr_id, "result for %08x does not validate on CPU!", nonce);
} else {
} else {
work_set_target_ratio(work, vhash);
*hashes_done = pdata[19] - first_nonce;
rc = 1;
work_set_target_ratio(work, vhash);
goto exit;
rc = 1;
}
goto exit;
}
}
}
}
}
}
}
emptyNonceVector:
emptyNonceVector:
if ((uint64_t) throughput + pdata[19] >= max_nonce) {
pdata[19] = max_nonce;
break;
}
pdata[19] += throughput;
pdata[19] += throughput;
} while (!work_restart[thr_id].restart);
} while (pdata[19] < max_nonce && !work_restart[thr_id].restart);
*hashes_done = pdata[19] - first_nonce;
exit:
exit:
cudaFreeHost(cpu_nonceVector);
*hashes_done = pdata[19] - first_nonce;
cudaFreeHost(hash);
return rc;
cudaFreeHost(cpu_nonceVector);
cudaFreeHost(hash);
CUDA_LOG_ERROR();
return rc;
}
}
// cleanup
// cleanup
extern "C" void free_heavy(int thr_id)
extern "C" void free_heavy(int thr_id)
{
{
if (!init[thr_id])
if (!init[thr_id])
return;
return;
cudaThreadSynchronize();
cudaThreadSynchronize();
cudaFree(heavy_nonceVector[thr_id]);
cudaFree(heavy_nonceVector[thr_id]);
blake512_cpu_free(thr_id);
blake512_cpu_free(thr_id);
groestl512_cpu_free(thr_id);
groestl512_cpu_free(thr_id);
hefty_cpu_free(thr_id);
hefty_cpu_free(thr_id);
keccak512_cpu_free(thr_id);
keccak512_cpu_free(thr_id);
sha256_cpu_free(thr_id);
sha256_cpu_free(thr_id);
combine_cpu_free(thr_id);
combine_cpu_free(thr_id);
init[thr_id] = false;
init[thr_id] = false;
cudaDeviceSynchronize();
cudaDeviceSynchronize();
}
}
__host__
__host__
void heavycoin_hash(uchar* output, const uchar* input, int len)
void heavycoin_hash(uchar* output, const uchar* input, int len)
{
{
unsigned char hash1[32];
unsigned char hash1[32];
unsigned char hash2[32];
unsigned char hash2[32];
uint32_t hash3[16];
uint32_t hash3[16];
uint32_t hash4[16];
uint32_t hash4[16];
uint32_t hash5[16];
uint32_t hash5[16];
uint32_t *final;
uint32_t *final;
SHA256_CTX ctx;
SHA256_CTX ctx;
sph_keccak512_context keccakCtx;
sph_keccak512_context keccakCtx;
sph_groestl512_context groestlCtx;
sph_groestl512_context groestlCtx;
sph_blake512_context blakeCtx;
sph_blake512_context blakeCtx;
HEFTY1(input, len, hash1);
HEFTY1(input, len, hash1);
/* HEFTY1 is new, so take an extra security measure to eliminate
/* HEFTY1 is new, so take an extra security measure to eliminate
* the possiblity of collisions:
* the possiblity of collisions:
*
*
* Hash(x) = SHA256(x + HEFTY1(x))
* Hash(x) = SHA256(x + HEFTY1(x))
*
*
* N.B. '+' is concatenation.
* N.B. '+' is concatenation.
*/
*/
SHA256_Init(&ctx);
SHA256_Init(&ctx);
SHA256_Update(&ctx, input, len);
SHA256_Update(&ctx, input, len);
SHA256_Update(&ctx, hash1, sizeof(hash1));
SHA256_Update(&ctx, hash1, sizeof(hash1));
SHA256_Final(hash2, &ctx);
SHA256_Final(hash2, &ctx);
/* Additional security: Do not rely on a single cryptographic hash
/* Additional security: Do not rely on a single cryptographic hash
* function. Instead, combine the outputs of 4 of the most secure
* function. Instead, combine the outputs of 4 of the most secure
* cryptographic hash functions-- SHA256, KECCAK512, GROESTL512
* cryptographic hash functions-- SHA256, KECCAK512, GROESTL512
* and BLAKE512.
* and BLAKE512.
*/
*/
sph_keccak512_init(&keccakCtx);
sph_keccak512_init(&keccakCtx);
sph_keccak512(&keccakCtx, input, len);
sph_keccak512(&keccakCtx, input, len);
sph_keccak512(&keccakCtx, hash1, sizeof(hash1));
sph_keccak512(&keccakCtx, hash1, sizeof(hash1));
sph_keccak512_close(&keccakCtx, (void *)&hash3);
sph_keccak512_close(&keccakCtx, (void *)&hash3);
sph_groestl512_init(&groestlCtx);
sph_groestl512_init(&groestlCtx);
sph_groestl512(&groestlCtx, input, len);
sph_groestl512(&groestlCtx, input, len);
sph_groestl512(&groestlCtx, hash1, sizeof(hash1));
sph_groestl512(&groestlCtx, hash1, sizeof(hash1));
sph_groestl512_close(&groestlCtx, (void *)&hash4);
sph_groestl512_close(&groestlCtx, (void *)&hash4);
sph_blake512_init(&blakeCtx);
sph_blake512_init(&blakeCtx);
sph_blake512(&blakeCtx, input, len);
sph_blake512(&blakeCtx, input, len);
sph_blake512(&blakeCtx, (unsigned char *)&hash1, sizeof(hash1));
sph_blake512(&blakeCtx, (unsigned char *)&hash1, sizeof(hash1));
sph_blake512_close(&blakeCtx, (void *)&hash5);
sph_blake512_close(&blakeCtx, (void *)&hash5);
final = (uint32_t *)output;
final = (uint32_t *)output;
combine_hashes(final, (uint32_t *)hash2, hash3, hash4, hash5);
combine_hashes(final, (uint32_t *)hash2, hash3, hash4, hash5);
}
}