|
|
@ -54,26 +54,54 @@ |
|
|
|
#define __BYTE_ORDER BYTE_ORDER |
|
|
|
#endif |
|
|
|
*/ |
|
|
|
|
|
|
|
static EhSolverCancelledException solver_cancelled; |
|
|
|
|
|
|
|
int8_t ZeroizeUnusedBits(size_t N, unsigned char* hash, size_t hLen) |
|
|
|
{ |
|
|
|
uint8_t rem = N % 8; |
|
|
|
if (rem) |
|
|
|
{ |
|
|
|
// clear lowest 8-rem bits
|
|
|
|
const size_t step = GetSizeInBytes(N); |
|
|
|
for (size_t i = step - 1; i < hLen; i += step) |
|
|
|
{ |
|
|
|
uint8_t b = 0xff << (8-rem); |
|
|
|
hash[i] &= b; |
|
|
|
} |
|
|
|
} |
|
|
|
return(0); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template<unsigned int N, unsigned int K> |
|
|
|
int Equihash<N,K>::InitialiseState(eh_HashState& base_state) |
|
|
|
{ |
|
|
|
uint32_t le_N = htole32(N); |
|
|
|
uint32_t le_K = htole32(K); |
|
|
|
|
|
|
|
unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {}; |
|
|
|
if ( ASSETCHAINS_NK[0] == 0 && ASSETCHAINS_NK[1] == 0 ) |
|
|
|
memcpy(personalization, "ZcashPoW", 8); |
|
|
|
else |
|
|
|
memcpy(personalization, "NandKPoW", 8); |
|
|
|
memcpy(personalization+8, &le_N, 4); |
|
|
|
memcpy(personalization+12, &le_K, 4); |
|
|
|
|
|
|
|
const uint8_t outlen = (512 / N) * GetSizeInBytes(N); |
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(!((!outlen) || (outlen > BLAKE2B_OUTBYTES))); |
|
|
|
return crypto_generichash_blake2b_init_salt_personal(&base_state, |
|
|
|
NULL, 0, // No key.
|
|
|
|
(512/N)*N/8, |
|
|
|
outlen, |
|
|
|
NULL, // No salt.
|
|
|
|
personalization); |
|
|
|
} |
|
|
|
|
|
|
|
void GenerateHash(const eh_HashState& base_state, eh_index g, |
|
|
|
unsigned char* hash, size_t hLen) |
|
|
|
unsigned char* hash, size_t hLen, size_t N) |
|
|
|
{ |
|
|
|
if ( ASSETCHAINS_NK[0] == 0 && ASSETCHAINS_NK[1] == 0 ) |
|
|
|
{ |
|
|
|
eh_HashState state; |
|
|
|
state = base_state; |
|
|
@ -82,13 +110,36 @@ void GenerateHash(const eh_HashState& base_state, eh_index g, |
|
|
|
sizeof(eh_index)); |
|
|
|
crypto_generichash_blake2b_final(&state, hash, hLen); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
uint32_t myHash[16] = {0}; |
|
|
|
uint32_t startIndex = g & 0xFFFFFFF0; |
|
|
|
|
|
|
|
for (uint32_t g2 = startIndex; g2 <= g; g2++) { |
|
|
|
uint32_t tmpHash[16] = {0}; |
|
|
|
|
|
|
|
eh_HashState state; |
|
|
|
state = base_state; |
|
|
|
eh_index lei = htole32(g2); |
|
|
|
crypto_generichash_blake2b_update(&state, (const unsigned char*) &lei, |
|
|
|
sizeof(eh_index)); |
|
|
|
|
|
|
|
crypto_generichash_blake2b_final(&state, (unsigned char*)&tmpHash[0], static_cast<uint8_t>(hLen)); |
|
|
|
|
|
|
|
for (uint32_t idx = 0; idx < 16; idx++) myHash[idx] += tmpHash[idx]; |
|
|
|
} |
|
|
|
|
|
|
|
memcpy(hash, &myHash[0], hLen); |
|
|
|
ZeroizeUnusedBits(N, hash, hLen); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void ExpandArray(const unsigned char* in, size_t in_len, |
|
|
|
unsigned char* out, size_t out_len, |
|
|
|
size_t bit_len, size_t byte_pad) |
|
|
|
{ |
|
|
|
assert(bit_len >= 8); |
|
|
|
assert(8*sizeof(uint32_t) >= 7+bit_len); |
|
|
|
assert(8*sizeof(uint32_t) >= bit_len); |
|
|
|
|
|
|
|
size_t out_width { (bit_len+7)/8 + byte_pad }; |
|
|
|
assert(out_len == 8*out_width*in_len/bit_len); |
|
|
@ -131,10 +182,10 @@ void CompressArray(const unsigned char* in, size_t in_len, |
|
|
|
size_t bit_len, size_t byte_pad) |
|
|
|
{ |
|
|
|
assert(bit_len >= 8); |
|
|
|
assert(8*sizeof(uint32_t) >= 7+bit_len); |
|
|
|
assert(8*sizeof(uint32_t) >= bit_len); |
|
|
|
|
|
|
|
size_t in_width { (bit_len+7)/8 + byte_pad }; |
|
|
|
assert(out_len == bit_len*in_len/(8*in_width)); |
|
|
|
assert(out_len == (bit_len*in_len/in_width + 7)/8); |
|
|
|
|
|
|
|
uint32_t bit_len_mask { ((uint32_t)1 << bit_len) - 1 }; |
|
|
|
|
|
|
@ -148,6 +199,7 @@ void CompressArray(const unsigned char* in, size_t in_len, |
|
|
|
// When we have fewer than 8 bits left in the accumulator, read the next
|
|
|
|
// input element.
|
|
|
|
if (acc_bits < 8) { |
|
|
|
if (j < in_len) { |
|
|
|
acc_value = acc_value << bit_len; |
|
|
|
for (size_t x = byte_pad; x < in_width; x++) { |
|
|
|
acc_value = acc_value | ( |
|
|
@ -159,6 +211,11 @@ void CompressArray(const unsigned char* in, size_t in_len, |
|
|
|
j += in_width; |
|
|
|
acc_bits += bit_len; |
|
|
|
} |
|
|
|
else { |
|
|
|
acc_value <<= 8 - acc_bits; |
|
|
|
acc_bits += 8 - acc_bits;; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
acc_bits -= 8; |
|
|
|
out[i] = (acc_value >> acc_bits) & 0xFF; |
|
|
@ -207,7 +264,7 @@ std::vector<eh_index> GetIndicesFromMinimal(std::vector<unsigned char> minimal, |
|
|
|
ExpandArray(minimal.data(), minimal.size(), |
|
|
|
array.data(), lenIndices, cBitLen+1, bytePad); |
|
|
|
std::vector<eh_index> ret; |
|
|
|
for (int i = 0; i < lenIndices; i += sizeof(eh_index)) { |
|
|
|
for (size_t i = 0; i < lenIndices; i += sizeof(eh_index)) { |
|
|
|
ret.push_back(ArrayToEhIndex(array.data()+i)); |
|
|
|
} |
|
|
|
return ret; |
|
|
@ -221,7 +278,7 @@ std::vector<unsigned char> GetMinimalFromIndices(std::vector<eh_index> indices, |
|
|
|
size_t minLen { (cBitLen+1)*lenIndices/(8*sizeof(eh_index)) }; |
|
|
|
size_t bytePad { sizeof(eh_index) - ((cBitLen+1)+7)/8 }; |
|
|
|
std::vector<unsigned char> array(lenIndices); |
|
|
|
for (int i = 0; i < indices.size(); i++) { |
|
|
|
for (size_t i = 0; i < indices.size(); i++) { |
|
|
|
EhIndexToArray(indices[i], array.data()+(i*sizeof(eh_index))); |
|
|
|
} |
|
|
|
std::vector<unsigned char> ret(minLen); |
|
|
@ -254,12 +311,12 @@ FullStepRow<WIDTH>::FullStepRow(const unsigned char* hashIn, size_t hInLen, |
|
|
|
} |
|
|
|
|
|
|
|
template<size_t WIDTH> template<size_t W> |
|
|
|
FullStepRow<WIDTH>::FullStepRow(const FullStepRow<W>& a, const FullStepRow<W>& b, size_t len, size_t lenIndices, int trim) : |
|
|
|
FullStepRow<WIDTH>::FullStepRow(const FullStepRow<W>& a, const FullStepRow<W>& b, size_t len, size_t lenIndices, size_t trim) : |
|
|
|
StepRow<WIDTH> {a} |
|
|
|
{ |
|
|
|
assert(len+lenIndices <= W); |
|
|
|
assert(len-trim+(2*lenIndices) <= WIDTH); |
|
|
|
for (int i = trim; i < len; i++) |
|
|
|
for (size_t i = trim; i < len; i++) |
|
|
|
hash[i-trim] = a.hash[i] ^ b.hash[i]; |
|
|
|
if (a.IndicesBefore(b, len, lenIndices)) { |
|
|
|
std::copy(a.hash+len, a.hash+len+lenIndices, hash+len-trim); |
|
|
@ -281,7 +338,7 @@ template<size_t WIDTH> |
|
|
|
bool StepRow<WIDTH>::IsZero(size_t len) |
|
|
|
{ |
|
|
|
// This doesn't need to be constant time.
|
|
|
|
for (int i = 0; i < len; i++) { |
|
|
|
for (size_t i = 0; i < len; i++) { |
|
|
|
if (hash[i] != 0) |
|
|
|
return false; |
|
|
|
} |
|
|
@ -301,10 +358,10 @@ std::vector<unsigned char> FullStepRow<WIDTH>::GetIndices(size_t len, size_t len |
|
|
|
} |
|
|
|
|
|
|
|
template<size_t WIDTH> |
|
|
|
bool HasCollision(StepRow<WIDTH>& a, StepRow<WIDTH>& b, int l) |
|
|
|
bool HasCollision(StepRow<WIDTH>& a, StepRow<WIDTH>& b, size_t l) |
|
|
|
{ |
|
|
|
// This doesn't need to be constant time.
|
|
|
|
for (int j = 0; j < l; j++) { |
|
|
|
for (size_t j = 0; j < l; j++) { |
|
|
|
if (a.hash[j] != b.hash[j]) |
|
|
|
return false; |
|
|
|
} |
|
|
@ -326,7 +383,7 @@ TruncatedStepRow<WIDTH>::TruncatedStepRow(const TruncatedStepRow<W>& a, const Tr |
|
|
|
{ |
|
|
|
assert(len+lenIndices <= W); |
|
|
|
assert(len-trim+(2*lenIndices) <= WIDTH); |
|
|
|
for (int i = trim; i < len; i++) |
|
|
|
for (size_t i = static_cast<size_t>(trim); i < len; i++) |
|
|
|
hash[i-trim] = a.hash[i] ^ b.hash[i]; |
|
|
|
if (a.IndicesBefore(b, len, lenIndices)) { |
|
|
|
std::copy(a.hash+len, a.hash+len+lenIndices, hash+len-trim); |
|
|
@ -355,10 +412,10 @@ std::shared_ptr<eh_trunc> TruncatedStepRow<WIDTH>::GetTruncatedIndices(size_t le |
|
|
|
#ifdef ENABLE_MINING |
|
|
|
template<unsigned int N, unsigned int K> |
|
|
|
bool Equihash<N,K>::BasicSolve(const eh_HashState& base_state, |
|
|
|
const std::function<bool(std::vector<unsigned char>)> validBlock, |
|
|
|
const std::function<bool(const std::vector<unsigned char>&)> validBlock, |
|
|
|
const std::function<bool(EhSolverCancelCheck)> cancelled) |
|
|
|
{ |
|
|
|
eh_index init_size { 1 << (CollisionBitLength + 1) }; |
|
|
|
eh_index init_size { 1U << (CollisionBitLength + 1) }; |
|
|
|
|
|
|
|
// 1) Generate first list
|
|
|
|
LogPrint("pow", "Generating first list\n"); |
|
|
@ -368,16 +425,16 @@ bool Equihash<N,K>::BasicSolve(const eh_HashState& base_state, |
|
|
|
X.reserve(init_size); |
|
|
|
unsigned char tmpHash[HashOutput]; |
|
|
|
for (eh_index g = 0; X.size() < init_size; g++) { |
|
|
|
GenerateHash(base_state, g, tmpHash, HashOutput); |
|
|
|
GenerateHash(base_state, g, tmpHash, HashOutput, N); |
|
|
|
for (eh_index i = 0; i < IndicesPerHashOutput && X.size() < init_size; i++) { |
|
|
|
X.emplace_back(tmpHash+(i*N/8), N/8, HashLength, |
|
|
|
CollisionBitLength, (g*IndicesPerHashOutput)+i); |
|
|
|
X.emplace_back(tmpHash+(i*GetSizeInBytes(N)), GetSizeInBytes(N), HashLength, |
|
|
|
CollisionBitLength, static_cast<int>(g*IndicesPerHashOutput)+i); |
|
|
|
} |
|
|
|
if (cancelled(ListGeneration)) throw solver_cancelled; |
|
|
|
} |
|
|
|
|
|
|
|
// 3) Repeat step 2 until 2n/(k+1) bits remain
|
|
|
|
for (int r = 1; r < K && X.size() > 0; r++) { |
|
|
|
for (unsigned int r = 1; r < K && X.size() > 0; r++) { |
|
|
|
LogPrint("pow", "Round %d:\n", r); |
|
|
|
// 2a) Sort the list
|
|
|
|
LogPrint("pow", "- Sorting list\n"); |
|
|
@ -385,20 +442,20 @@ bool Equihash<N,K>::BasicSolve(const eh_HashState& base_state, |
|
|
|
if (cancelled(ListSorting)) throw solver_cancelled; |
|
|
|
|
|
|
|
LogPrint("pow", "- Finding collisions\n"); |
|
|
|
int i = 0; |
|
|
|
int posFree = 0; |
|
|
|
size_t i = 0; |
|
|
|
size_t posFree = 0; |
|
|
|
std::vector<FullStepRow<FullWidth>> Xc; |
|
|
|
while (i < X.size() - 1) { |
|
|
|
// 2b) Find next set of unordered pairs with collisions on the next n/(k+1) bits
|
|
|
|
int j = 1; |
|
|
|
size_t j = 1; |
|
|
|
while (i+j < X.size() && |
|
|
|
HasCollision(X[i], X[i+j], CollisionByteLength)) { |
|
|
|
j++; |
|
|
|
} |
|
|
|
|
|
|
|
// 2c) Calculate tuples (X_i ^ X_j, (i, j))
|
|
|
|
for (int l = 0; l < j - 1; l++) { |
|
|
|
for (int m = l + 1; m < j; m++) { |
|
|
|
for (size_t l = 0; l < j - 1; l++) { |
|
|
|
for (size_t m = l + 1; m < j; m++) { |
|
|
|
if (DistinctIndices(X[i+l], X[i+m], hashLen, lenIndices)) { |
|
|
|
Xc.emplace_back(X[i+l], X[i+m], hashLen, lenIndices, CollisionByteLength); |
|
|
|
} |
|
|
@ -442,16 +499,16 @@ bool Equihash<N,K>::BasicSolve(const eh_HashState& base_state, |
|
|
|
std::sort(X.begin(), X.end(), CompareSR(hashLen)); |
|
|
|
if (cancelled(FinalSorting)) throw solver_cancelled; |
|
|
|
LogPrint("pow", "- Finding collisions\n"); |
|
|
|
int i = 0; |
|
|
|
size_t i = 0; |
|
|
|
while (i < X.size() - 1) { |
|
|
|
int j = 1; |
|
|
|
size_t j = 1; |
|
|
|
while (i+j < X.size() && |
|
|
|
HasCollision(X[i], X[i+j], hashLen)) { |
|
|
|
j++; |
|
|
|
} |
|
|
|
|
|
|
|
for (int l = 0; l < j - 1; l++) { |
|
|
|
for (int m = l + 1; m < j; m++) { |
|
|
|
for (size_t l = 0; l < j - 1; l++) { |
|
|
|
for (size_t m = l + 1; m < j; m++) { |
|
|
|
FullStepRow<FinalFullWidth> res(X[i+l], X[i+m], hashLen, lenIndices, 0); |
|
|
|
if (DistinctIndices(X[i+l], X[i+m], hashLen, lenIndices)) { |
|
|
|
auto soln = res.GetIndices(hashLen, 2*lenIndices, CollisionBitLength); |
|
|
@ -475,20 +532,21 @@ bool Equihash<N,K>::BasicSolve(const eh_HashState& base_state, |
|
|
|
template<size_t WIDTH> |
|
|
|
void 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) |
|
|
|
{ |
|
|
|
int i = 0; |
|
|
|
int posFree = 0; |
|
|
|
size_t i = 0; |
|
|
|
size_t posFree = 0; |
|
|
|
assert(X.size() > 0); |
|
|
|
std::vector<FullStepRow<WIDTH>> Xc; |
|
|
|
while (i < X.size() - 1) { |
|
|
|
// 2b) Find next set of unordered pairs with collisions on the next n/(k+1) bits
|
|
|
|
int j = 1; |
|
|
|
size_t j = 1; |
|
|
|
while (i+j < X.size() && |
|
|
|
HasCollision(X[i], X[i+j], clen)) { |
|
|
|
j++; |
|
|
|
} |
|
|
|
|
|
|
|
// 2c) Calculate tuples (X_i ^ X_j, (i, j))
|
|
|
|
for (int l = 0; l < j - 1; l++) { |
|
|
|
for (int m = l + 1; m < j; m++) { |
|
|
|
for (size_t l = 0; l < j - 1; l++) { |
|
|
|
for (size_t m = l + 1; m < j; m++) { |
|
|
|
if (DistinctIndices(X[i+l], X[i+m], hlen, lenIndices)) { |
|
|
|
if (IsValidBranch(X[i+l], hlen, ilen, lt) && IsValidBranch(X[i+m], hlen, ilen, rt)) { |
|
|
|
Xc.emplace_back(X[i+l], X[i+m], hlen, lenIndices, clen); |
|
|
@ -526,10 +584,10 @@ void CollideBranches(std::vector<FullStepRow<WIDTH>>& X, const size_t hlen, cons |
|
|
|
|
|
|
|
template<unsigned int N, unsigned int K> |
|
|
|
bool Equihash<N,K>::OptimisedSolve(const eh_HashState& base_state, |
|
|
|
const std::function<bool(std::vector<unsigned char>)> validBlock, |
|
|
|
const std::function<bool(const std::vector<unsigned char>&)> validBlock, |
|
|
|
const std::function<bool(EhSolverCancelCheck)> cancelled) |
|
|
|
{ |
|
|
|
eh_index init_size { 1 << (CollisionBitLength + 1) }; |
|
|
|
eh_index init_size { 1U << (CollisionBitLength + 1) }; |
|
|
|
eh_index recreate_size { UntruncateIndex(1, 0, CollisionBitLength + 1) }; |
|
|
|
|
|
|
|
// First run the algorithm with truncated indices
|
|
|
@ -547,16 +605,16 @@ bool Equihash<N,K>::OptimisedSolve(const eh_HashState& base_state, |
|
|
|
Xt.reserve(init_size); |
|
|
|
unsigned char tmpHash[HashOutput]; |
|
|
|
for (eh_index g = 0; Xt.size() < init_size; g++) { |
|
|
|
GenerateHash(base_state, g, tmpHash, HashOutput); |
|
|
|
GenerateHash(base_state, g, tmpHash, HashOutput, N); |
|
|
|
for (eh_index i = 0; i < IndicesPerHashOutput && Xt.size() < init_size; i++) { |
|
|
|
Xt.emplace_back(tmpHash+(i*N/8), N/8, HashLength, CollisionBitLength, |
|
|
|
(g*IndicesPerHashOutput)+i, CollisionBitLength + 1); |
|
|
|
Xt.emplace_back(tmpHash+(i*GetSizeInBytes(N)), GetSizeInBytes(N), HashLength, CollisionBitLength, |
|
|
|
static_cast<eh_index>(g*IndicesPerHashOutput)+i, static_cast<unsigned int>(CollisionBitLength + 1)); |
|
|
|
} |
|
|
|
if (cancelled(ListGeneration)) throw solver_cancelled; |
|
|
|
} |
|
|
|
|
|
|
|
// 3) Repeat step 2 until 2n/(k+1) bits remain
|
|
|
|
for (int r = 1; r < K && Xt.size() > 0; r++) { |
|
|
|
for (unsigned int r = 1; r < K && Xt.size() > 0; r++) { |
|
|
|
LogPrint("pow", "Round %d:\n", r); |
|
|
|
// 2a) Sort the list
|
|
|
|
LogPrint("pow", "- Sorting list\n"); |
|
|
@ -564,21 +622,21 @@ bool Equihash<N,K>::OptimisedSolve(const eh_HashState& base_state, |
|
|
|
if (cancelled(ListSorting)) throw solver_cancelled; |
|
|
|
|
|
|
|
LogPrint("pow", "- Finding collisions\n"); |
|
|
|
int i = 0; |
|
|
|
int posFree = 0; |
|
|
|
size_t i = 0; |
|
|
|
size_t posFree = 0; |
|
|
|
std::vector<TruncatedStepRow<TruncatedWidth>> Xc; |
|
|
|
while (i < Xt.size() - 1) { |
|
|
|
// 2b) Find next set of unordered pairs with collisions on the next n/(k+1) bits
|
|
|
|
int j = 1; |
|
|
|
size_t j = 1; |
|
|
|
while (i+j < Xt.size() && |
|
|
|
HasCollision(Xt[i], Xt[i+j], CollisionByteLength)) { |
|
|
|
j++; |
|
|
|
} |
|
|
|
|
|
|
|
// 2c) Calculate tuples (X_i ^ X_j, (i, j))
|
|
|
|
bool checking_for_zero = (i == 0 && Xt[0].IsZero(hashLen)); |
|
|
|
for (int l = 0; l < j - 1; l++) { |
|
|
|
for (int m = l + 1; m < j; m++) { |
|
|
|
//bool checking_for_zero = (i == 0 && Xt[0].IsZero(hashLen));
|
|
|
|
for (size_t l = 0; l < j - 1; l++) { |
|
|
|
for (size_t m = l + 1; m < j; m++) { |
|
|
|
// We truncated, so don't check for distinct indices here
|
|
|
|
TruncatedStepRow<TruncatedWidth> Xi {Xt[i+l], Xt[i+m], |
|
|
|
hashLen, lenIndices, |
|
|
@ -628,16 +686,16 @@ bool Equihash<N,K>::OptimisedSolve(const eh_HashState& base_state, |
|
|
|
std::sort(Xt.begin(), Xt.end(), CompareSR(hashLen)); |
|
|
|
if (cancelled(FinalSorting)) throw solver_cancelled; |
|
|
|
LogPrint("pow", "- Finding collisions\n"); |
|
|
|
int i = 0; |
|
|
|
size_t i = 0; |
|
|
|
while (i < Xt.size() - 1) { |
|
|
|
int j = 1; |
|
|
|
size_t j = 1; |
|
|
|
while (i+j < Xt.size() && |
|
|
|
HasCollision(Xt[i], Xt[i+j], hashLen)) { |
|
|
|
j++; |
|
|
|
} |
|
|
|
|
|
|
|
for (int l = 0; l < j - 1; l++) { |
|
|
|
for (int m = l + 1; m < j; m++) { |
|
|
|
for (size_t l = 0; l < j - 1; l++) { |
|
|
|
for (size_t m = l + 1; m < j; m++) { |
|
|
|
TruncatedStepRow<FinalTruncatedWidth> res(Xt[i+l], Xt[i+m], |
|
|
|
hashLen, lenIndices, 0); |
|
|
|
auto soln = res.GetTruncatedIndices(hashLen, 2*lenIndices); |
|
|
@ -676,10 +734,10 @@ bool Equihash<N,K>::OptimisedSolve(const eh_HashState& base_state, |
|
|
|
eh_index newIndex { UntruncateIndex(partialSoln.get()[i], j, CollisionBitLength + 1) }; |
|
|
|
if (j == 0 || newIndex % IndicesPerHashOutput == 0) { |
|
|
|
GenerateHash(base_state, newIndex/IndicesPerHashOutput, |
|
|
|
tmpHash, HashOutput); |
|
|
|
tmpHash, HashOutput, N); |
|
|
|
} |
|
|
|
icv.emplace_back(tmpHash+((newIndex % IndicesPerHashOutput) * N/8), |
|
|
|
N/8, HashLength, CollisionBitLength, newIndex); |
|
|
|
icv.emplace_back(tmpHash+((newIndex % IndicesPerHashOutput) * GetSizeInBytes(N)), |
|
|
|
GetSizeInBytes(N), HashLength, CollisionBitLength, newIndex); |
|
|
|
if (cancelled(PartialGeneration)) throw solver_cancelled; |
|
|
|
} |
|
|
|
boost::optional<std::vector<FullStepRow<FinalFullWidth>>> ic = icv; |
|
|
@ -697,7 +755,7 @@ bool Equihash<N,K>::OptimisedSolve(const eh_HashState& base_state, |
|
|
|
ic->insert(ic->end(), X[r]->begin(), X[r]->end()); |
|
|
|
std::sort(ic->begin(), ic->end(), CompareSR(hashLen)); |
|
|
|
if (cancelled(PartialSorting)) throw solver_cancelled; |
|
|
|
size_t lti = rti-(1<<r); |
|
|
|
size_t lti = rti-(static_cast<size_t>(1)<<r); |
|
|
|
CollideBranches(*ic, hashLen, lenIndices, |
|
|
|
CollisionByteLength, |
|
|
|
CollisionBitLength + 1, |
|
|
@ -760,16 +818,16 @@ bool Equihash<N,K>::IsValidSolution(const eh_HashState& base_state, std::vector< |
|
|
|
X.reserve(1 << K); |
|
|
|
unsigned char tmpHash[HashOutput]; |
|
|
|
for (eh_index i : GetIndicesFromMinimal(soln, CollisionBitLength)) { |
|
|
|
GenerateHash(base_state, i/IndicesPerHashOutput, tmpHash, HashOutput); |
|
|
|
X.emplace_back(tmpHash+((i % IndicesPerHashOutput) * N/8), |
|
|
|
N/8, HashLength, CollisionBitLength, i); |
|
|
|
GenerateHash(base_state, i/IndicesPerHashOutput, tmpHash, HashOutput, N); |
|
|
|
X.emplace_back(tmpHash+((i % IndicesPerHashOutput) * GetSizeInBytes(N)), |
|
|
|
GetSizeInBytes(N), HashLength, CollisionBitLength, i); |
|
|
|
} |
|
|
|
|
|
|
|
size_t hashLen = HashLength; |
|
|
|
size_t lenIndices = sizeof(eh_index); |
|
|
|
while (X.size() > 1) { |
|
|
|
std::vector<FullStepRow<FinalFullWidth>> Xc; |
|
|
|
for (int i = 0; i < X.size(); i += 2) { |
|
|
|
for (size_t i = 0; i < X.size(); i += 2) { |
|
|
|
if (!HasCollision(X[i], X[i+1], CollisionByteLength)) { |
|
|
|
LogPrint("pow", "Invalid solution: invalid collision length between StepRows\n"); |
|
|
|
LogPrint("pow", "X[i] = %s\n", X[i].GetHex(hashLen)); |
|
|
@ -795,50 +853,74 @@ bool Equihash<N,K>::IsValidSolution(const eh_HashState& base_state, std::vector< |
|
|
|
return X[0].IsZero(hashLen); |
|
|
|
} |
|
|
|
|
|
|
|
// Explicit instantiations for Equihash<200,9>
|
|
|
|
template int Equihash<200,9>::InitialiseState(eh_HashState& base_state); |
|
|
|
#ifdef ENABLE_MINING |
|
|
|
template bool Equihash<200,9>::BasicSolve(const eh_HashState& base_state, |
|
|
|
const std::function<bool(const std::vector<unsigned char>&)> validBlock, |
|
|
|
const std::function<bool(EhSolverCancelCheck)> cancelled); |
|
|
|
template bool Equihash<200,9>::OptimisedSolve(const eh_HashState& base_state, |
|
|
|
const std::function<bool(const std::vector<unsigned char>&)> validBlock, |
|
|
|
const std::function<bool(EhSolverCancelCheck)> cancelled); |
|
|
|
#endif |
|
|
|
template bool Equihash<200,9>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln); |
|
|
|
|
|
|
|
// Explicit instantiations for Equihash<96,3>
|
|
|
|
template int Equihash<96,3>::InitialiseState(eh_HashState& base_state); |
|
|
|
template int Equihash<150,5>::InitialiseState(eh_HashState& base_state); |
|
|
|
#ifdef ENABLE_MINING |
|
|
|
template bool Equihash<96,3>::BasicSolve(const eh_HashState& base_state, |
|
|
|
const std::function<bool(std::vector<unsigned char>)> validBlock, |
|
|
|
template bool Equihash<150,5>::BasicSolve(const eh_HashState& base_state, |
|
|
|
const std::function<bool(const std::vector<unsigned char>&)> validBlock, |
|
|
|
const std::function<bool(EhSolverCancelCheck)> cancelled); |
|
|
|
template bool Equihash<96,3>::OptimisedSolve(const eh_HashState& base_state, |
|
|
|
const std::function<bool(std::vector<unsigned char>)> validBlock, |
|
|
|
template bool Equihash<150,5>::OptimisedSolve(const eh_HashState& base_state, |
|
|
|
const std::function<bool(const std::vector<unsigned char>&)> validBlock, |
|
|
|
const std::function<bool(EhSolverCancelCheck)> cancelled); |
|
|
|
#endif |
|
|
|
template bool Equihash<96,3>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln); |
|
|
|
template bool Equihash<150,5>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln); |
|
|
|
|
|
|
|
// Explicit instantiations for Equihash<200,9>
|
|
|
|
template int Equihash<200,9>::InitialiseState(eh_HashState& base_state); |
|
|
|
// Explicit instantiations for Equihash<48,5>
|
|
|
|
template int Equihash<144,5>::InitialiseState(eh_HashState& base_state); |
|
|
|
#ifdef ENABLE_MINING |
|
|
|
template bool Equihash<200,9>::BasicSolve(const eh_HashState& base_state, |
|
|
|
const std::function<bool(std::vector<unsigned char>)> validBlock, |
|
|
|
template bool Equihash<144,5>::BasicSolve(const eh_HashState& base_state, |
|
|
|
const std::function<bool(const std::vector<unsigned char>&)> validBlock, |
|
|
|
const std::function<bool(EhSolverCancelCheck)> cancelled); |
|
|
|
template bool Equihash<200,9>::OptimisedSolve(const eh_HashState& base_state, |
|
|
|
const std::function<bool(std::vector<unsigned char>)> validBlock, |
|
|
|
template bool Equihash<144,5>::OptimisedSolve(const eh_HashState& base_state, |
|
|
|
const std::function<bool(const std::vector<unsigned char>&)> validBlock, |
|
|
|
const std::function<bool(EhSolverCancelCheck)> cancelled); |
|
|
|
#endif |
|
|
|
template bool Equihash<200,9>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln); |
|
|
|
template bool Equihash<144,5>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln); |
|
|
|
|
|
|
|
// Explicit instantiations for Equihash<96,5>
|
|
|
|
template int Equihash<96,5>::InitialiseState(eh_HashState& base_state); |
|
|
|
template int Equihash<ASSETCHAINS_N,ASSETCHAINS_K>::InitialiseState(eh_HashState& base_state); |
|
|
|
#ifdef ENABLE_MINING |
|
|
|
template bool Equihash<96,5>::BasicSolve(const eh_HashState& base_state, |
|
|
|
const std::function<bool(std::vector<unsigned char>)> validBlock, |
|
|
|
template bool Equihash<ASSETCHAINS_N,ASSETCHAINS_K>::BasicSolve(const eh_HashState& base_state, |
|
|
|
const std::function<bool(const std::vector<unsigned char>&)> validBlock, |
|
|
|
const std::function<bool(EhSolverCancelCheck)> cancelled); |
|
|
|
template bool Equihash<96,5>::OptimisedSolve(const eh_HashState& base_state, |
|
|
|
const std::function<bool(std::vector<unsigned char>)> validBlock, |
|
|
|
template bool Equihash<ASSETCHAINS_N,ASSETCHAINS_K>::OptimisedSolve(const eh_HashState& base_state, |
|
|
|
const std::function<bool(const std::vector<unsigned char>&)> validBlock, |
|
|
|
const std::function<bool(EhSolverCancelCheck)> cancelled); |
|
|
|
#endif |
|
|
|
template bool Equihash<96,5>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln); |
|
|
|
template bool Equihash<ASSETCHAINS_N,ASSETCHAINS_K>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln); |
|
|
|
|
|
|
|
// Explicit instantiations for Equihash<48,5>
|
|
|
|
// Explicit instantiations for Equihash<96,5>
|
|
|
|
template int Equihash<48,5>::InitialiseState(eh_HashState& base_state); |
|
|
|
#ifdef ENABLE_MINING |
|
|
|
template bool Equihash<48,5>::BasicSolve(const eh_HashState& base_state, |
|
|
|
const std::function<bool(std::vector<unsigned char>)> validBlock, |
|
|
|
const std::function<bool(const std::vector<unsigned char>&)> validBlock, |
|
|
|
const std::function<bool(EhSolverCancelCheck)> cancelled); |
|
|
|
template bool Equihash<48,5>::OptimisedSolve(const eh_HashState& base_state, |
|
|
|
const std::function<bool(std::vector<unsigned char>)> validBlock, |
|
|
|
const std::function<bool(const std::vector<unsigned char>&)> validBlock, |
|
|
|
const std::function<bool(EhSolverCancelCheck)> cancelled); |
|
|
|
#endif |
|
|
|
template bool Equihash<48,5>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln); |
|
|
|
|
|
|
|
// Explicit instantiations for Equihash<48,5>
|
|
|
|
template int Equihash<210,9>::InitialiseState(eh_HashState& base_state); |
|
|
|
#ifdef ENABLE_MINING |
|
|
|
template bool Equihash<210,9>::BasicSolve(const eh_HashState& base_state, |
|
|
|
const std::function<bool(const std::vector<unsigned char>&)> validBlock, |
|
|
|
const std::function<bool(EhSolverCancelCheck)> cancelled); |
|
|
|
template bool Equihash<210,9>::OptimisedSolve(const eh_HashState& base_state, |
|
|
|
const std::function<bool(const std::vector<unsigned char>&)> validBlock, |
|
|
|
const std::function<bool(EhSolverCancelCheck)> cancelled); |
|
|
|
#endif |
|
|
|
template bool Equihash<210,9>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln); |
|
|
|