1 // (C) 2018 Michael Toutonghi
\r
2 // Distributed under the MIT software license, see the accompanying
\r
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
\r
6 This provides the PoW hash function for Verus, enabling CPU mining.
\r
8 #ifndef VERUS_HASH_H_
\r
9 #define VERUS_HASH_H_
\r
11 // verbose output when defined
\r
12 //#define VERUSHASHDEBUG 1
\r
17 #include "uint256.h"
\r
18 #include "crypto/verus_clhash.h"
\r
22 #include "crypto/haraka.h"
\r
23 #include "crypto/haraka_portable.h"
\r
29 static void Hash(void *result, const void *data, size_t len);
\r
30 static void (*haraka512Function)(unsigned char *out, const unsigned char *in);
\r
36 CVerusHash &Write(const unsigned char *data, size_t len);
\r
43 std::fill(buf1, buf1 + sizeof(buf1), 0);
\r
47 int64_t *ExtraI64Ptr() { return (int64_t *)(curBuf + 32); }
\r
52 std::fill(curBuf + 32 + curPos, curBuf + 64, 0);
\r
55 void ExtraHash(unsigned char hash[32]) { (*haraka512Function)(hash, curBuf); }
\r
57 void Finalize(unsigned char hash[32])
\r
61 std::fill(curBuf + 32 + curPos, curBuf + 64, 0);
\r
62 (*haraka512Function)(hash, curBuf);
\r
65 std::memcpy(hash, curBuf, 32);
\r
69 // only buf1, the first source, needs to be zero initialized
\r
70 unsigned char buf1[64] = {0}, buf2[64];
\r
71 unsigned char *curBuf = buf1, *result = buf2;
\r
78 static void Hash(void *result, const void *data, size_t len);
\r
79 static void (*haraka512Function)(unsigned char *out, const unsigned char *in);
\r
80 static void (*haraka512KeyedFunction)(unsigned char *out, const unsigned char *in, const u128 *rc);
\r
81 static void (*haraka256Function)(unsigned char *out, const unsigned char *in);
\r
87 CVerusHashV2() : vclh() {
\r
88 // we must have allocated key space, or can't run
\r
89 if (!verusclhasher_key.get())
\r
91 printf("ERROR: failed to allocate hash buffer - terminating\n");
\r
96 CVerusHashV2 &Write(const unsigned char *data, size_t len);
\r
98 CVerusHashV2 &Reset()
\r
103 std::fill(buf1, buf1 + sizeof(buf1), 0);
\r
107 inline int64_t *ExtraI64Ptr() { return (int64_t *)(curBuf + 32); }
\r
108 inline void ClearExtra()
\r
112 std::fill(curBuf + 32 + curPos, curBuf + 64, 0);
\r
116 template <typename T>
\r
117 void FillExtra(const T *_data)
\r
119 unsigned char *data = (unsigned char *)_data;
\r
121 int left = 32 - pos;
\r
124 int len = left > sizeof(T) ? sizeof(T) : left;
\r
125 std::memcpy(curBuf + 32 + pos, data, len);
\r
128 } while (left > 0);
\r
130 inline void ExtraHash(unsigned char hash[32]) { (*haraka512Function)(hash, curBuf); }
\r
131 inline void ExtraHashKeyed(unsigned char hash[32], u128 *key) { (*haraka512KeyedFunction)(hash, curBuf, key); }
\r
133 void Finalize(unsigned char hash[32])
\r
137 std::fill(curBuf + 32 + curPos, curBuf + 64, 0);
\r
138 (*haraka512Function)(hash, curBuf);
\r
141 std::memcpy(hash, curBuf, 32);
\r
144 // chains Haraka256 from 32 bytes to fill the key
\r
145 u128 *GenNewCLKey(unsigned char *seedBytes32)
\r
147 unsigned char *key = (unsigned char *)verusclhasher_key.get();
\r
148 verusclhash_descr *pdesc = (verusclhash_descr *)verusclhasher_descr.get();
\r
149 // skip keygen if it is the current key
\r
150 if (pdesc->seed != *((uint256 *)seedBytes32))
\r
152 // generate a new key by chain hashing with Haraka256 from the last curbuf
\r
153 int n256blks = pdesc->keySizeInBytes >> 5;
\r
154 int nbytesExtra = pdesc->keySizeInBytes & 0x1f;
\r
155 unsigned char *pkey = key + pdesc->keySizeInBytes;
\r
156 unsigned char *psrc = seedBytes32;
\r
157 for (int i = 0; i < n256blks; i++)
\r
159 (*haraka256Function)(pkey, psrc);
\r
165 unsigned char buf[32];
\r
166 (*haraka256Function)(buf, psrc);
\r
167 memcpy(pkey, buf, nbytesExtra);
\r
169 pdesc->seed = *((uint256 *)seedBytes32);
\r
171 memcpy(key, key + pdesc->keySizeInBytes, pdesc->keySizeInBytes);
\r
173 #ifdef VERUSHASHDEBUG
\r
174 uint256 *bhalf1 = (uint256 *)key;
\r
175 uint256 *bhalf2 = bhalf1 + ((vclh.keyMask + 1) >> 5);
\r
176 printf("New key: %s%s\n", bhalf1->GetHex().c_str(), bhalf2->GetHex().c_str());
\r
178 return (u128 *)key;
\r
181 inline uint64_t IntermediateTo128Offset(uint64_t intermediate)
\r
183 // the mask is where we wrap
\r
184 uint64_t mask = vclh.keyMask >> 4;
\r
185 return intermediate & mask;
\r
188 void Finalize2b(unsigned char hash[32])
\r
190 // fill buffer to the end with the beginning of it to prevent any foreknowledge of
\r
191 // bits that may contain zero
\r
192 FillExtra((u128 *)curBuf);
\r
194 #ifdef VERUSHASHDEBUG
\r
195 uint256 *bhalf1 = (uint256 *)curBuf;
\r
196 uint256 *bhalf2 = bhalf1 + 1;
\r
197 printf("Curbuf: %s%s\n", bhalf1->GetHex().c_str(), bhalf2->GetHex().c_str());
\r
200 // gen new key with what is last in buffer
\r
201 u128 *key = GenNewCLKey(curBuf);
\r
203 // run verusclhash on the buffer
\r
204 uint64_t intermediate = vclh(curBuf, key);
\r
206 // fill buffer to the end with the result
\r
207 FillExtra(&intermediate);
\r
209 #ifdef VERUSHASHDEBUG
\r
210 printf("intermediate %lx\n", intermediate);
\r
211 printf("Curbuf: %s%s\n", bhalf1->GetHex().c_str(), bhalf2->GetHex().c_str());
\r
212 bhalf1 = (uint256 *)key;
\r
213 bhalf2 = bhalf1 + ((vclh.keyMask + 1) >> 5);
\r
214 printf(" Key: %s%s\n", bhalf1->GetHex().c_str(), bhalf2->GetHex().c_str());
\r
217 // get the final hash with a mutated dynamic key for each hash result
\r
218 (*haraka512KeyedFunction)(hash, curBuf, key + IntermediateTo128Offset(intermediate));
\r
222 // test against the portable version
\r
223 uint256 testHash1 = *(uint256 *)hash, testHash2;
\r
224 FillExtra((u128 *)curBuf);
\r
225 u128 *hashKey = ((u128 *)vclh.gethashkey());
\r
226 uint64_t temp = verusclhash_port(key, curBuf, vclh.keyMask);
\r
228 haraka512_keyed((unsigned char *)&testHash2, curBuf, hashKey + IntermediateTo128Offset(intermediate));
\r
229 if (testHash1 != testHash2)
\r
231 printf("Portable version failed! intermediate1: %lx, intermediate2: %lx\n", intermediate, temp);
\r
237 inline unsigned char *CurBuffer()
\r
243 // only buf1, the first source, needs to be zero initialized
\r
244 alignas(16) unsigned char buf1[64] = {0}, buf2[64];
\r
245 unsigned char *curBuf = buf1, *result = buf2;
\r
249 extern void verus_hash(void *result, const void *data, size_t len);
\r
250 extern void verus_hash_v2(void *result, const void *data, size_t len);
\r