diff --git a/src/crypto/equihash.cpp b/src/crypto/equihash.cpp index cc9804752..5f6f4eaec 100644 --- a/src/crypto/equihash.cpp +++ b/src/crypto/equihash.cpp @@ -72,7 +72,8 @@ eh_index UntruncateIndex(const eh_trunc t, const eh_index r, const unsigned int } template -StepRow::StepRow(unsigned int n, const eh_HashState& base_state, eh_index i) +StepRow::StepRow(const eh_HashState& base_state, eh_index i, + size_t hLen, size_t cBitLen, size_t cByteLen) { eh_HashState state; state = base_state; @@ -80,7 +81,16 @@ StepRow::StepRow(unsigned int n, const eh_HashState& base_state, eh_index eh_index lei = htole32(i); memcpy(array, &lei, sizeof(eh_index)); crypto_generichash_blake2b_update(&state, array, sizeof(eh_index)); - crypto_generichash_blake2b_final(&state, hash, n/8); + crypto_generichash_blake2b_final(&state, hash, hLen); + + if (8*cByteLen != cBitLen) { + // We are not colliding an integer number of bytes, expand + // TODO fix this to expand from the correct length instead of clearing bits + // When this is done, change hLen to be N/8 instead of HashLength + for (size_t i = 0; i < hLen; i += cByteLen) { + hash[i] &= 0xFF >> (8*cByteLen - cBitLen); + } + } } template template @@ -91,10 +101,11 @@ StepRow::StepRow(const StepRow& a) } template -FullStepRow::FullStepRow(unsigned int n, const eh_HashState& base_state, eh_index i) : - StepRow {n, base_state, i} +FullStepRow::FullStepRow(const eh_HashState& base_state, eh_index i, + size_t hLen, size_t cBitLen, size_t cByteLen) : + StepRow {base_state, i, hLen, cBitLen, cByteLen} { - EhIndexToArray(i, hash+(n/8)); + EhIndexToArray(i, hash+hLen); } template template @@ -154,10 +165,12 @@ bool HasCollision(StepRow& a, StepRow& b, int l) } template -TruncatedStepRow::TruncatedStepRow(unsigned int n, const eh_HashState& base_state, eh_index i, unsigned int ilen) : - StepRow {n, base_state, i} +TruncatedStepRow::TruncatedStepRow(const eh_HashState& base_state, eh_index i, + size_t hLen, size_t cBitLen, size_t cByteLen, + unsigned int ilen) : + StepRow {base_state, i, hLen, cBitLen, cByteLen} { - hash[n/8] = TruncateIndex(i, ilen); + hash[hLen] = TruncateIndex(i, ilen); } template template @@ -201,12 +214,13 @@ bool Equihash::BasicSolve(const eh_HashState& base_state, // 1) Generate first list LogPrint("pow", "Generating first list\n"); - size_t hashLen = N/8; + size_t hashLen = HashLength; size_t lenIndices = sizeof(eh_index); std::vector> X; X.reserve(init_size); for (eh_index i = 0; i < init_size; i++) { - X.emplace_back(N, base_state, i); + X.emplace_back(base_state, i, HashLength, + CollisionBitLength, CollisionByteLength); if (cancelled(ListGeneration)) throw solver_cancelled; } @@ -372,12 +386,13 @@ bool Equihash::OptimisedSolve(const eh_HashState& base_state, // 1) Generate first list LogPrint("pow", "Generating first list\n"); - size_t hashLen = N/8; + size_t hashLen = HashLength; size_t lenIndices = sizeof(eh_trunc); std::vector> Xt; Xt.reserve(init_size); for (eh_index i = 0; i < init_size; i++) { - Xt.emplace_back(N, base_state, i, CollisionBitLength + 1); + Xt.emplace_back(base_state, i, HashLength, CollisionBitLength, + CollisionByteLength, CollisionBitLength + 1); if (cancelled(ListGeneration)) throw solver_cancelled; } @@ -486,13 +501,14 @@ bool Equihash::OptimisedSolve(const eh_HashState& base_state, icv.reserve(recreate_size); for (eh_index j = 0; j < recreate_size; j++) { eh_index newIndex { UntruncateIndex(partialSoln.get()[i], j, CollisionBitLength + 1) }; - icv.emplace_back(N, base_state, newIndex); + icv.emplace_back(base_state, newIndex, HashLength, + CollisionBitLength, CollisionByteLength); if (cancelled(PartialGeneration)) throw solver_cancelled; } boost::optional>> ic = icv; // 2a) For each pair of lists: - hashLen = N/8; + hashLen = HashLength; lenIndices = sizeof(eh_index); size_t rti = i; for (size_t r = 0; r <= K; r++) { @@ -560,10 +576,11 @@ bool Equihash::IsValidSolution(const eh_HashState& base_state, std::vector< std::vector> X; X.reserve(soln_size); for (eh_index i : soln) { - X.emplace_back(N, base_state, i); + X.emplace_back(base_state, i, HashLength, + CollisionBitLength, CollisionByteLength); } - size_t hashLen = N/8; + size_t hashLen = HashLength; size_t lenIndices = sizeof(eh_index); while (X.size() > 1) { std::vector> Xc; diff --git a/src/crypto/equihash.h b/src/crypto/equihash.h index 383e77221..c03b23566 100644 --- a/src/crypto/equihash.h +++ b/src/crypto/equihash.h @@ -38,7 +38,8 @@ protected: unsigned char hash[WIDTH]; public: - StepRow(unsigned int n, const eh_HashState& base_state, eh_index i); + StepRow(const eh_HashState& base_state, eh_index i, + size_t hLen, size_t cBitLen, size_t cByteLen); ~StepRow() { } template @@ -75,7 +76,8 @@ class FullStepRow : public StepRow using StepRow::hash; public: - FullStepRow(unsigned int n, const eh_HashState& base_state, eh_index i); + FullStepRow(const eh_HashState& base_state, eh_index i, + size_t hLen, size_t cBitLen, size_t cByteLen); ~FullStepRow() { } FullStepRow(const FullStepRow& a) : StepRow {a} { } @@ -99,7 +101,9 @@ class TruncatedStepRow : public StepRow using StepRow::hash; public: - TruncatedStepRow(unsigned int n, const eh_HashState& base_state, eh_index i, unsigned int ilen); + TruncatedStepRow(const eh_HashState& base_state, eh_index i, + size_t hLen, size_t cBitLen, size_t cByteLen, + unsigned int ilen); ~TruncatedStepRow() { } TruncatedStepRow(const TruncatedStepRow& a) : StepRow {a} { } @@ -141,16 +145,16 @@ class Equihash private: BOOST_STATIC_ASSERT(K < N); BOOST_STATIC_ASSERT(N % 8 == 0); - BOOST_STATIC_ASSERT((N/(K+1)) % 8 == 0); BOOST_STATIC_ASSERT((N/(K+1)) + 1 < 8*sizeof(eh_index)); public: enum { CollisionBitLength=N/(K+1) }; - enum { CollisionByteLength=CollisionBitLength/8 }; + enum : size_t { CollisionByteLength=(CollisionBitLength+7)/8 }; + enum : size_t { HashLength=(K+1)*CollisionByteLength }; enum : size_t { FullWidth=2*CollisionByteLength+sizeof(eh_index)*(1 << (K-1)) }; enum : size_t { FinalFullWidth=2*CollisionByteLength+sizeof(eh_index)*(1 << (K)) }; - enum : size_t { TruncatedWidth=max((N/8)+sizeof(eh_trunc), 2*CollisionByteLength+sizeof(eh_trunc)*(1 << (K-1))) }; - enum : size_t { FinalTruncatedWidth=max((N/8)+sizeof(eh_trunc), 2*CollisionByteLength+sizeof(eh_trunc)*(1 << (K))) }; + enum : size_t { TruncatedWidth=max(HashLength+sizeof(eh_trunc), 2*CollisionByteLength+sizeof(eh_trunc)*(1 << (K-1))) }; + enum : size_t { FinalTruncatedWidth=max(HashLength+sizeof(eh_trunc), 2*CollisionByteLength+sizeof(eh_trunc)*(1 << (K))) }; Equihash() { }