]> Git Repo - VerusCoin.git/blame - src/crypto/equihash.cpp
Update miner tests for platform-independent Equihash
[VerusCoin.git] / src / crypto / equihash.cpp
CommitLineData
6d25662f
JG
1// Copyright (c) 2016 Jack Grigg
2// Copyright (c) 2016 The Zcash developers
3// Distributed under the MIT software license, see the accompanying
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6// Implementation of the Equihash Proof-of-Work algorithm.
7//
8// Reference
9// =========
10// Alex Biryukov and Dmitry Khovratovich
11// Equihash: Asymmetric Proof-of-Work Based on the Generalized Birthday Problem
12// NDSS ’16, 21-24 February 2016, San Diego, CA, USA
13// https://www.internetsociety.org/sites/default/files/blogs-media/equihash-asymmetric-proof-of-work-based-generalized-birthday-problem.pdf
14
15#include "crypto/equihash.h"
16#include "util.h"
17
18#include <algorithm>
6d25662f
JG
19#include <iostream>
20#include <stdexcept>
21
0a66f013
JG
22#include <boost/optional.hpp>
23
e9574728
JG
24template<unsigned int N, unsigned int K>
25int Equihash<N,K>::InitialiseState(eh_HashState& base_state)
6d25662f 26{
933cb4cd
JG
27 uint32_t n = htole32(N);
28 uint32_t k = htole32(K);
6d25662f 29 unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {};
a6dcf2ee 30 memcpy(personalization, "ZcashPoW", 8);
933cb4cd
JG
31 memcpy(personalization+8, &n, 4);
32 memcpy(personalization+12, &k, 4);
6d25662f
JG
33 return crypto_generichash_blake2b_init_salt_personal(&base_state,
34 NULL, 0, // No key.
e9574728 35 N/8,
6d25662f
JG
36 NULL, // No salt.
37 personalization);
38}
39
d07cf629 40// Big-endian so that array comparison is equivalent to integer comparison
d4d76536 41void EhIndexToArray(const eh_index i, unsigned char* array)
29d9986c
JG
42{
43 assert(sizeof(eh_index) == 4);
933cb4cd
JG
44 eh_index bei = htobe32(i);
45 memcpy(array, &bei, sizeof(eh_index));
29d9986c
JG
46}
47
d07cf629 48// Big-endian so that array comparison is equivalent to integer comparison
d4d76536 49eh_index ArrayToEhIndex(const unsigned char* array)
29d9986c
JG
50{
51 assert(sizeof(eh_index) == 4);
933cb4cd
JG
52 eh_index bei;
53 memcpy(&bei, array, sizeof(eh_index));
54 return be32toh(bei);
29d9986c
JG
55}
56
d4d76536 57eh_trunc TruncateIndex(const eh_index i, const unsigned int ilen)
c92c1f60
JG
58{
59 // Truncate to 8 bits
60 assert(sizeof(eh_trunc) == 1);
61 return (i >> (ilen - 8)) & 0xff;
62}
63
d4d76536 64eh_index UntruncateIndex(const eh_trunc t, const eh_index r, const unsigned int ilen)
c92c1f60
JG
65{
66 eh_index i{t};
67 return (i << (ilen - 8)) | r;
68}
69
d4d76536
JG
70template<size_t WIDTH>
71StepRow<WIDTH>::StepRow(unsigned int n, const eh_HashState& base_state, eh_index i)
6d25662f
JG
72{
73 eh_HashState state;
74 state = base_state;
a6dcf2ee 75 unsigned char array[sizeof(eh_index)];
933cb4cd
JG
76 eh_index lei = htole32(i);
77 memcpy(array, &lei, sizeof(eh_index));
a6dcf2ee 78 crypto_generichash_blake2b_update(&state, array, sizeof(eh_index));
6d25662f 79 crypto_generichash_blake2b_final(&state, hash, n/8);
6d25662f
JG
80}
81
d4d76536
JG
82template<size_t WIDTH> template<size_t W>
83StepRow<WIDTH>::StepRow(const StepRow<W>& a)
6d25662f 84{
d4d76536
JG
85 assert(W <= WIDTH);
86 std::copy(a.hash, a.hash+W, hash);
6d25662f
JG
87}
88
d4d76536
JG
89template<size_t WIDTH>
90FullStepRow<WIDTH>::FullStepRow(unsigned int n, const eh_HashState& base_state, eh_index i) :
91 StepRow<WIDTH> {n, base_state, i}
6d25662f 92{
d4d76536 93 EhIndexToArray(i, hash+(n/8));
6d25662f
JG
94}
95
d4d76536
JG
96template<size_t WIDTH> template<size_t W>
97FullStepRow<WIDTH>::FullStepRow(const FullStepRow<W>& a, const FullStepRow<W>& b, size_t len, size_t lenIndices, int trim) :
98 StepRow<WIDTH> {a}
a3361e77 99{
d4d76536
JG
100 assert(len+lenIndices <= W);
101 assert(len-trim+(2*lenIndices) <= WIDTH);
102 for (int i = trim; i < len; i++)
103 hash[i-trim] = a.hash[i] ^ b.hash[i];
d07cf629 104 if (a.IndicesBefore(b, len, lenIndices)) {
d4d76536
JG
105 std::copy(a.hash+len, a.hash+len+lenIndices, hash+len-trim);
106 std::copy(b.hash+len, b.hash+len+lenIndices, hash+len-trim+lenIndices);
a683cc85 107 } else {
d4d76536
JG
108 std::copy(b.hash+len, b.hash+len+lenIndices, hash+len-trim);
109 std::copy(a.hash+len, a.hash+len+lenIndices, hash+len-trim+lenIndices);
a683cc85 110 }
6d25662f
JG
111}
112
d4d76536
JG
113template<size_t WIDTH>
114FullStepRow<WIDTH>& FullStepRow<WIDTH>::operator=(const FullStepRow<WIDTH>& a)
6d25662f 115{
d4d76536 116 std::copy(a.hash, a.hash+WIDTH, hash);
a683cc85 117 return *this;
6d25662f
JG
118}
119
d4d76536
JG
120template<size_t WIDTH>
121bool StepRow<WIDTH>::IsZero(size_t len)
6d25662f 122{
447444ae
JG
123 // This doesn't need to be constant time.
124 for (int i = 0; i < len; i++) {
125 if (hash[i] != 0)
126 return false;
127 }
128 return true;
6d25662f
JG
129}
130
d4d76536
JG
131template<size_t WIDTH>
132std::vector<eh_index> FullStepRow<WIDTH>::GetIndices(size_t len, size_t lenIndices) const
29d9986c
JG
133{
134 std::vector<eh_index> ret;
135 for (int i = 0; i < lenIndices; i += sizeof(eh_index)) {
136 ret.push_back(ArrayToEhIndex(hash+len+i));
137 }
138 return ret;
139}
140
d4d76536
JG
141template<size_t WIDTH>
142bool HasCollision(StepRow<WIDTH>& a, StepRow<WIDTH>& b, int l)
6d25662f 143{
447444ae
JG
144 // This doesn't need to be constant time.
145 for (int j = 0; j < l; j++) {
146 if (a.hash[j] != b.hash[j])
147 return false;
148 }
149 return true;
6d25662f
JG
150}
151
d4d76536
JG
152template<size_t WIDTH>
153TruncatedStepRow<WIDTH>::TruncatedStepRow(unsigned int n, const eh_HashState& base_state, eh_index i, unsigned int ilen) :
154 StepRow<WIDTH> {n, base_state, i}
6d25662f 155{
d4d76536 156 hash[n/8] = TruncateIndex(i, ilen);
6d25662f
JG
157}
158
d4d76536
JG
159template<size_t WIDTH> template<size_t W>
160TruncatedStepRow<WIDTH>::TruncatedStepRow(const TruncatedStepRow<W>& a, const TruncatedStepRow<W>& b, size_t len, size_t lenIndices, int trim) :
161 StepRow<WIDTH> {a}
c92c1f60 162{
d4d76536
JG
163 assert(len+lenIndices <= W);
164 assert(len-trim+(2*lenIndices) <= WIDTH);
165 for (int i = trim; i < len; i++)
166 hash[i-trim] = a.hash[i] ^ b.hash[i];
167 if (a.IndicesBefore(b, len, lenIndices)) {
168 std::copy(a.hash+len, a.hash+len+lenIndices, hash+len-trim);
169 std::copy(b.hash+len, b.hash+len+lenIndices, hash+len-trim+lenIndices);
a683cc85 170 } else {
d4d76536
JG
171 std::copy(b.hash+len, b.hash+len+lenIndices, hash+len-trim);
172 std::copy(a.hash+len, a.hash+len+lenIndices, hash+len-trim+lenIndices);
a683cc85 173 }
c92c1f60
JG
174}
175
d4d76536
JG
176template<size_t WIDTH>
177TruncatedStepRow<WIDTH>& TruncatedStepRow<WIDTH>::operator=(const TruncatedStepRow<WIDTH>& a)
39f5cb35 178{
d4d76536 179 std::copy(a.hash, a.hash+WIDTH, hash);
a683cc85 180 return *this;
39f5cb35
JG
181}
182
d4d76536
JG
183template<size_t WIDTH>
184eh_trunc* TruncatedStepRow<WIDTH>::GetTruncatedIndices(size_t len, size_t lenIndices) const
39f5cb35 185{
39f5cb35
JG
186 eh_trunc* p = new eh_trunc[lenIndices];
187 std::copy(hash+len, hash+len+lenIndices, p);
188 return p;
189}
190
e9574728
JG
191template<unsigned int N, unsigned int K>
192std::set<std::vector<eh_index>> Equihash<N,K>::BasicSolve(const eh_HashState& base_state)
6d25662f 193{
e9574728 194 eh_index init_size { 1 << (CollisionBitLength + 1) };
6d25662f
JG
195
196 // 1) Generate first list
197 LogPrint("pow", "Generating first list\n");
639c4004 198 size_t hashLen = N/8;
d4d76536
JG
199 size_t lenIndices = sizeof(eh_index);
200 std::vector<FullStepRow<FullWidth>> X;
6d25662f
JG
201 X.reserve(init_size);
202 for (eh_index i = 0; i < init_size; i++) {
e9574728 203 X.emplace_back(N, base_state, i);
6d25662f
JG
204 }
205
206 // 3) Repeat step 2 until 2n/(k+1) bits remain
e9574728 207 for (int r = 1; r < K && X.size() > 0; r++) {
6d25662f
JG
208 LogPrint("pow", "Round %d:\n", r);
209 // 2a) Sort the list
210 LogPrint("pow", "- Sorting list\n");
639c4004 211 std::sort(X.begin(), X.end(), CompareSR(hashLen));
6d25662f
JG
212
213 LogPrint("pow", "- Finding collisions\n");
214 int i = 0;
215 int posFree = 0;
d4d76536 216 std::vector<FullStepRow<FullWidth>> Xc;
6d25662f
JG
217 while (i < X.size() - 1) {
218 // 2b) Find next set of unordered pairs with collisions on the next n/(k+1) bits
219 int j = 1;
220 while (i+j < X.size() &&
e9574728 221 HasCollision(X[i], X[i+j], CollisionByteLength)) {
6d25662f
JG
222 j++;
223 }
224
225 // 2c) Calculate tuples (X_i ^ X_j, (i, j))
226 for (int l = 0; l < j - 1; l++) {
227 for (int m = l + 1; m < j; m++) {
d4d76536
JG
228 if (DistinctIndices(X[i+l], X[i+m], hashLen, lenIndices)) {
229 Xc.emplace_back(X[i+l], X[i+m], hashLen, lenIndices, CollisionByteLength);
6d25662f
JG
230 }
231 }
232 }
233
234 // 2d) Store tuples on the table in-place if possible
235 while (posFree < i+j && Xc.size() > 0) {
236 X[posFree++] = Xc.back();
237 Xc.pop_back();
238 }
239
240 i += j;
241 }
242
243 // 2e) Handle edge case where final table entry has no collision
244 while (posFree < X.size() && Xc.size() > 0) {
245 X[posFree++] = Xc.back();
246 Xc.pop_back();
247 }
248
249 if (Xc.size() > 0) {
250 // 2f) Add overflow to end of table
251 X.insert(X.end(), Xc.begin(), Xc.end());
252 } else if (posFree < X.size()) {
253 // 2g) Remove empty space at the end
254 X.erase(X.begin()+posFree, X.end());
255 X.shrink_to_fit();
256 }
639c4004
JG
257
258 hashLen -= CollisionByteLength;
d4d76536 259 lenIndices *= 2;
6d25662f
JG
260 }
261
262 // k+1) Find a collision on last 2n(k+1) bits
263 LogPrint("pow", "Final round:\n");
264 std::set<std::vector<eh_index>> solns;
265 if (X.size() > 1) {
266 LogPrint("pow", "- Sorting list\n");
639c4004 267 std::sort(X.begin(), X.end(), CompareSR(hashLen));
6d25662f
JG
268 LogPrint("pow", "- Finding collisions\n");
269 for (int i = 0; i < X.size() - 1; i++) {
d4d76536
JG
270 FullStepRow<FinalFullWidth> res(X[i], X[i+1], hashLen, lenIndices, 0);
271 if (res.IsZero(hashLen) && DistinctIndices(X[i], X[i+1], hashLen, lenIndices)) {
272 solns.insert(res.GetIndices(hashLen, 2*lenIndices));
6d25662f
JG
273 }
274 }
275 } else
276 LogPrint("pow", "- List is empty\n");
277
278 return solns;
279}
280
d4d76536
JG
281template<size_t WIDTH>
282void CollideBranches(std::vector<FullStepRow<WIDTH>>& X, const size_t hlen, const size_t lenIndices, const unsigned int clen, const unsigned int ilen, const eh_trunc lt, const eh_trunc rt)
c92c1f60
JG
283{
284 int i = 0;
285 int posFree = 0;
d4d76536 286 std::vector<FullStepRow<WIDTH>> Xc;
c92c1f60
JG
287 while (i < X.size() - 1) {
288 // 2b) Find next set of unordered pairs with collisions on the next n/(k+1) bits
289 int j = 1;
290 while (i+j < X.size() &&
291 HasCollision(X[i], X[i+j], clen)) {
292 j++;
293 }
294
295 // 2c) Calculate tuples (X_i ^ X_j, (i, j))
296 for (int l = 0; l < j - 1; l++) {
297 for (int m = l + 1; m < j; m++) {
d4d76536
JG
298 if (DistinctIndices(X[i+l], X[i+m], hlen, lenIndices)) {
299 if (IsValidBranch(X[i+l], hlen, ilen, lt) && IsValidBranch(X[i+m], hlen, ilen, rt)) {
300 Xc.emplace_back(X[i+l], X[i+m], hlen, lenIndices, clen);
301 } else if (IsValidBranch(X[i+m], hlen, ilen, lt) && IsValidBranch(X[i+l], hlen, ilen, rt)) {
302 Xc.emplace_back(X[i+m], X[i+l], hlen, lenIndices, clen);
c92c1f60
JG
303 }
304 }
305 }
306 }
307
308 // 2d) Store tuples on the table in-place if possible
309 while (posFree < i+j && Xc.size() > 0) {
310 X[posFree++] = Xc.back();
311 Xc.pop_back();
312 }
313
314 i += j;
315 }
316
317 // 2e) Handle edge case where final table entry has no collision
318 while (posFree < X.size() && Xc.size() > 0) {
319 X[posFree++] = Xc.back();
320 Xc.pop_back();
321 }
322
323 if (Xc.size() > 0) {
324 // 2f) Add overflow to end of table
325 X.insert(X.end(), Xc.begin(), Xc.end());
326 } else if (posFree < X.size()) {
327 // 2g) Remove empty space at the end
328 X.erase(X.begin()+posFree, X.end());
329 X.shrink_to_fit();
330 }
331}
332
e9574728
JG
333template<unsigned int N, unsigned int K>
334std::set<std::vector<eh_index>> Equihash<N,K>::OptimisedSolve(const eh_HashState& base_state)
c92c1f60 335{
e9574728 336 eh_index init_size { 1 << (CollisionBitLength + 1) };
c92c1f60
JG
337
338 // First run the algorithm with truncated indices
339
e9574728 340 eh_index soln_size { 1 << K };
447444ae
JG
341 // Each element of partialSolns is dynamically allocated in a call to
342 // GetTruncatedIndices(), and freed at the end of this function.
39f5cb35 343 std::vector<eh_trunc*> partialSolns;
c92c1f60
JG
344 {
345
346 // 1) Generate first list
347 LogPrint("pow", "Generating first list\n");
639c4004 348 size_t hashLen = N/8;
d4d76536
JG
349 size_t lenIndices = sizeof(eh_trunc);
350 std::vector<TruncatedStepRow<TruncatedWidth>> Xt;
c92c1f60
JG
351 Xt.reserve(init_size);
352 for (eh_index i = 0; i < init_size; i++) {
e9574728 353 Xt.emplace_back(N, base_state, i, CollisionBitLength + 1);
c92c1f60
JG
354 }
355
356 // 3) Repeat step 2 until 2n/(k+1) bits remain
e9574728 357 for (int r = 1; r < K && Xt.size() > 0; r++) {
c92c1f60
JG
358 LogPrint("pow", "Round %d:\n", r);
359 // 2a) Sort the list
360 LogPrint("pow", "- Sorting list\n");
639c4004 361 std::sort(Xt.begin(), Xt.end(), CompareSR(hashLen));
c92c1f60
JG
362
363 LogPrint("pow", "- Finding collisions\n");
364 int i = 0;
365 int posFree = 0;
d4d76536 366 std::vector<TruncatedStepRow<TruncatedWidth>> Xc;
c92c1f60
JG
367 while (i < Xt.size() - 1) {
368 // 2b) Find next set of unordered pairs with collisions on the next n/(k+1) bits
369 int j = 1;
370 while (i+j < Xt.size() &&
e9574728 371 HasCollision(Xt[i], Xt[i+j], CollisionByteLength)) {
c92c1f60
JG
372 j++;
373 }
374
375 // 2c) Calculate tuples (X_i ^ X_j, (i, j))
376 for (int l = 0; l < j - 1; l++) {
377 for (int m = l + 1; m < j; m++) {
378 // We truncated, so don't check for distinct indices here
d4d76536 379 Xc.emplace_back(Xt[i+l], Xt[i+m], hashLen, lenIndices, CollisionByteLength);
c92c1f60
JG
380 }
381 }
382
383 // 2d) Store tuples on the table in-place if possible
384 while (posFree < i+j && Xc.size() > 0) {
385 Xt[posFree++] = Xc.back();
386 Xc.pop_back();
387 }
388
389 i += j;
390 }
391
392 // 2e) Handle edge case where final table entry has no collision
393 while (posFree < Xt.size() && Xc.size() > 0) {
394 Xt[posFree++] = Xc.back();
395 Xc.pop_back();
396 }
397
398 if (Xc.size() > 0) {
399 // 2f) Add overflow to end of table
400 Xt.insert(Xt.end(), Xc.begin(), Xc.end());
401 } else if (posFree < Xt.size()) {
402 // 2g) Remove empty space at the end
403 Xt.erase(Xt.begin()+posFree, Xt.end());
404 Xt.shrink_to_fit();
405 }
639c4004
JG
406
407 hashLen -= CollisionByteLength;
d4d76536 408 lenIndices *= 2;
c92c1f60
JG
409 }
410
411 // k+1) Find a collision on last 2n(k+1) bits
412 LogPrint("pow", "Final round:\n");
413 if (Xt.size() > 1) {
414 LogPrint("pow", "- Sorting list\n");
639c4004 415 std::sort(Xt.begin(), Xt.end(), CompareSR(hashLen));
c92c1f60
JG
416 LogPrint("pow", "- Finding collisions\n");
417 for (int i = 0; i < Xt.size() - 1; i++) {
d4d76536
JG
418 TruncatedStepRow<FinalTruncatedWidth> res(Xt[i], Xt[i+1], hashLen, lenIndices, 0);
419 if (res.IsZero(hashLen)) {
420 partialSolns.push_back(res.GetTruncatedIndices(hashLen, 2*lenIndices));
c92c1f60
JG
421 }
422 }
423 } else
424 LogPrint("pow", "- List is empty\n");
425
426 } // Ensure Xt goes out of scope and is destroyed
427
428 LogPrint("pow", "Found %d partial solutions\n", partialSolns.size());
429
430 // Now for each solution run the algorithm again to recreate the indices
431 LogPrint("pow", "Culling solutions\n");
432 std::set<std::vector<eh_index>> solns;
e9574728 433 eh_index recreate_size { UntruncateIndex(1, 0, CollisionBitLength + 1) };
c92c1f60 434 int invalidCount = 0;
39f5cb35 435 for (eh_trunc* partialSoln : partialSolns) {
0a66f013
JG
436 size_t hashLen;
437 size_t lenIndices;
438 std::vector<boost::optional<std::vector<FullStepRow<FinalFullWidth>>>> X;
439 X.reserve(K+1);
440
441 // 3) Repeat steps 1 and 2 for each partial index
39f5cb35 442 for (eh_index i = 0; i < soln_size; i++) {
0a66f013
JG
443 // 1) Generate first list of possibilities
444 std::vector<FullStepRow<FinalFullWidth>> icv;
445 icv.reserve(recreate_size);
c92c1f60 446 for (eh_index j = 0; j < recreate_size; j++) {
e9574728 447 eh_index newIndex { UntruncateIndex(partialSoln[i], j, CollisionBitLength + 1) };
0a66f013 448 icv.emplace_back(N, base_state, newIndex);
c92c1f60 449 }
0a66f013 450 boost::optional<std::vector<FullStepRow<FinalFullWidth>>> ic = icv;
c92c1f60
JG
451
452 // 2a) For each pair of lists:
0a66f013
JG
453 hashLen = N/8;
454 lenIndices = sizeof(eh_index);
455 size_t rti = i;
456 for (size_t r = 0; r <= K; r++) {
457 // 2b) Until we are at the top of a subtree:
458 if (r < X.size()) {
459 if (X[r]) {
460 // 2c) Merge the lists
461 ic->reserve(ic->size() + X[r]->size());
462 ic->insert(ic->end(), X[r]->begin(), X[r]->end());
463 std::sort(ic->begin(), ic->end(), CompareSR(hashLen));
464 size_t lti = rti-(1<<r);
465 CollideBranches(*ic, hashLen, lenIndices,
466 CollisionByteLength,
467 CollisionBitLength + 1,
468 partialSoln[lti], partialSoln[rti]);
469
470 // 2d) Check if this has become an invalid solution
471 if (ic->size() == 0)
472 goto invalidsolution;
473
474 X[r] = boost::none;
475 hashLen -= CollisionByteLength;
476 lenIndices *= 2;
477 rti = lti;
478 } else {
479 X[r] = *ic;
480 break;
481 }
482 } else {
483 X.push_back(ic);
484 break;
485 }
c92c1f60 486 }
c92c1f60
JG
487 }
488
489 // We are at the top of the tree
0a66f013
JG
490 assert(X.size() == K+1);
491 for (FullStepRow<FinalFullWidth> row : *X[K]) {
d4d76536 492 solns.insert(row.GetIndices(hashLen, lenIndices));
c92c1f60 493 }
39f5cb35 494 goto deletesolution;
c92c1f60
JG
495
496invalidsolution:
497 invalidCount++;
39f5cb35
JG
498
499deletesolution:
500 delete[] partialSoln;
c92c1f60
JG
501 }
502 LogPrint("pow", "- Number of invalid solutions found: %d\n", invalidCount);
503
504 return solns;
505}
506
e9574728
JG
507template<unsigned int N, unsigned int K>
508bool Equihash<N,K>::IsValidSolution(const eh_HashState& base_state, std::vector<eh_index> soln)
6d25662f 509{
e9574728 510 eh_index soln_size { 1u << K };
6d25662f
JG
511 if (soln.size() != soln_size) {
512 LogPrint("pow", "Invalid solution size: %d\n", soln.size());
513 return false;
514 }
515
d4d76536 516 std::vector<FullStepRow<FinalFullWidth>> X;
6d25662f
JG
517 X.reserve(soln_size);
518 for (eh_index i : soln) {
e9574728 519 X.emplace_back(N, base_state, i);
6d25662f
JG
520 }
521
d4d76536
JG
522 size_t hashLen = N/8;
523 size_t lenIndices = sizeof(eh_index);
6d25662f 524 while (X.size() > 1) {
d4d76536 525 std::vector<FullStepRow<FinalFullWidth>> Xc;
6d25662f 526 for (int i = 0; i < X.size(); i += 2) {
e9574728 527 if (!HasCollision(X[i], X[i+1], CollisionByteLength)) {
6d25662f 528 LogPrint("pow", "Invalid solution: invalid collision length between StepRows\n");
d4d76536
JG
529 LogPrint("pow", "X[i] = %s\n", X[i].GetHex(hashLen));
530 LogPrint("pow", "X[i+1] = %s\n", X[i+1].GetHex(hashLen));
6d25662f
JG
531 return false;
532 }
d07cf629 533 if (X[i+1].IndicesBefore(X[i], hashLen, lenIndices)) {
6d25662f
JG
534 return false;
535 LogPrint("pow", "Invalid solution: Index tree incorrectly ordered\n");
536 }
d4d76536 537 if (!DistinctIndices(X[i], X[i+1], hashLen, lenIndices)) {
6d25662f
JG
538 LogPrint("pow", "Invalid solution: duplicate indices\n");
539 return false;
540 }
d4d76536 541 Xc.emplace_back(X[i], X[i+1], hashLen, lenIndices, CollisionByteLength);
6d25662f
JG
542 }
543 X = Xc;
d4d76536
JG
544 hashLen -= CollisionByteLength;
545 lenIndices *= 2;
6d25662f
JG
546 }
547
548 assert(X.size() == 1);
d4d76536 549 return X[0].IsZero(hashLen);
6d25662f 550}
e9574728 551
ae37d2a4
JG
552// Explicit instantiations for Equihash<96,3>
553template int Equihash<96,3>::InitialiseState(eh_HashState& base_state);
554template std::set<std::vector<eh_index>> Equihash<96,3>::BasicSolve(const eh_HashState& base_state);
555template std::set<std::vector<eh_index>> Equihash<96,3>::OptimisedSolve(const eh_HashState& base_state);
556template bool Equihash<96,3>::IsValidSolution(const eh_HashState& base_state, std::vector<eh_index> soln);
557
e9574728
JG
558// Explicit instantiations for Equihash<96,5>
559template int Equihash<96,5>::InitialiseState(eh_HashState& base_state);
560template std::set<std::vector<eh_index>> Equihash<96,5>::BasicSolve(const eh_HashState& base_state);
561template std::set<std::vector<eh_index>> Equihash<96,5>::OptimisedSolve(const eh_HashState& base_state);
562template bool Equihash<96,5>::IsValidSolution(const eh_HashState& base_state, std::vector<eh_index> soln);
563
564// Explicit instantiations for Equihash<48,5>
565template int Equihash<48,5>::InitialiseState(eh_HashState& base_state);
566template std::set<std::vector<eh_index>> Equihash<48,5>::BasicSolve(const eh_HashState& base_state);
567template std::set<std::vector<eh_index>> Equihash<48,5>::OptimisedSolve(const eh_HashState& base_state);
568template bool Equihash<48,5>::IsValidSolution(const eh_HashState& base_state, std::vector<eh_index> soln);
This page took 0.095016 seconds and 4 git commands to generate.