]> Git Repo - VerusCoin.git/blob - src/crypto/verus_hash.h
Try thread_local instead of boost::thread_specific_ptr
[VerusCoin.git] / src / crypto / verus_hash.h
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
4 \r
5 /*\r
6 This provides the PoW hash function for Verus, enabling CPU mining.\r
7 */\r
8 #ifndef VERUS_HASH_H_\r
9 #define VERUS_HASH_H_\r
10 \r
11 // verbose output when defined\r
12 //#define VERUSHASHDEBUG 1\r
13 \r
14 #include <cstring>\r
15 #include <vector>\r
16 \r
17 #include "uint256.h"\r
18 #include "crypto/verus_clhash.h"\r
19 \r
20 extern "C" \r
21 {\r
22 #include "crypto/haraka.h"\r
23 #include "crypto/haraka_portable.h"\r
24 }\r
25 \r
26 class CVerusHash\r
27 {\r
28     public:\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
31 \r
32         static void init();\r
33 \r
34         CVerusHash() { }\r
35 \r
36         CVerusHash &Write(const unsigned char *data, size_t len);\r
37 \r
38         CVerusHash &Reset()\r
39         {\r
40             curBuf = buf1;\r
41             result = buf2;\r
42             curPos = 0;\r
43             std::fill(buf1, buf1 + sizeof(buf1), 0);\r
44             return *this;\r
45         }\r
46 \r
47         int64_t *ExtraI64Ptr() { return (int64_t *)(curBuf + 32); }\r
48         void ClearExtra()\r
49         {\r
50             if (curPos)\r
51             {\r
52                 std::fill(curBuf + 32 + curPos, curBuf + 64, 0);\r
53             }\r
54         }\r
55         void ExtraHash(unsigned char hash[32]) { (*haraka512Function)(hash, curBuf); }\r
56 \r
57         void Finalize(unsigned char hash[32])\r
58         {\r
59             if (curPos)\r
60             {\r
61                 std::fill(curBuf + 32 + curPos, curBuf + 64, 0);\r
62                 (*haraka512Function)(hash, curBuf);\r
63             }\r
64             else\r
65                 std::memcpy(hash, curBuf, 32);\r
66         }\r
67 \r
68     private:\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
72         size_t curPos = 0;\r
73 };\r
74 \r
75 class CVerusHashV2\r
76 {\r
77     public:\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
82 \r
83         static void init();\r
84 \r
85         verusclhasher vclh;\r
86 \r
87         CVerusHashV2() : vclh() {\r
88             // we must have allocated key space, or can't run\r
89             if (!verusclhasher_key.get())\r
90             {\r
91                 printf("ERROR: failed to allocate hash buffer - terminating\n");\r
92                 assert(false);\r
93             }\r
94         }\r
95 \r
96         CVerusHashV2 &Write(const unsigned char *data, size_t len);\r
97 \r
98         CVerusHashV2 &Reset()\r
99         {\r
100             curBuf = buf1;\r
101             result = buf2;\r
102             curPos = 0;\r
103             std::fill(buf1, buf1 + sizeof(buf1), 0);\r
104             return *this;\r
105         }\r
106 \r
107         inline int64_t *ExtraI64Ptr() { return (int64_t *)(curBuf + 32); }\r
108         inline void ClearExtra()\r
109         {\r
110             if (curPos)\r
111             {\r
112                 std::fill(curBuf + 32 + curPos, curBuf + 64, 0);\r
113             }\r
114         }\r
115 \r
116         template <typename T>\r
117         void FillExtra(const T *_data)\r
118         {\r
119             unsigned char *data = (unsigned char *)_data;\r
120             int pos = curPos;\r
121             int left = 32 - pos;\r
122             do\r
123             {\r
124                 int len = left > sizeof(T) ? sizeof(T) : left;\r
125                 std::memcpy(curBuf + 32 + pos, data, len);\r
126                 pos += len;\r
127                 left -= len;\r
128             } while (left > 0);\r
129         }\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
132 \r
133         void Finalize(unsigned char hash[32])\r
134         {\r
135             if (curPos)\r
136             {\r
137                 std::fill(curBuf + 32 + curPos, curBuf + 64, 0);\r
138                 (*haraka512Function)(hash, curBuf);\r
139             }\r
140             else\r
141                 std::memcpy(hash, curBuf, 32);\r
142         }\r
143 \r
144         // chains Haraka256 from 32 bytes to fill the key\r
145         u128 *GenNewCLKey(unsigned char *seedBytes32)\r
146         {\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
151             {\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
158                 {\r
159                     (*haraka256Function)(pkey, psrc);\r
160                     psrc = pkey;\r
161                     pkey += 32;\r
162                 }\r
163                 if (nbytesExtra)\r
164                 {\r
165                     unsigned char buf[32];\r
166                     (*haraka256Function)(buf, psrc);\r
167                     memcpy(pkey, buf, nbytesExtra);\r
168                 }\r
169                 pdesc->seed = *((uint256 *)seedBytes32);\r
170             }\r
171             memcpy(key, key + pdesc->keySizeInBytes, pdesc->keySizeInBytes);\r
172 \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
177 #endif\r
178             return (u128 *)key;\r
179         }\r
180 \r
181         inline uint64_t IntermediateTo128Offset(uint64_t intermediate)\r
182         {\r
183             // the mask is where we wrap\r
184             uint64_t mask = vclh.keyMask >> 4;\r
185             return intermediate & mask;\r
186         }\r
187 \r
188         void Finalize2b(unsigned char hash[32])\r
189         {\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
193 \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
198 #endif\r
199 \r
200             // gen new key with what is last in buffer\r
201             u128 *key = GenNewCLKey(curBuf);\r
202 \r
203             // run verusclhash on the buffer\r
204             uint64_t intermediate = vclh(curBuf, key);\r
205 \r
206             // fill buffer to the end with the result\r
207             FillExtra(&intermediate);\r
208 \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
215 #endif\r
216 \r
217             // get the final hash with a mutated dynamic key for each hash result\r
218             (*haraka512KeyedFunction)(hash, curBuf, key + IntermediateTo128Offset(intermediate));\r
219 \r
220             /*\r
221             // TEST BEGIN\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
227             FillExtra(&temp);\r
228             haraka512_keyed((unsigned char *)&testHash2, curBuf, hashKey + IntermediateTo128Offset(intermediate));\r
229             if (testHash1 != testHash2)\r
230             {\r
231                 printf("Portable version failed! intermediate1: %lx, intermediate2: %lx\n", intermediate, temp);\r
232             }\r
233             // END TEST\r
234             */\r
235         }\r
236 \r
237         inline unsigned char *CurBuffer()\r
238         {\r
239             return curBuf;\r
240         }\r
241 \r
242     private:\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
246         size_t curPos = 0;\r
247 };\r
248 \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
251 \r
252 #endif\r
This page took 0.039443 seconds and 4 git commands to generate.