Store the Equihash solution in minimal representation in the block header
The genesis blocks and miner tests have been regenerated, because changing the block header serialisation format changes the block hash, and thus validity. The Equihash solutions have been removed from the bloom test inputs for simplicity (block validity is not checked there; only a valid serialisation is necessary).
This commit is contained in:
@@ -165,6 +165,39 @@ eh_index UntruncateIndex(const eh_trunc t, const eh_index r, const unsigned int
|
||||
return (i << (ilen - 8)) | r;
|
||||
}
|
||||
|
||||
std::vector<eh_index> GetIndicesFromMinimal(std::vector<unsigned char> minimal,
|
||||
size_t cBitLen)
|
||||
{
|
||||
assert(((cBitLen+1)+7)/8 <= sizeof(eh_index));
|
||||
size_t lenIndices { 8*sizeof(eh_index)*minimal.size()/(cBitLen+1) };
|
||||
size_t bytePad { sizeof(eh_index) - ((cBitLen+1)+7)/8 };
|
||||
std::vector<unsigned char> array(lenIndices);
|
||||
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)) {
|
||||
ret.push_back(ArrayToEhIndex(array.data()+i));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> GetMinimalFromIndices(std::vector<eh_index> indices,
|
||||
size_t cBitLen)
|
||||
{
|
||||
assert(((cBitLen+1)+7)/8 <= sizeof(eh_index));
|
||||
size_t lenIndices { indices.size()*sizeof(eh_index) };
|
||||
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++) {
|
||||
EhIndexToArray(indices[i], array.data()+(i*sizeof(eh_index)));
|
||||
}
|
||||
std::vector<unsigned char> ret(minLen);
|
||||
CompressArray(array.data(), lenIndices,
|
||||
ret.data(), minLen, cBitLen+1, bytePad);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<size_t WIDTH>
|
||||
StepRow<WIDTH>::StepRow(const unsigned char* hashIn, size_t hInLen,
|
||||
size_t hLen, size_t cBitLen)
|
||||
@@ -224,12 +257,14 @@ bool StepRow<WIDTH>::IsZero(size_t len)
|
||||
}
|
||||
|
||||
template<size_t WIDTH>
|
||||
std::vector<eh_index> FullStepRow<WIDTH>::GetIndices(size_t len, size_t lenIndices) const
|
||||
std::vector<unsigned char> FullStepRow<WIDTH>::GetIndices(size_t len, size_t lenIndices,
|
||||
size_t cBitLen) const
|
||||
{
|
||||
std::vector<eh_index> ret;
|
||||
for (int i = 0; i < lenIndices; i += sizeof(eh_index)) {
|
||||
ret.push_back(ArrayToEhIndex(hash+len+i));
|
||||
}
|
||||
assert(((cBitLen+1)+7)/8 <= sizeof(eh_index));
|
||||
size_t minLen { (cBitLen+1)*lenIndices/(8*sizeof(eh_index)) };
|
||||
size_t bytePad { sizeof(eh_index) - ((cBitLen+1)+7)/8 };
|
||||
std::vector<unsigned char> ret(minLen);
|
||||
CompressArray(hash+len, lenIndices, ret.data(), minLen, cBitLen+1, bytePad);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -287,7 +322,7 @@ std::shared_ptr<eh_trunc> TruncatedStepRow<WIDTH>::GetTruncatedIndices(size_t le
|
||||
|
||||
template<unsigned int N, unsigned int K>
|
||||
bool Equihash<N,K>::BasicSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<eh_index>)> validBlock,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled)
|
||||
{
|
||||
eh_index init_size { 1 << (CollisionBitLength + 1) };
|
||||
@@ -386,7 +421,8 @@ bool Equihash<N,K>::BasicSolve(const eh_HashState& base_state,
|
||||
for (int 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) &&
|
||||
validBlock(res.GetIndices(hashLen, 2*lenIndices))) {
|
||||
validBlock(res.GetIndices(hashLen, 2*lenIndices,
|
||||
CollisionBitLength))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -455,7 +491,7 @@ 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<eh_index>)> validBlock,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled)
|
||||
{
|
||||
eh_index init_size { 1 << (CollisionBitLength + 1) };
|
||||
@@ -589,7 +625,7 @@ bool Equihash<N,K>::OptimisedSolve(const eh_HashState& base_state,
|
||||
// Now for each solution run the algorithm again to recreate the indices
|
||||
LogPrint("pow", "Culling solutions\n");
|
||||
for (std::shared_ptr<eh_trunc> partialSoln : partialSolns) {
|
||||
std::set<std::vector<eh_index>> solns;
|
||||
std::set<std::vector<unsigned char>> solns;
|
||||
size_t hashLen;
|
||||
size_t lenIndices;
|
||||
unsigned char tmpHash[HashOutput];
|
||||
@@ -656,7 +692,7 @@ bool Equihash<N,K>::OptimisedSolve(const eh_HashState& base_state,
|
||||
// We are at the top of the tree
|
||||
assert(X.size() == K+1);
|
||||
for (FullStepRow<FinalFullWidth> row : *X[K]) {
|
||||
solns.insert(row.GetIndices(hashLen, lenIndices));
|
||||
solns.insert(row.GetIndices(hashLen, lenIndices, CollisionBitLength));
|
||||
}
|
||||
for (auto soln : solns) {
|
||||
if (validBlock(soln))
|
||||
@@ -674,18 +710,18 @@ invalidsolution:
|
||||
}
|
||||
|
||||
template<unsigned int N, unsigned int K>
|
||||
bool Equihash<N,K>::IsValidSolution(const eh_HashState& base_state, std::vector<eh_index> soln)
|
||||
bool Equihash<N,K>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln)
|
||||
{
|
||||
eh_index soln_size { 1u << K };
|
||||
if (soln.size() != soln_size) {
|
||||
LogPrint("pow", "Invalid solution size: %d\n", soln.size());
|
||||
if (soln.size() != SolutionWidth) {
|
||||
LogPrint("pow", "Invalid solution length: %d (expected %d)\n",
|
||||
soln.size(), SolutionWidth);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<FullStepRow<FinalFullWidth>> X;
|
||||
X.reserve(soln_size);
|
||||
X.reserve(1 << K);
|
||||
unsigned char tmpHash[HashOutput];
|
||||
for (eh_index i : soln) {
|
||||
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);
|
||||
@@ -724,39 +760,39 @@ bool Equihash<N,K>::IsValidSolution(const eh_HashState& base_state, std::vector<
|
||||
// Explicit instantiations for Equihash<96,3>
|
||||
template int Equihash<96,3>::InitialiseState(eh_HashState& base_state);
|
||||
template bool Equihash<96,3>::BasicSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<eh_index>)> validBlock,
|
||||
const std::function<bool(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<eh_index>)> validBlock,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
template bool Equihash<96,3>::IsValidSolution(const eh_HashState& base_state, std::vector<eh_index> soln);
|
||||
template bool Equihash<96,3>::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);
|
||||
template bool Equihash<200,9>::BasicSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<eh_index>)> validBlock,
|
||||
const std::function<bool(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<eh_index>)> validBlock,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
template bool Equihash<200,9>::IsValidSolution(const eh_HashState& base_state, std::vector<eh_index> soln);
|
||||
template bool Equihash<200,9>::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 bool Equihash<96,5>::BasicSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<eh_index>)> validBlock,
|
||||
const std::function<bool(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<eh_index>)> validBlock,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
template bool Equihash<96,5>::IsValidSolution(const eh_HashState& base_state, std::vector<eh_index> soln);
|
||||
template bool Equihash<96,5>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln);
|
||||
|
||||
// Explicit instantiations for Equihash<48,5>
|
||||
template int Equihash<48,5>::InitialiseState(eh_HashState& base_state);
|
||||
template bool Equihash<48,5>::BasicSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<eh_index>)> validBlock,
|
||||
const std::function<bool(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<eh_index>)> validBlock,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
template bool Equihash<48,5>::IsValidSolution(const eh_HashState& base_state, std::vector<eh_index> soln);
|
||||
template bool Equihash<48,5>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln);
|
||||
|
||||
@@ -34,6 +34,11 @@ void CompressArray(const unsigned char* in, size_t in_len,
|
||||
eh_index ArrayToEhIndex(const unsigned char* array);
|
||||
eh_trunc TruncateIndex(const eh_index i, const unsigned int ilen);
|
||||
|
||||
std::vector<eh_index> GetIndicesFromMinimal(std::vector<unsigned char> minimal,
|
||||
size_t cBitLen);
|
||||
std::vector<unsigned char> GetMinimalFromIndices(std::vector<eh_index> indices,
|
||||
size_t cBitLen);
|
||||
|
||||
template<size_t WIDTH>
|
||||
class StepRow
|
||||
{
|
||||
@@ -93,9 +98,13 @@ public:
|
||||
FullStepRow& operator=(const FullStepRow<WIDTH>& a);
|
||||
|
||||
inline bool IndicesBefore(const FullStepRow<WIDTH>& a, size_t len, size_t lenIndices) const { return memcmp(hash+len, a.hash+len, lenIndices) < 0; }
|
||||
std::vector<eh_index> GetIndices(size_t len, size_t lenIndices) const;
|
||||
std::vector<unsigned char> GetIndices(size_t len, size_t lenIndices,
|
||||
size_t cBitLen) const;
|
||||
|
||||
template<size_t W>
|
||||
friend bool DistinctIndices(const FullStepRow<W>& a, const FullStepRow<W>& b,
|
||||
size_t len, size_t lenIndices);
|
||||
template<size_t W>
|
||||
friend bool IsValidBranch(const FullStepRow<W>& a, const size_t len, const unsigned int ilen, const eh_trunc t);
|
||||
};
|
||||
|
||||
@@ -164,17 +173,18 @@ public:
|
||||
enum : size_t { FinalFullWidth=2*CollisionByteLength+sizeof(eh_index)*(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))) };
|
||||
enum : size_t { SolutionWidth=(1 << K)*(CollisionBitLength+1)/8 };
|
||||
|
||||
Equihash() { }
|
||||
|
||||
int InitialiseState(eh_HashState& base_state);
|
||||
bool BasicSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<eh_index>)> validBlock,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
bool OptimisedSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<eh_index>)> validBlock,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
bool IsValidSolution(const eh_HashState& base_state, std::vector<eh_index> soln);
|
||||
bool IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln);
|
||||
};
|
||||
|
||||
#include "equihash.tcc"
|
||||
@@ -198,7 +208,7 @@ static Equihash<48,5> Eh48_5;
|
||||
}
|
||||
|
||||
inline bool EhBasicSolve(unsigned int n, unsigned int k, const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<eh_index>)> validBlock,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled)
|
||||
{
|
||||
if (n == 96 && k == 3) {
|
||||
@@ -215,14 +225,14 @@ inline bool EhBasicSolve(unsigned int n, unsigned int k, const eh_HashState& bas
|
||||
}
|
||||
|
||||
inline bool EhBasicSolveUncancellable(unsigned int n, unsigned int k, const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<eh_index>)> validBlock)
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock)
|
||||
{
|
||||
return EhBasicSolve(n, k, base_state, validBlock,
|
||||
[](EhSolverCancelCheck pos) { return false; });
|
||||
}
|
||||
|
||||
inline bool EhOptimisedSolve(unsigned int n, unsigned int k, const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<eh_index>)> validBlock,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled)
|
||||
{
|
||||
if (n == 96 && k == 3) {
|
||||
@@ -239,7 +249,7 @@ inline bool EhOptimisedSolve(unsigned int n, unsigned int k, const eh_HashState&
|
||||
}
|
||||
|
||||
inline bool EhOptimisedSolveUncancellable(unsigned int n, unsigned int k, const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<eh_index>)> validBlock)
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock)
|
||||
{
|
||||
return EhOptimisedSolve(n, k, base_state, validBlock,
|
||||
[](EhSolverCancelCheck pos) { return false; });
|
||||
|
||||
@@ -10,11 +10,9 @@
|
||||
template<size_t WIDTH>
|
||||
bool DistinctIndices(const FullStepRow<WIDTH>& a, const FullStepRow<WIDTH>& b, size_t len, size_t lenIndices)
|
||||
{
|
||||
std::vector<eh_index> vIndicesA = a.GetIndices(len, lenIndices);
|
||||
std::vector<eh_index> vIndicesB = b.GetIndices(len, lenIndices);
|
||||
for(auto const& value1: vIndicesA) {
|
||||
for(auto const& value2: vIndicesB) {
|
||||
if (value1==value2) {
|
||||
for(size_t i = 0; i < lenIndices; i += sizeof(eh_index)) {
|
||||
for(size_t j = 0; j < lenIndices; j += sizeof(eh_index)) {
|
||||
if (memcmp(a.hash+len+i, b.hash+len+j, sizeof(eh_index)) == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user