A cryptographic module for node.js
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

238 lines
7.8 KiB

// (C) 2018 Michael Toutonghi
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
/*
This provides the PoW hash function for Verus, enabling CPU mining.
*/
#ifndef VERUS_HASH_H_
#define VERUS_HASH_H_
// verbose output when defined
//#define VERUSHASHDEBUG 1
#include <cstring>
#include <vector>
#include "uint256.h"
#include "verus_clhash.h"
extern "C"
{
#include "haraka.h"
#include "haraka_portable.h"
}
class CVerusHash
{
public:
static void Hash(void *result, const void *data, size_t len);
static void (*haraka512Function)(unsigned char *out, const unsigned char *in);
static void init();
CVerusHash() { }
CVerusHash &Write(const unsigned char *data, size_t len);
CVerusHash &Reset()
{
curBuf = buf1;
result = buf2;
curPos = 0;
std::fill(buf1, buf1 + sizeof(buf1), 0);
return *this;
}
int64_t *ExtraI64Ptr() { return (int64_t *)(curBuf + 32); }
void ClearExtra()
{
if (curPos)
{
std::fill(curBuf + 32 + curPos, curBuf + 64, 0);
}
}
void ExtraHash(unsigned char hash[32]) { (*haraka512Function)(hash, curBuf); }
void Finalize(unsigned char hash[32])
{
if (curPos)
{
std::fill(curBuf + 32 + curPos, curBuf + 64, 0);
(*haraka512Function)(hash, curBuf);
}
else
std::memcpy(hash, curBuf, 32);
}
private:
// only buf1, the first source, needs to be zero initialized
unsigned char buf1[64] = {0}, buf2[64];
unsigned char *curBuf = buf1, *result = buf2;
size_t curPos = 0;
};
class CVerusHashV2
{
public:
static void Hash(void *result, const void *data, size_t len);
static void (*haraka512Function)(unsigned char *out, const unsigned char *in);
static void (*haraka512KeyedFunction)(unsigned char *out, const unsigned char *in, const u128 *rc);
static void (*haraka256Function)(unsigned char *out, const unsigned char *in);
static void init();
verusclhasher vclh;
CVerusHashV2(int solutionVerusion=SOLUTION_VERUSHHASH_V2) : vclh(VERUSKEYSIZE, solutionVerusion) {
// we must have allocated key space, or can't run
if (!verusclhasher_key.get())
{
printf("ERROR: failed to allocate hash buffer - terminating\n");
assert(false);
}
}
CVerusHashV2 &Write(const unsigned char *data, size_t len);
inline CVerusHashV2 &Reset()
{
curBuf = buf1;
result = buf2;
curPos = 0;
std::fill(buf1, buf1 + sizeof(buf1), 0);
return *this;
}
inline int64_t *ExtraI64Ptr() { return (int64_t *)(curBuf + 32); }
inline void ClearExtra()
{
if (curPos)
{
std::fill(curBuf + 32 + curPos, curBuf + 64, 0);
}
}
template <typename T>
inline void FillExtra(const T *_data)
{
unsigned char *data = (unsigned char *)_data;
int pos = curPos;
int left = 32 - pos;
do
{
int len = left > sizeof(T) ? sizeof(T) : left;
std::memcpy(curBuf + 32 + pos, data, len);
pos += len;
left -= len;
} while (left > 0);
}
inline void ExtraHash(unsigned char hash[32]) { (*haraka512Function)(hash, curBuf); }
inline void ExtraHashKeyed(unsigned char hash[32], u128 *key) { (*haraka512KeyedFunction)(hash, curBuf, key); }
void Finalize(unsigned char hash[32])
{
if (curPos)
{
std::fill(curBuf + 32 + curPos, curBuf + 64, 0);
(*haraka512Function)(hash, curBuf);
}
else
std::memcpy(hash, curBuf, 32);
}
// chains Haraka256 from 32 bytes to fill the key
static u128 *GenNewCLKey(unsigned char *seedBytes32)
{
unsigned char *key = (unsigned char *)verusclhasher_key.get();
verusclhash_descr *pdesc = (verusclhash_descr *)verusclhasher_descr.get();
int size = pdesc->keySizeInBytes;
int refreshsize = verusclhasher::keymask(size) + 1;
// skip keygen if it is the current key
if (pdesc->seed != *((uint256 *)seedBytes32))
{
// generate a new key by chain hashing with Haraka256 from the last curbuf
int n256blks = size >> 5;
int nbytesExtra = size & 0x1f;
unsigned char *pkey = key;
unsigned char *psrc = seedBytes32;
for (int i = 0; i < n256blks; i++)
{
(*haraka256Function)(pkey, psrc);
psrc = pkey;
pkey += 32;
}
if (nbytesExtra)
{
unsigned char buf[32];
(*haraka256Function)(buf, psrc);
memcpy(pkey, buf, nbytesExtra);
}
pdesc->seed = *((uint256 *)seedBytes32);
memcpy(key + size, key, refreshsize);
}
else
{
memcpy(key, key + size, refreshsize);
}
memset((unsigned char *)key + (size + refreshsize), 0, size - refreshsize);
return (u128 *)key;
}
inline uint64_t IntermediateTo128Offset(uint64_t intermediate)
{
// the mask is where we wrap
uint64_t mask = vclh.keyMask >> 4;
return intermediate & mask;
}
void Finalize2b(unsigned char hash[32])
{
// fill buffer to the end with the beginning of it to prevent any foreknowledge of
// bits that may contain zero
FillExtra((u128 *)curBuf);
#ifdef VERUSHASHDEBUG
uint256 *bhalf1 = (uint256 *)curBuf;
uint256 *bhalf2 = bhalf1 + 1;
printf("Curbuf: %s%s\n", bhalf1->GetHex().c_str(), bhalf2->GetHex().c_str());
#endif
// gen new key with what is last in buffer
u128 *key = GenNewCLKey(curBuf);
// run verusclhash on the buffer
uint64_t intermediate = vclh(curBuf, key);
// fill buffer to the end with the result
FillExtra(&intermediate);
#ifdef VERUSHASHDEBUG
printf("intermediate %lx\n", intermediate);
printf("Curbuf: %s%s\n", bhalf1->GetHex().c_str(), bhalf2->GetHex().c_str());
bhalf1 = (uint256 *)key;
bhalf2 = bhalf1 + ((vclh.keyMask + 1) >> 5);
printf(" Key: %s%s\n", bhalf1->GetHex().c_str(), bhalf2->GetHex().c_str());
#endif
// get the final hash with a mutated dynamic key for each hash result
(*haraka512KeyedFunction)(hash, curBuf, key + IntermediateTo128Offset(intermediate));
}
inline unsigned char *CurBuffer()
{
return curBuf;
}
private:
// only buf1, the first source, needs to be zero initialized
alignas(32) unsigned char buf1[64] = {0}, buf2[64];
unsigned char *curBuf = buf1, *result = buf2;
size_t curPos = 0;
};
extern void verus_hash(void *result, const void *data, size_t len);
extern void verus_hash_v2(void *result, const void *data, size_t len);
#endif