Rename ScanMidstateWorker to KernelWorker, move kernel scanning to separate module.
[novacoin.git] / src / kernel_worker.cpp
1 #include <vector>
2 #include <inttypes.h>
3
4 #include "uint256.h"
5 #include "bignum.h"
6 #include "kernel.h"
7 #include "kernel_worker.h"
8
9 using namespace std;
10
11 #ifdef USE_ASM
12
13 #if defined(__i386__) || defined(__x86_64__)
14 #include <immintrin.h>
15 #endif
16
17 #ifndef __i386__
18 // kernel padding
19 static const uint32_t block1_suffix[9] = { 0x80000000, 0, 0, 0, 0, 0, 0, 0, 0x000000e0 };
20 // hash padding
21 static const uint32_t block2_suffix[8] = { 0x80000000, 0, 0, 0, 0, 0, 0, 0x00000100 };
22
23 // Sha256 initial state
24 static const uint32_t sha256_initial[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 };
25
26 extern "C" void sha256_transform(uint32_t *state, const uint32_t *block, int swap);
27 #endif
28
29 // 4-way kernel padding
30 static const uint32_t block1_suffix_4way[4 * 9] = {
31     0x80000000, 0x80000000, 0x80000000, 0x80000000,
32     0, 0, 0, 0,
33     0, 0, 0, 0,
34     0, 0, 0, 0,
35     0, 0, 0, 0,
36     0, 0, 0, 0,
37     0, 0, 0, 0,
38     0, 0, 0, 0,
39     0x000000e0, 0x000000e0, 0x000000e0, 0x000000e0
40 };
41
42 // 4-way hash padding
43 static const uint32_t block2_suffix_4way[4 * 8] = {
44     0x80000000, 0x80000000, 0x80000000, 0x80000000,
45     0, 0, 0, 0,
46     0, 0, 0, 0,
47     0, 0, 0, 0,
48     0, 0, 0, 0,
49     0, 0, 0, 0,
50     0, 0, 0, 0,
51     0x00000100, 0x00000100, 0x00000100, 0x00000100
52 };
53
54 extern "C" int sha256_use_4way();
55 extern "C" void sha256_init_4way(uint32_t *state);
56 extern "C" void sha256_transform_4way(uint32_t *state, const uint32_t *block, int swap);
57 bool fUse4Way = sha256_use_4way() != 0;
58
59 #ifdef __x86_64__
60 // 8-way kernel padding
61 static const uint32_t block1_suffix_8way[8 * 9] = {
62     0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000,
63     0, 0, 0, 0, 0, 0, 0, 0,
64     0, 0, 0, 0, 0, 0, 0, 0,
65     0, 0, 0, 0, 0, 0, 0, 0,
66     0, 0, 0, 0, 0, 0, 0, 0,
67     0, 0, 0, 0, 0, 0, 0, 0,
68     0, 0, 0, 0, 0, 0, 0, 0,
69     0, 0, 0, 0, 0, 0, 0, 0,
70     0x000000e0, 0x000000e0, 0x000000e0, 0x000000e0, 0x000000e0, 0x000000e0, 0x000000e0, 0x000000e0
71 };
72
73 // 8-way hash padding
74 static const uint32_t block2_suffix_8way[8 * 8] = {
75     0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000,
76     0, 0, 0, 0, 0, 0, 0, 0,
77     0, 0, 0, 0, 0, 0, 0, 0,
78     0, 0, 0, 0, 0, 0, 0, 0,
79     0, 0, 0, 0, 0, 0, 0, 0,
80     0, 0, 0, 0, 0, 0, 0, 0,
81     0, 0, 0, 0, 0, 0, 0, 0,
82     0x000000e0, 0x000000e0, 0x000000e0, 0x000000e0, 0x000000e0, 0x000000e0, 0x000000e0, 0x000000e0
83 };
84
85 extern "C" int sha256_use_8way();
86 extern "C" void sha256_init_8way(uint32_t *state);
87 extern "C" void sha256_transform_8way(uint32_t *state, const uint32_t *block, int swap);
88 bool fUse8Way = sha256_use_8way() != 0;
89
90 inline void copyrow8_swap32(uint32_t *to, uint32_t *from)
91 {
92     // There are no AVX2 CPUs without SSSE3 support, so we don't need any conditions here.
93     __m128i mask = _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3);
94     _mm_storeu_si128((__m128i *)&to[0], _mm_shuffle_epi8(_mm_loadu_si128((__m128i *)&from[0]), mask));
95     _mm_storeu_si128((__m128i *)&to[4], _mm_shuffle_epi8(_mm_loadu_si128((__m128i *)&from[4]), mask));
96 }
97 #endif
98
99 #if defined(__i386__) || defined(__x86_64__)
100 extern "C" int sha256_use_ssse3();
101 bool fUseSSSE3 = sha256_use_ssse3() != 0;
102
103 inline void copyrow4_swap32(uint32_t *to, uint32_t *from)
104 {
105     if (!fUseSSSE3)
106     {
107         for (int i = 0; i < 4; i++)
108             to[i] = __builtin_bswap32(from[i]);
109     }
110     else
111     {
112         __m128i mask = _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3);
113         _mm_storeu_si128((__m128i *)&to[0], _mm_shuffle_epi8(_mm_loadu_si128((__m128i *)&from[0]), mask));
114     }
115 }
116 #else
117 inline void copyrow4_swap32(uint32_t *to, uint32_t *from)
118 {
119     for (int i = 0; i < 4; i++)
120         to[i] = __builtin_bswap32(from[i]);
121 }
122 #endif
123 #endif
124
125 KernelWorker::KernelWorker(unsigned char *kernel, uint32_t nBits, uint32_t nInputTxTime, int64_t nValueIn, uint32_t nIntervalBegin, uint32_t nIntervalEnd) 
126         : kernel(kernel), nBits(nBits), nInputTxTime(nInputTxTime), bnValueIn(nValueIn), nIntervalBegin(nIntervalBegin), nIntervalEnd(nIntervalEnd)
127     {
128         solutions = vector<std::pair<uint256,uint32_t> >();
129     }
130
131 #ifdef USE_ASM
132 #ifdef __x86_64__
133 void KernelWorker::Do_8way()
134 {
135     SetThreadPriority(THREAD_PRIORITY_LOWEST);
136
137     // Compute maximum possible target to filter out majority of obviously insufficient hashes
138     CBigNum bnTargetPerCoinDay;
139     bnTargetPerCoinDay.SetCompact(nBits);
140     uint256 nMaxTarget = (bnTargetPerCoinDay * bnValueIn * nStakeMaxAge / COIN / nOneDay).getuint256();
141
142     uint32_t blocks1[8 * 16] __attribute__((aligned(16)));
143     uint32_t blocks2[8 * 16] __attribute__((aligned(16)));
144     uint32_t candidates[8 * 8] __attribute__((aligned(16)));
145
146     vector<uint32_t> vRow = vector<uint32_t>(8);
147     uint32_t *pnKernel = (uint32_t *) kernel;
148
149     for(int i = 0; i < 7; i++)
150     {
151         fill(vRow.begin(), vRow.end(), pnKernel[i]);
152         copyrow8_swap32(&blocks1[i*8], &vRow[0]);
153     }
154
155     memcpy(&blocks1[56], &block1_suffix_8way[0], 36*8);   // sha256 padding
156     memcpy(&blocks2[64], &block2_suffix_8way[0], 32*8);
157
158     uint32_t nHashes[8];
159     uint32_t nTimeStamps[8];
160
161     // Search forward in time from the given timestamp
162     // Stopping search in case of shutting down
163     for (uint32_t nTimeTx=nIntervalBegin, nMaxTarget32 = nMaxTarget.Get32(7); nTimeTx<nIntervalEnd && !fShutdown; nTimeTx +=8)
164     {
165         sha256_init_8way(blocks2);
166         sha256_init_8way(candidates);
167
168         nTimeStamps[0] = nTimeTx;
169         nTimeStamps[1] = nTimeTx+1;
170         nTimeStamps[2] = nTimeTx+2;
171         nTimeStamps[3] = nTimeTx+3;
172         nTimeStamps[4] = nTimeTx+4;
173         nTimeStamps[5] = nTimeTx+5;
174         nTimeStamps[6] = nTimeTx+6;
175         nTimeStamps[7] = nTimeTx+7;
176
177         copyrow8_swap32(&blocks1[24], &nTimeStamps[0]); // Kernel timestamps
178         sha256_transform_8way(&blocks2[0], &blocks1[0], 0); // first hashing
179         sha256_transform_8way(&candidates[0], &blocks2[0], 0); // second hashing
180         copyrow8_swap32(&nHashes[0], &candidates[56]);
181
182         for(int nResult = 0; nResult < 8; nResult++)
183         {
184             if (nHashes[nResult] <= nMaxTarget32) // Possible hit
185             {
186                 uint256 nHashProofOfStake = 0;
187                 uint32_t *pnHashProofOfStake = (uint32_t *) &nHashProofOfStake;
188
189                 for (int i = 0; i < 7; i++)
190                     pnHashProofOfStake[i] = __builtin_bswap32(candidates[(i*8) + nResult]);
191                 pnHashProofOfStake[7] = nHashes[nResult];
192
193                 CBigNum bnCoinDayWeight = bnValueIn * GetWeight((int64_t)nInputTxTime, (int64_t)nTimeStamps[nResult]) / COIN / nOneDay;
194                 CBigNum bnTargetProofOfStake = bnCoinDayWeight * bnTargetPerCoinDay;
195
196                 if (bnTargetProofOfStake >= CBigNum(nHashProofOfStake))
197                     solutions.push_back(std::pair<uint256,uint32_t>(nHashProofOfStake, nTimeStamps[nResult]));
198             }
199         }
200     }
201 }
202 #endif
203
204 void KernelWorker::Do_4way()
205 {
206     SetThreadPriority(THREAD_PRIORITY_LOWEST);
207
208     // Compute maximum possible target to filter out majority of obviously insufficient hashes
209     CBigNum bnTargetPerCoinDay;
210     bnTargetPerCoinDay.SetCompact(nBits);
211     uint256 nMaxTarget = (bnTargetPerCoinDay * bnValueIn * nStakeMaxAge / COIN / nOneDay).getuint256();
212
213     uint32_t blocks1[4 * 16] __attribute__((aligned(16)));
214     uint32_t blocks2[4 * 16] __attribute__((aligned(16)));
215     uint32_t candidates[4 * 8] __attribute__((aligned(16)));
216
217     vector<uint32_t> vRow = vector<uint32_t>(4);
218     uint32_t *pnKernel = (uint32_t *) kernel;
219
220     for(int i = 0; i < 7; i++)
221     {
222         fill(vRow.begin(), vRow.end(), pnKernel[i]);
223         copyrow4_swap32(&blocks1[i*4], &vRow[0]);
224     }
225
226     memcpy(&blocks1[28], &block1_suffix_4way[0], 36*4);   // sha256 padding
227     memcpy(&blocks2[32], &block2_suffix_4way[0], 32*4);
228
229     uint32_t nHashes[4];
230     uint32_t nTimeStamps[4];
231
232     // Search forward in time from the given timestamp
233     // Stopping search in case of shutting down
234     for (uint32_t nTimeTx=nIntervalBegin, nMaxTarget32 = nMaxTarget.Get32(7); nTimeTx<nIntervalEnd && !fShutdown; nTimeTx +=4)
235     {
236         sha256_init_4way(blocks2);
237         sha256_init_4way(candidates);
238
239         nTimeStamps[0] = nTimeTx;
240         nTimeStamps[1] = nTimeTx+1;
241         nTimeStamps[2] = nTimeTx+2;
242         nTimeStamps[3] = nTimeTx+3;
243
244         copyrow4_swap32(&blocks1[24], &nTimeStamps[0]); // Kernel timestamps
245         sha256_transform_4way(&blocks2[0], &blocks1[0], 0); // first hashing
246         sha256_transform_4way(&candidates[0], &blocks2[0], 0); // second hashing
247         copyrow4_swap32(&nHashes[0], &candidates[28]);
248
249         for(int nResult = 0; nResult < 4; nResult++)
250         {
251             if (nHashes[nResult] <= nMaxTarget32) // Possible hit
252             {
253                 uint256 nHashProofOfStake = 0;
254                 uint32_t *pnHashProofOfStake = (uint32_t *) &nHashProofOfStake;
255
256                 for (int i = 0; i < 7; i++)
257                     pnHashProofOfStake[i] = __builtin_bswap32(candidates[(i*4) + nResult]);
258                 pnHashProofOfStake[7] = nHashes[nResult];
259
260                 CBigNum bnCoinDayWeight = bnValueIn * GetWeight((int64_t)nInputTxTime, (int64_t)nTimeStamps[nResult]) / COIN / nOneDay;
261                 CBigNum bnTargetProofOfStake = bnCoinDayWeight * bnTargetPerCoinDay;
262
263                 if (bnTargetProofOfStake >= CBigNum(nHashProofOfStake))
264                     solutions.push_back(std::pair<uint256,uint32_t>(nHashProofOfStake, nTimeStamps[nResult]));
265             }
266         }
267     }
268 }
269 #endif
270
271 void KernelWorker::Do_generic()
272 {
273     SetThreadPriority(THREAD_PRIORITY_LOWEST);
274
275     // Compute maximum possible target to filter out majority of obviously insufficient hashes
276     CBigNum bnTargetPerCoinDay;
277     bnTargetPerCoinDay.SetCompact(nBits);
278     uint256 nMaxTarget = (bnTargetPerCoinDay * bnValueIn * nStakeMaxAge / COIN / nOneDay).getuint256();
279
280 #if !defined(USE_ASM) || defined(__i386__)
281     SHA256_CTX ctx, workerCtx;
282     // Init new sha256 context and update it
283     //   with first 24 bytes of kernel
284     SHA256_Init(&ctx);
285     SHA256_Update(&ctx, kernel, 8 + 16);
286     workerCtx = ctx; // save context
287
288     // Sha256 result buffer
289     uint32_t hashProofOfStake[8];
290     uint256 *pnHashProofOfStake = (uint256 *)&hashProofOfStake;
291
292     // Search forward in time from the given timestamp
293     // Stopping search in case of shutting down
294     for (uint32_t nTimeTx=nIntervalBegin, nMaxTarget32 = nMaxTarget.Get32(7); nTimeTx<nIntervalEnd && !fShutdown; nTimeTx++)
295     {
296         // Complete first hashing iteration
297         uint256 hash1;
298         SHA256_Update(&ctx, (unsigned char*)&nTimeTx, 4);
299         SHA256_Final((unsigned char*)&hash1, &ctx);
300
301         // Restore context
302         ctx = workerCtx;
303
304         // Finally, calculate kernel hash
305         SHA256((unsigned char*)&hash1, sizeof(hashProofOfStake), (unsigned char*)&hashProofOfStake);
306
307         // Skip if hash doesn't satisfy the maximum target
308         if (hashProofOfStake[7] > nMaxTarget32)
309             continue;
310
311         CBigNum bnCoinDayWeight = bnValueIn * GetWeight((int64_t)nInputTxTime, (int64_t)nTimeTx) / COIN / nOneDay;
312         CBigNum bnTargetProofOfStake = bnCoinDayWeight * bnTargetPerCoinDay;
313
314         if (bnTargetProofOfStake >= CBigNum(*pnHashProofOfStake))
315             solutions.push_back(std::pair<uint256,uint32_t>(*pnHashProofOfStake, nTimeTx));
316     }
317 #else
318     uint32_t block1[16] __attribute__((aligned(16)));
319     uint32_t block2[16] __attribute__((aligned(16)));
320     uint32_t candidate[8] __attribute__((aligned(16)));
321
322     memcpy(&block1[7], &block1_suffix[0], 36);   // sha256 padding
323     memcpy(&block2[8], &block2_suffix[0], 32);
324
325     uint32_t *pnKernel = (uint32_t *) kernel;
326
327     for (int i = 0; i < 6; i++)
328         block1[i] = __builtin_bswap32(pnKernel[i]);
329
330     // Search forward in time from the given timestamp
331     // Stopping search in case of shutting down
332     for (uint32_t nTimeTx=nIntervalBegin, nMaxTarget32 = nMaxTarget.Get32(7); nTimeTx<nIntervalEnd && !fShutdown; nTimeTx++)
333     {
334         memcpy(&block2[0], &sha256_initial[0], 32);
335         memcpy(&candidate[0], &sha256_initial[0], 32);
336
337         block1[6] = __builtin_bswap32(nTimeTx);
338
339         sha256_transform(&block2[0], &block1[0], 0); // first hashing
340         sha256_transform(&candidate[0], &block2[0], 0); // second hashing
341
342         uint32_t nHash7 = __builtin_bswap32(candidate[7]);
343
344         // Skip if hash doesn't satisfy the maximum target
345         if (nHash7 > nMaxTarget32)
346             continue;
347
348         uint256 nHashProofOfStake;
349         uint32_t *pnHashProofOfStake = (uint32_t *) &nHashProofOfStake;
350
351         for (int i = 0; i < 7; i++)
352             pnHashProofOfStake[i] = __builtin_bswap32(candidate[i]);
353         pnHashProofOfStake[7] = nHash7;
354
355         CBigNum bnCoinDayWeight = bnValueIn * GetWeight((int64_t)nInputTxTime, (int64_t)nTimeTx) / COIN / nOneDay;
356         CBigNum bnTargetProofOfStake = bnCoinDayWeight * bnTargetPerCoinDay;
357
358         if (bnTargetProofOfStake >= CBigNum(nHashProofOfStake))
359             solutions.push_back(std::pair<uint256,uint32_t>(nHashProofOfStake, nTimeTx));
360     }
361 #endif
362 }
363
364 void KernelWorker::Do()
365 {
366 #ifdef USE_ASM
367 #ifdef __x86_64__
368     if (false && fUse8Way) // disable for now
369     {
370         Do_8way();
371         return;
372     }
373 #endif
374     if (fUse4Way)
375     {
376         Do_4way();
377         return;
378     }
379 #endif
380
381     Do_generic();
382 }
383
384 vector<pair<uint256,uint32_t> >& KernelWorker::GetSolutions()
385 {
386     return solutions;
387 }
388