Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
litecoincash-project
GitHub Repository: litecoincash-project/cpuminer-multi
Path: blob/master/algo/minotaur.c
1299 views
1
#include <miner.h>
2
3
#include <stdlib.h>
4
#include <stdint.h>
5
#include <string.h>
6
#include <stdio.h>
7
8
#include <sha3/sph_blake.h>
9
#include <sha3/sph_bmw.h>
10
#include <sha3/sph_groestl.h>
11
#include <sha3/sph_jh.h>
12
#include <sha3/sph_keccak.h>
13
#include <sha3/sph_skein.h>
14
#include <sha3/sph_luffa.h>
15
#include <sha3/sph_cubehash.h>
16
#include <sha3/sph_shavite.h>
17
#include <sha3/sph_simd.h>
18
#include <sha3/sph_echo.h>
19
#include <sha3/sph_hamsi.h>
20
#include <sha3/sph_fugue.h>
21
#include <sha3/sph_shabal.h>
22
#include <sha3/sph_whirlpool.h>
23
#include <sha3/sph_sha2.h>
24
#include <algo/yespower/yespower.h>
25
26
// Config
27
#define MINOTAUR_ALGO_COUNT 16
28
//#define MINOTAUR_DEBUG
29
30
static const yespower_params_t yespower_params = {YESPOWER_1_0, 2048, 8, "et in arcadia ego", 17};
31
32
typedef struct TortureNode TortureNode;
33
typedef struct TortureGarden TortureGarden;
34
35
// Graph of hash algos plus SPH contexts
36
struct TortureGarden {
37
sph_blake512_context context_blake;
38
sph_bmw512_context context_bmw;
39
sph_cubehash512_context context_cubehash;
40
sph_echo512_context context_echo;
41
sph_fugue512_context context_fugue;
42
sph_groestl512_context context_groestl;
43
sph_hamsi512_context context_hamsi;
44
sph_jh512_context context_jh;
45
sph_keccak512_context context_keccak;
46
sph_luffa512_context context_luffa;
47
sph_shabal512_context context_shabal;
48
sph_shavite512_context context_shavite;
49
sph_simd512_context context_simd;
50
sph_skein512_context context_skein;
51
sph_whirlpool_context context_whirlpool;
52
sph_sha512_context context_sha2;
53
54
struct TortureNode {
55
unsigned int algo;
56
TortureNode *childLeft;
57
TortureNode *childRight;
58
} nodes[22];
59
};
60
61
// Get a 64-byte hash for given 64-byte input, using given TortureGarden contexts and given algo index
62
void get_hash(void *output, const void *input, TortureGarden *garden, unsigned int algo)
63
{
64
unsigned char _ALIGN(64) hash[64];
65
memset(hash, 0, sizeof(hash)); // Doesn't affect Minotaur as all hash outputs are 64 bytes; required for MinotaurX due to yespower's 32 byte output.
66
67
switch (algo) {
68
case 0:
69
sph_blake512_init(&garden->context_blake);
70
sph_blake512(&garden->context_blake, input, 64);
71
sph_blake512_close(&garden->context_blake, hash);
72
break;
73
case 1:
74
sph_bmw512_init(&garden->context_bmw);
75
sph_bmw512(&garden->context_bmw, input, 64);
76
sph_bmw512_close(&garden->context_bmw, hash);
77
break;
78
case 2:
79
sph_cubehash512_init(&garden->context_cubehash);
80
sph_cubehash512(&garden->context_cubehash, input, 64);
81
sph_cubehash512_close(&garden->context_cubehash, hash);
82
break;
83
case 3:
84
sph_echo512_init(&garden->context_echo);
85
sph_echo512(&garden->context_echo, input, 64);
86
sph_echo512_close(&garden->context_echo, hash);
87
break;
88
case 4:
89
sph_fugue512_init(&garden->context_fugue);
90
sph_fugue512(&garden->context_fugue, input, 64);
91
sph_fugue512_close(&garden->context_fugue, hash);
92
break;
93
case 5:
94
sph_groestl512_init(&garden->context_groestl);
95
sph_groestl512(&garden->context_groestl, input, 64);
96
sph_groestl512_close(&garden->context_groestl, hash);
97
break;
98
case 6:
99
sph_hamsi512_init(&garden->context_hamsi);
100
sph_hamsi512(&garden->context_hamsi, input, 64);
101
sph_hamsi512_close(&garden->context_hamsi, hash);
102
break;
103
case 7:
104
sph_sha512_init(&garden->context_sha2);
105
sph_sha512(&garden->context_sha2, input, 64);
106
sph_sha512_close(&garden->context_sha2, hash);
107
break;
108
case 8:
109
sph_jh512_init(&garden->context_jh);
110
sph_jh512(&garden->context_jh, input, 64);
111
sph_jh512_close(&garden->context_jh, hash);
112
break;
113
case 9:
114
sph_keccak512_init(&garden->context_keccak);
115
sph_keccak512(&garden->context_keccak, input, 64);
116
sph_keccak512_close(&garden->context_keccak, hash);
117
break;
118
case 10:
119
sph_luffa512_init(&garden->context_luffa);
120
sph_luffa512(&garden->context_luffa, input, 64);
121
sph_luffa512_close(&garden->context_luffa, hash);
122
break;
123
case 11:
124
sph_shabal512_init(&garden->context_shabal);
125
sph_shabal512(&garden->context_shabal, input, 64);
126
sph_shabal512_close(&garden->context_shabal, hash);
127
break;
128
case 12:
129
sph_shavite512_init(&garden->context_shavite);
130
sph_shavite512(&garden->context_shavite, input, 64);
131
sph_shavite512_close(&garden->context_shavite, hash);
132
break;
133
case 13:
134
sph_simd512_init(&garden->context_simd);
135
sph_simd512(&garden->context_simd, input, 64);
136
sph_simd512_close(&garden->context_simd, hash);
137
break;
138
case 14:
139
sph_skein512_init(&garden->context_skein);
140
sph_skein512(&garden->context_skein, input, 64);
141
sph_skein512_close(&garden->context_skein, hash);
142
break;
143
case 15:
144
sph_whirlpool_init(&garden->context_whirlpool);
145
sph_whirlpool(&garden->context_whirlpool, input, 64);
146
sph_whirlpool_close(&garden->context_whirlpool, hash);
147
break;
148
// NB: The CPU-hard gate must be case MINOTAUR_ALGO_COUNT.
149
case 16:
150
yespower_tls(input, 64, &yespower_params, (yespower_binary_t*)hash);
151
}
152
153
// Output the hash
154
memcpy(output, hash, 64);
155
}
156
157
// Recursively traverse a given torture garden starting with a given hash and given node within the garden. The hash is overwritten with the final hash.
158
void traverse_garden(TortureGarden *garden, void *hash, TortureNode *node)
159
{
160
unsigned char _ALIGN(64) partialHash[64];
161
memset(partialHash, 0, sizeof(partialHash)); // Doesn't affect Minotaur as all hash outputs are 64 bytes; required for MinotaurX due to yespower's 32 byte output.
162
get_hash(partialHash, hash, garden, node->algo);
163
164
#ifdef MINOTAUR_DEBUG
165
printf("* Ran algo %d. Partial hash:\t", node->algo);
166
for (int i = 63; i >= 0; i--) printf("%02x", partialHash[i]);
167
printf("\n");
168
fflush(0);
169
#endif
170
171
if (partialHash[63] % 2 == 0) { // Last byte of output hash is even
172
if (node->childLeft != NULL)
173
traverse_garden(garden, partialHash, node->childLeft);
174
} else { // Last byte of output hash is odd
175
if (node->childRight != NULL)
176
traverse_garden(garden, partialHash, node->childRight);
177
}
178
179
memcpy(hash, partialHash, 64);
180
}
181
182
// Associate child nodes with a parent node
183
inline void link_nodes(TortureNode *parent, TortureNode *childLeft, TortureNode *childRight)
184
{
185
parent->childLeft = childLeft;
186
parent->childRight = childRight;
187
}
188
189
// Produce a 32-byte hash from 80-byte input data
190
void minotaurhash(void *output, const void *input, bool minotaurX)
191
{
192
// Create torture garden nodes. Note that both sides of 19 and 20 lead to 21, and 21 has no children (to make traversal complete).
193
// The successful path through the garden visits 7 nodes.
194
TortureGarden garden;
195
link_nodes(&garden.nodes[0], &garden.nodes[1], &garden.nodes[2]);
196
link_nodes(&garden.nodes[1], &garden.nodes[3], &garden.nodes[4]);
197
link_nodes(&garden.nodes[2], &garden.nodes[5], &garden.nodes[6]);
198
link_nodes(&garden.nodes[3], &garden.nodes[7], &garden.nodes[8]);
199
link_nodes(&garden.nodes[4], &garden.nodes[9], &garden.nodes[10]);
200
link_nodes(&garden.nodes[5], &garden.nodes[11], &garden.nodes[12]);
201
link_nodes(&garden.nodes[6], &garden.nodes[13], &garden.nodes[14]);
202
link_nodes(&garden.nodes[7], &garden.nodes[15], &garden.nodes[16]);
203
link_nodes(&garden.nodes[8], &garden.nodes[15], &garden.nodes[16]);
204
link_nodes(&garden.nodes[9], &garden.nodes[15], &garden.nodes[16]);
205
link_nodes(&garden.nodes[10], &garden.nodes[15], &garden.nodes[16]);
206
link_nodes(&garden.nodes[11], &garden.nodes[17], &garden.nodes[18]);
207
link_nodes(&garden.nodes[12], &garden.nodes[17], &garden.nodes[18]);
208
link_nodes(&garden.nodes[13], &garden.nodes[17], &garden.nodes[18]);
209
link_nodes(&garden.nodes[14], &garden.nodes[17], &garden.nodes[18]);
210
link_nodes(&garden.nodes[15], &garden.nodes[19], &garden.nodes[20]);
211
link_nodes(&garden.nodes[16], &garden.nodes[19], &garden.nodes[20]);
212
link_nodes(&garden.nodes[17], &garden.nodes[19], &garden.nodes[20]);
213
link_nodes(&garden.nodes[18], &garden.nodes[19], &garden.nodes[20]);
214
link_nodes(&garden.nodes[19], &garden.nodes[21], &garden.nodes[21]);
215
link_nodes(&garden.nodes[20], &garden.nodes[21], &garden.nodes[21]);
216
garden.nodes[21].childLeft = NULL;
217
garden.nodes[21].childRight = NULL;
218
219
// Find initial sha512 hash
220
unsigned char _ALIGN(64) hash[64];
221
sph_sha512_init(&garden.context_sha2);
222
sph_sha512(&garden.context_sha2, input, 80);
223
sph_sha512_close(&garden.context_sha2, hash);
224
225
#ifdef MINOTAUR_DEBUG
226
printf("** Initial hash:\t\t");
227
for (int i = 63; i >= 0; i--) printf("%02x", hash[i]);
228
printf("\n");
229
fflush(0);
230
#endif
231
232
// Assign algos to torture garden nodes based on initial hash
233
for (int i = 0; i < 22; i++)
234
garden.nodes[i].algo = hash[i] % MINOTAUR_ALGO_COUNT;
235
236
// Hardened garden gates on MinotaurX
237
if (minotaurX)
238
garden.nodes[21].algo = MINOTAUR_ALGO_COUNT;
239
240
// Send the initial hash through the torture garden
241
traverse_garden(&garden, hash, &garden.nodes[0]);
242
243
// Truncate the result to 32 bytes
244
memcpy(output, hash, 32);
245
246
#ifdef MINOTAUR_DEBUG
247
printf("** Final hash:\t\t\t");
248
for (int i = 31; i >= 0; i--) printf("%02x", hash[i]);
249
printf("\n");
250
fflush(0);
251
#endif
252
}
253
254
// Scan driver
255
int scanhash_minotaur(int thr_id, struct work *work, uint32_t max_nonce, uint64_t *hashes_done, bool minotaurX)
256
{
257
uint32_t _ALIGN(64) hash[8];
258
uint32_t _ALIGN(64) endiandata[20];
259
uint32_t *pdata = work->data;
260
uint32_t *ptarget = work->target;
261
262
const uint32_t Htarg = ptarget[7];
263
const uint32_t first_nonce = pdata[19];
264
uint32_t nonce = first_nonce;
265
volatile uint8_t *restart = &(work_restart[thr_id].restart);
266
267
if (opt_benchmark)
268
ptarget[7] = 0x0cff;
269
270
for (int k=0; k < 19; k++)
271
be32enc(&endiandata[k], pdata[k]);
272
273
do {
274
be32enc(&endiandata[19], nonce);
275
minotaurhash(hash, endiandata, minotaurX);
276
277
if (hash[7] <= Htarg && fulltest(hash, ptarget)) {
278
work_set_target_ratio(work, hash);
279
pdata[19] = nonce;
280
*hashes_done = pdata[19] - first_nonce;
281
return 1;
282
}
283
nonce++;
284
285
} while (nonce < max_nonce && !(*restart));
286
287
pdata[19] = nonce;
288
*hashes_done = pdata[19] - first_nonce + 1;
289
return 0;
290
}
291
292