From 39f5cb35f96d9c16061880b1c8d4cfa18c9f5e28 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 4 May 2016 13:47:49 +1200 Subject: [PATCH] Store truncated indices in the same char* as the hash (H/T tromp for the idea!) --- src/crypto/equihash.cpp | 66 +++++++++++++++++++++++++++++++---------- src/crypto/equihash.h | 11 +++---- 2 files changed, 57 insertions(+), 20 deletions(-) diff --git a/src/crypto/equihash.cpp b/src/crypto/equihash.cpp index ae6585fb0..1511d383a 100644 --- a/src/crypto/equihash.cpp +++ b/src/crypto/equihash.cpp @@ -172,19 +172,33 @@ bool IsValidBranch(const FullStepRow& a, const unsigned int ilen, const eh_trunc TruncatedStepRow::TruncatedStepRow(unsigned int n, const eh_HashState& base_state, eh_index i, unsigned int ilen) : StepRow {n, base_state, i}, - indices {TruncateIndex(i, ilen)} + lenIndices {1} { - assert(indices.size() == 1); + unsigned char* p = new unsigned char[len+lenIndices]; + std::copy(hash, hash+len, p); + p[len] = TruncateIndex(i, ilen); + delete[] hash; + hash = p; +} + +TruncatedStepRow::TruncatedStepRow(const TruncatedStepRow& a) : + StepRow {a}, + lenIndices {a.lenIndices} +{ + unsigned char* p = new unsigned char[a.len+a.lenIndices]; + std::copy(a.hash, a.hash+a.len+a.lenIndices, p); + delete[] hash; + hash = p; } TruncatedStepRow& TruncatedStepRow::operator=(const TruncatedStepRow& a) { - unsigned char* p = new unsigned char[a.len]; - std::copy(a.hash, a.hash+a.len, p); + unsigned char* p = new unsigned char[a.len+a.lenIndices]; + std::copy(a.hash, a.hash+a.len+a.lenIndices, p); delete[] hash; hash = p; len = a.len; - indices = a.indices; + lenIndices = a.lenIndices; return *this; } @@ -193,19 +207,37 @@ TruncatedStepRow& TruncatedStepRow::operator^=(const TruncatedStepRow& a) if (a.len != len) { throw std::invalid_argument("Hash length differs"); } - if (a.indices.size() != indices.size()) { + if (a.lenIndices != lenIndices) { throw std::invalid_argument("Number of indices differs"); } - unsigned char* p = new unsigned char[len]; + unsigned char* p = new unsigned char[len+lenIndices+a.lenIndices]; for (int i = 0; i < len; i++) p[i] = hash[i] ^ a.hash[i]; + std::copy(hash+len, hash+len+lenIndices, p+len); + std::copy(a.hash+a.len, a.hash+a.len+a.lenIndices, p+len+lenIndices); delete[] hash; hash = p; - indices.reserve(indices.size() + a.indices.size()); - indices.insert(indices.end(), a.indices.begin(), a.indices.end()); + lenIndices += a.lenIndices; return *this; } +void TruncatedStepRow::TrimHash(int l) +{ + unsigned char* p = new unsigned char[len-l+lenIndices]; + std::copy(hash+l, hash+len+lenIndices, p); + delete[] hash; + hash = p; + len -= l; +} + +eh_trunc* TruncatedStepRow::GetPartialSolution(eh_index soln_size) const +{ + assert(lenIndices == soln_size); + eh_trunc* p = new eh_trunc[lenIndices]; + std::copy(hash+len, hash+len+lenIndices, p); + return p; +} + Equihash::Equihash(unsigned int n, unsigned int k) : n(n), k(k) { @@ -358,7 +390,8 @@ std::set> Equihash::OptimisedSolve(const eh_HashState& bas // First run the algorithm with truncated indices - std::vector> partialSolns; + eh_index soln_size { 1 << k }; + std::vector partialSolns; { // 1) Generate first list @@ -431,7 +464,7 @@ std::set> Equihash::OptimisedSolve(const eh_HashState& bas for (int i = 0; i < Xt.size() - 1; i++) { TruncatedStepRow res = Xt[i] ^ Xt[i+1]; if (res.IsZero()) { - partialSolns.push_back(res.GetPartialSolution()); + partialSolns.push_back(res.GetPartialSolution(soln_size)); } } } else @@ -446,11 +479,11 @@ std::set> Equihash::OptimisedSolve(const eh_HashState& bas std::set> solns; eh_index recreate_size { UntruncateIndex(1, 0, CollisionBitLength() + 1) }; int invalidCount = 0; - for (std::vector partialSoln : partialSolns) { + for (eh_trunc* partialSoln : partialSolns) { // 1) Generate first list of possibilities std::vector> X; - X.reserve(partialSoln.size()); - for (int i = 0; i < partialSoln.size(); i++) { + X.reserve(soln_size); + for (eh_index i = 0; i < soln_size; i++) { std::vector ic; ic.reserve(recreate_size); for (eh_index j = 0; j < recreate_size; j++) { @@ -489,10 +522,13 @@ std::set> Equihash::OptimisedSolve(const eh_HashState& bas for (FullStepRow row : X[0]) { solns.insert(row.GetSolution()); } - continue; + goto deletesolution; invalidsolution: invalidCount++; + +deletesolution: + delete[] partialSoln; } LogPrint("pow", "- Number of invalid solutions found: %d\n", invalidCount); diff --git a/src/crypto/equihash.h b/src/crypto/equihash.h index 32ae011c5..a94c149af 100644 --- a/src/crypto/equihash.h +++ b/src/crypto/equihash.h @@ -76,21 +76,22 @@ bool IsValidBranch(const FullStepRow& a, const unsigned int ilen, const eh_trunc class TruncatedStepRow : public StepRow { private: - std::vector indices; + unsigned int lenIndices; public: TruncatedStepRow(unsigned int n, const eh_HashState& base_state, eh_index i, unsigned int ilen); ~TruncatedStepRow() { } - TruncatedStepRow(const TruncatedStepRow& a) : StepRow {a}, indices(a.indices) { } + TruncatedStepRow(const TruncatedStepRow& a); TruncatedStepRow& operator=(const TruncatedStepRow& a); TruncatedStepRow& operator^=(const TruncatedStepRow& a); - bool IndicesBefore(const TruncatedStepRow& a) { return indices[0] < a.indices[0]; } - std::vector GetPartialSolution() { return std::vector(indices); } + void TrimHash(int l); + inline bool IndicesBefore(const TruncatedStepRow& a) const { return memcmp(hash+len, a.hash+a.len, lenIndices) < 0; } + eh_trunc* GetPartialSolution(eh_index soln_size) const; friend inline const TruncatedStepRow operator^(const TruncatedStepRow& a, const TruncatedStepRow& b) { - if (a.indices[0] < b.indices[0]) { return TruncatedStepRow(a) ^= b; } + if (a.IndicesBefore(b)) { return TruncatedStepRow(a) ^= b; } else { return TruncatedStepRow(b) ^= a; } } };