Auto merge of #1172 - str4d:1148-remove-equihash-collision-length-assumption, r=bitcartel
Remove the assumption that n/(k+1) is a multiple of 8 This version works, but generates the initial rows in a way that is probably not what we want to specify. Closes #1148
This commit is contained in:
@@ -72,7 +72,8 @@ eh_index UntruncateIndex(const eh_trunc t, const eh_index r, const unsigned int
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<size_t WIDTH>
|
template<size_t WIDTH>
|
||||||
StepRow<WIDTH>::StepRow(unsigned int n, const eh_HashState& base_state, eh_index i)
|
StepRow<WIDTH>::StepRow(const eh_HashState& base_state, eh_index i,
|
||||||
|
size_t hLen, size_t cBitLen, size_t cByteLen)
|
||||||
{
|
{
|
||||||
eh_HashState state;
|
eh_HashState state;
|
||||||
state = base_state;
|
state = base_state;
|
||||||
@@ -80,7 +81,16 @@ StepRow<WIDTH>::StepRow(unsigned int n, const eh_HashState& base_state, eh_index
|
|||||||
eh_index lei = htole32(i);
|
eh_index lei = htole32(i);
|
||||||
memcpy(array, &lei, sizeof(eh_index));
|
memcpy(array, &lei, sizeof(eh_index));
|
||||||
crypto_generichash_blake2b_update(&state, array, 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<size_t WIDTH> template<size_t W>
|
template<size_t WIDTH> template<size_t W>
|
||||||
@@ -91,10 +101,11 @@ StepRow<WIDTH>::StepRow(const StepRow<W>& a)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<size_t WIDTH>
|
template<size_t WIDTH>
|
||||||
FullStepRow<WIDTH>::FullStepRow(unsigned int n, const eh_HashState& base_state, eh_index i) :
|
FullStepRow<WIDTH>::FullStepRow(const eh_HashState& base_state, eh_index i,
|
||||||
StepRow<WIDTH> {n, base_state, i}
|
size_t hLen, size_t cBitLen, size_t cByteLen) :
|
||||||
|
StepRow<WIDTH> {base_state, i, hLen, cBitLen, cByteLen}
|
||||||
{
|
{
|
||||||
EhIndexToArray(i, hash+(n/8));
|
EhIndexToArray(i, hash+hLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t WIDTH> template<size_t W>
|
template<size_t WIDTH> template<size_t W>
|
||||||
@@ -154,10 +165,12 @@ bool HasCollision(StepRow<WIDTH>& a, StepRow<WIDTH>& b, int l)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<size_t WIDTH>
|
template<size_t WIDTH>
|
||||||
TruncatedStepRow<WIDTH>::TruncatedStepRow(unsigned int n, const eh_HashState& base_state, eh_index i, unsigned int ilen) :
|
TruncatedStepRow<WIDTH>::TruncatedStepRow(const eh_HashState& base_state, eh_index i,
|
||||||
StepRow<WIDTH> {n, base_state, i}
|
size_t hLen, size_t cBitLen, size_t cByteLen,
|
||||||
|
unsigned int ilen) :
|
||||||
|
StepRow<WIDTH> {base_state, i, hLen, cBitLen, cByteLen}
|
||||||
{
|
{
|
||||||
hash[n/8] = TruncateIndex(i, ilen);
|
hash[hLen] = TruncateIndex(i, ilen);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t WIDTH> template<size_t W>
|
template<size_t WIDTH> template<size_t W>
|
||||||
@@ -201,12 +214,13 @@ bool Equihash<N,K>::BasicSolve(const eh_HashState& base_state,
|
|||||||
|
|
||||||
// 1) Generate first list
|
// 1) Generate first list
|
||||||
LogPrint("pow", "Generating first list\n");
|
LogPrint("pow", "Generating first list\n");
|
||||||
size_t hashLen = N/8;
|
size_t hashLen = HashLength;
|
||||||
size_t lenIndices = sizeof(eh_index);
|
size_t lenIndices = sizeof(eh_index);
|
||||||
std::vector<FullStepRow<FullWidth>> X;
|
std::vector<FullStepRow<FullWidth>> X;
|
||||||
X.reserve(init_size);
|
X.reserve(init_size);
|
||||||
for (eh_index i = 0; i < init_size; i++) {
|
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;
|
if (cancelled(ListGeneration)) throw solver_cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,12 +386,13 @@ bool Equihash<N,K>::OptimisedSolve(const eh_HashState& base_state,
|
|||||||
|
|
||||||
// 1) Generate first list
|
// 1) Generate first list
|
||||||
LogPrint("pow", "Generating first list\n");
|
LogPrint("pow", "Generating first list\n");
|
||||||
size_t hashLen = N/8;
|
size_t hashLen = HashLength;
|
||||||
size_t lenIndices = sizeof(eh_trunc);
|
size_t lenIndices = sizeof(eh_trunc);
|
||||||
std::vector<TruncatedStepRow<TruncatedWidth>> Xt;
|
std::vector<TruncatedStepRow<TruncatedWidth>> Xt;
|
||||||
Xt.reserve(init_size);
|
Xt.reserve(init_size);
|
||||||
for (eh_index i = 0; i < init_size; i++) {
|
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;
|
if (cancelled(ListGeneration)) throw solver_cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,13 +501,14 @@ bool Equihash<N,K>::OptimisedSolve(const eh_HashState& base_state,
|
|||||||
icv.reserve(recreate_size);
|
icv.reserve(recreate_size);
|
||||||
for (eh_index j = 0; j < recreate_size; j++) {
|
for (eh_index j = 0; j < recreate_size; j++) {
|
||||||
eh_index newIndex { UntruncateIndex(partialSoln.get()[i], j, CollisionBitLength + 1) };
|
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;
|
if (cancelled(PartialGeneration)) throw solver_cancelled;
|
||||||
}
|
}
|
||||||
boost::optional<std::vector<FullStepRow<FinalFullWidth>>> ic = icv;
|
boost::optional<std::vector<FullStepRow<FinalFullWidth>>> ic = icv;
|
||||||
|
|
||||||
// 2a) For each pair of lists:
|
// 2a) For each pair of lists:
|
||||||
hashLen = N/8;
|
hashLen = HashLength;
|
||||||
lenIndices = sizeof(eh_index);
|
lenIndices = sizeof(eh_index);
|
||||||
size_t rti = i;
|
size_t rti = i;
|
||||||
for (size_t r = 0; r <= K; r++) {
|
for (size_t r = 0; r <= K; r++) {
|
||||||
@@ -560,10 +576,11 @@ bool Equihash<N,K>::IsValidSolution(const eh_HashState& base_state, std::vector<
|
|||||||
std::vector<FullStepRow<FinalFullWidth>> X;
|
std::vector<FullStepRow<FinalFullWidth>> X;
|
||||||
X.reserve(soln_size);
|
X.reserve(soln_size);
|
||||||
for (eh_index i : soln) {
|
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);
|
size_t lenIndices = sizeof(eh_index);
|
||||||
while (X.size() > 1) {
|
while (X.size() > 1) {
|
||||||
std::vector<FullStepRow<FinalFullWidth>> Xc;
|
std::vector<FullStepRow<FinalFullWidth>> Xc;
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ protected:
|
|||||||
unsigned char hash[WIDTH];
|
unsigned char hash[WIDTH];
|
||||||
|
|
||||||
public:
|
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() { }
|
~StepRow() { }
|
||||||
|
|
||||||
template<size_t W>
|
template<size_t W>
|
||||||
@@ -75,7 +76,8 @@ class FullStepRow : public StepRow<WIDTH>
|
|||||||
using StepRow<WIDTH>::hash;
|
using StepRow<WIDTH>::hash;
|
||||||
|
|
||||||
public:
|
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() { }
|
||||||
|
|
||||||
FullStepRow(const FullStepRow<WIDTH>& a) : StepRow<WIDTH> {a} { }
|
FullStepRow(const FullStepRow<WIDTH>& a) : StepRow<WIDTH> {a} { }
|
||||||
@@ -99,7 +101,9 @@ class TruncatedStepRow : public StepRow<WIDTH>
|
|||||||
using StepRow<WIDTH>::hash;
|
using StepRow<WIDTH>::hash;
|
||||||
|
|
||||||
public:
|
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() { }
|
||||||
|
|
||||||
TruncatedStepRow(const TruncatedStepRow<WIDTH>& a) : StepRow<WIDTH> {a} { }
|
TruncatedStepRow(const TruncatedStepRow<WIDTH>& a) : StepRow<WIDTH> {a} { }
|
||||||
@@ -141,16 +145,16 @@ class Equihash
|
|||||||
private:
|
private:
|
||||||
BOOST_STATIC_ASSERT(K < N);
|
BOOST_STATIC_ASSERT(K < N);
|
||||||
BOOST_STATIC_ASSERT(N % 8 == 0);
|
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));
|
BOOST_STATIC_ASSERT((N/(K+1)) + 1 < 8*sizeof(eh_index));
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum { CollisionBitLength=N/(K+1) };
|
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 { FullWidth=2*CollisionByteLength+sizeof(eh_index)*(1 << (K-1)) };
|
||||||
enum : size_t { FinalFullWidth=2*CollisionByteLength+sizeof(eh_index)*(1 << (K)) };
|
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 { TruncatedWidth=max(HashLength+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 { FinalTruncatedWidth=max(HashLength+sizeof(eh_trunc), 2*CollisionByteLength+sizeof(eh_trunc)*(1 << (K))) };
|
||||||
|
|
||||||
Equihash() { }
|
Equihash() { }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user