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:
zkbot 2016-08-05 16:53:28 +00:00
commit 76470978f4
2 changed files with 44 additions and 23 deletions

View File

@ -72,7 +72,8 @@ eh_index UntruncateIndex(const eh_trunc t, const eh_index r, const unsigned int
}
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;
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);
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<size_t WIDTH> template<size_t W>
@ -91,10 +101,11 @@ StepRow<WIDTH>::StepRow(const StepRow<W>& a)
}
template<size_t WIDTH>
FullStepRow<WIDTH>::FullStepRow(unsigned int n, const eh_HashState& base_state, eh_index i) :
StepRow<WIDTH> {n, base_state, i}
FullStepRow<WIDTH>::FullStepRow(const eh_HashState& base_state, eh_index 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>
@ -154,10 +165,12 @@ bool HasCollision(StepRow<WIDTH>& a, StepRow<WIDTH>& b, int l)
}
template<size_t WIDTH>
TruncatedStepRow<WIDTH>::TruncatedStepRow(unsigned int n, const eh_HashState& base_state, eh_index i, unsigned int ilen) :
StepRow<WIDTH> {n, base_state, i}
TruncatedStepRow<WIDTH>::TruncatedStepRow(const eh_HashState& base_state, eh_index 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>
@ -201,12 +214,13 @@ bool Equihash<N,K>::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<FullStepRow<FullWidth>> 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<N,K>::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<TruncatedStepRow<TruncatedWidth>> 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<N,K>::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<std::vector<FullStepRow<FinalFullWidth>>> 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<N,K>::IsValidSolution(const eh_HashState& base_state, std::vector<
std::vector<FullStepRow<FinalFullWidth>> 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<FullStepRow<FinalFullWidth>> Xc;

View File

@ -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<size_t W>
@ -75,7 +76,8 @@ class FullStepRow : public StepRow<WIDTH>
using StepRow<WIDTH>::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<WIDTH>& a) : StepRow<WIDTH> {a} { }
@ -99,7 +101,9 @@ class TruncatedStepRow : public StepRow<WIDTH>
using StepRow<WIDTH>::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<WIDTH>& a) : StepRow<WIDTH> {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() { }