Use template parameters to statically initialise Equihash
This commit is contained in:
@@ -19,31 +19,18 @@
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
void validate_params(int n, int k)
|
||||
{
|
||||
if (k>=n) {
|
||||
std::cerr << "n must be larger than k\n";
|
||||
throw invalid_params();
|
||||
}
|
||||
if (n % 8 != 0) {
|
||||
std::cerr << "Parameters must satisfy n = 0 mod 8\n";
|
||||
throw invalid_params();
|
||||
}
|
||||
if ((n/(k+1)) % 8 != 0) {
|
||||
std::cerr << "Parameters must satisfy n/(k+1) = 0 mod 8\n";
|
||||
throw invalid_params();
|
||||
}
|
||||
}
|
||||
|
||||
int Equihash::InitialiseState(eh_HashState& base_state)
|
||||
template<unsigned int N, unsigned int K>
|
||||
int Equihash<N,K>::InitialiseState(eh_HashState& base_state)
|
||||
{
|
||||
unsigned int n = N;
|
||||
unsigned int k = K;
|
||||
unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {};
|
||||
memcpy(personalization, "ZcashPOW", 8);
|
||||
memcpy(personalization+8, &n, 4);
|
||||
memcpy(personalization+12, &k, 4);
|
||||
return crypto_generichash_blake2b_init_salt_personal(&base_state,
|
||||
NULL, 0, // No key.
|
||||
n/8,
|
||||
N/8,
|
||||
NULL, // No salt.
|
||||
personalization);
|
||||
}
|
||||
@@ -238,27 +225,21 @@ eh_trunc* TruncatedStepRow::GetPartialSolution(eh_index soln_size) const
|
||||
return p;
|
||||
}
|
||||
|
||||
Equihash::Equihash(unsigned int n, unsigned int k) :
|
||||
n(n), k(k)
|
||||
template<unsigned int N, unsigned int K>
|
||||
std::set<std::vector<eh_index>> Equihash<N,K>::BasicSolve(const eh_HashState& base_state)
|
||||
{
|
||||
validate_params(n, k);
|
||||
}
|
||||
|
||||
std::set<std::vector<eh_index>> Equihash::BasicSolve(const eh_HashState& base_state)
|
||||
{
|
||||
assert(CollisionBitLength() + 1 < 8*sizeof(eh_index));
|
||||
eh_index init_size { 1 << (CollisionBitLength() + 1) };
|
||||
eh_index init_size { 1 << (CollisionBitLength + 1) };
|
||||
|
||||
// 1) Generate first list
|
||||
LogPrint("pow", "Generating first list\n");
|
||||
std::vector<FullStepRow> X;
|
||||
X.reserve(init_size);
|
||||
for (eh_index i = 0; i < init_size; i++) {
|
||||
X.emplace_back(n, base_state, i);
|
||||
X.emplace_back(N, base_state, i);
|
||||
}
|
||||
|
||||
// 3) Repeat step 2 until 2n/(k+1) bits remain
|
||||
for (int r = 1; r < k && X.size() > 0; r++) {
|
||||
for (int r = 1; r < K && X.size() > 0; r++) {
|
||||
LogPrint("pow", "Round %d:\n", r);
|
||||
// 2a) Sort the list
|
||||
LogPrint("pow", "- Sorting list\n");
|
||||
@@ -272,7 +253,7 @@ std::set<std::vector<eh_index>> Equihash::BasicSolve(const eh_HashState& base_st
|
||||
// 2b) Find next set of unordered pairs with collisions on the next n/(k+1) bits
|
||||
int j = 1;
|
||||
while (i+j < X.size() &&
|
||||
HasCollision(X[i], X[i+j], CollisionByteLength())) {
|
||||
HasCollision(X[i], X[i+j], CollisionByteLength)) {
|
||||
j++;
|
||||
}
|
||||
|
||||
@@ -281,7 +262,7 @@ std::set<std::vector<eh_index>> Equihash::BasicSolve(const eh_HashState& base_st
|
||||
for (int m = l + 1; m < j; m++) {
|
||||
if (DistinctIndices(X[i+l], X[i+m])) {
|
||||
Xc.push_back(X[i+l] ^ X[i+m]);
|
||||
Xc.back().TrimHash(CollisionByteLength());
|
||||
Xc.back().TrimHash(CollisionByteLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -383,14 +364,14 @@ void CollideBranches(std::vector<FullStepRow>& X, const unsigned int clen, const
|
||||
}
|
||||
}
|
||||
|
||||
std::set<std::vector<eh_index>> Equihash::OptimisedSolve(const eh_HashState& base_state)
|
||||
template<unsigned int N, unsigned int K>
|
||||
std::set<std::vector<eh_index>> Equihash<N,K>::OptimisedSolve(const eh_HashState& base_state)
|
||||
{
|
||||
assert(CollisionBitLength() + 1 < 8*sizeof(eh_index));
|
||||
eh_index init_size { 1 << (CollisionBitLength() + 1) };
|
||||
eh_index init_size { 1 << (CollisionBitLength + 1) };
|
||||
|
||||
// First run the algorithm with truncated indices
|
||||
|
||||
eh_index soln_size { 1 << k };
|
||||
eh_index soln_size { 1 << K };
|
||||
std::vector<eh_trunc*> partialSolns;
|
||||
{
|
||||
|
||||
@@ -399,11 +380,11 @@ std::set<std::vector<eh_index>> Equihash::OptimisedSolve(const eh_HashState& bas
|
||||
std::vector<TruncatedStepRow> 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(N, base_state, i, CollisionBitLength + 1);
|
||||
}
|
||||
|
||||
// 3) Repeat step 2 until 2n/(k+1) bits remain
|
||||
for (int r = 1; r < k && Xt.size() > 0; r++) {
|
||||
for (int r = 1; r < K && Xt.size() > 0; r++) {
|
||||
LogPrint("pow", "Round %d:\n", r);
|
||||
// 2a) Sort the list
|
||||
LogPrint("pow", "- Sorting list\n");
|
||||
@@ -417,7 +398,7 @@ std::set<std::vector<eh_index>> Equihash::OptimisedSolve(const eh_HashState& bas
|
||||
// 2b) Find next set of unordered pairs with collisions on the next n/(k+1) bits
|
||||
int j = 1;
|
||||
while (i+j < Xt.size() &&
|
||||
HasCollision(Xt[i], Xt[i+j], CollisionByteLength())) {
|
||||
HasCollision(Xt[i], Xt[i+j], CollisionByteLength)) {
|
||||
j++;
|
||||
}
|
||||
|
||||
@@ -426,7 +407,7 @@ std::set<std::vector<eh_index>> Equihash::OptimisedSolve(const eh_HashState& bas
|
||||
for (int m = l + 1; m < j; m++) {
|
||||
// We truncated, so don't check for distinct indices here
|
||||
Xc.push_back(Xt[i+l] ^ Xt[i+m]);
|
||||
Xc.back().TrimHash(CollisionByteLength());
|
||||
Xc.back().TrimHash(CollisionByteLength);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -477,7 +458,7 @@ std::set<std::vector<eh_index>> Equihash::OptimisedSolve(const eh_HashState& bas
|
||||
// Now for each solution run the algorithm again to recreate the indices
|
||||
LogPrint("pow", "Culling solutions\n");
|
||||
std::set<std::vector<eh_index>> solns;
|
||||
eh_index recreate_size { UntruncateIndex(1, 0, CollisionBitLength() + 1) };
|
||||
eh_index recreate_size { UntruncateIndex(1, 0, CollisionBitLength + 1) };
|
||||
int invalidCount = 0;
|
||||
for (eh_trunc* partialSoln : partialSolns) {
|
||||
// 1) Generate first list of possibilities
|
||||
@@ -487,8 +468,8 @@ std::set<std::vector<eh_index>> Equihash::OptimisedSolve(const eh_HashState& bas
|
||||
std::vector<FullStepRow> ic;
|
||||
ic.reserve(recreate_size);
|
||||
for (eh_index j = 0; j < recreate_size; j++) {
|
||||
eh_index newIndex { UntruncateIndex(partialSoln[i], j, CollisionBitLength() + 1) };
|
||||
ic.emplace_back(n, base_state, newIndex);
|
||||
eh_index newIndex { UntruncateIndex(partialSoln[i], j, CollisionBitLength + 1) };
|
||||
ic.emplace_back(N, base_state, newIndex);
|
||||
}
|
||||
X.push_back(ic);
|
||||
}
|
||||
@@ -505,7 +486,7 @@ std::set<std::vector<eh_index>> Equihash::OptimisedSolve(const eh_HashState& bas
|
||||
ic.reserve(X[v].size() + X[v+1].size());
|
||||
ic.insert(ic.end(), X[v+1].begin(), X[v+1].end());
|
||||
std::sort(ic.begin(), ic.end());
|
||||
CollideBranches(ic, CollisionByteLength(), CollisionBitLength() + 1, partialSoln[(1<<r)*v], partialSoln[(1<<r)*(v+1)]);
|
||||
CollideBranches(ic, CollisionByteLength, CollisionBitLength + 1, partialSoln[(1<<r)*v], partialSoln[(1<<r)*(v+1)]);
|
||||
|
||||
// 2v) Check if this has become an invalid solution
|
||||
if (ic.size() == 0)
|
||||
@@ -535,9 +516,10 @@ deletesolution:
|
||||
return solns;
|
||||
}
|
||||
|
||||
bool Equihash::IsValidSolution(const eh_HashState& base_state, std::vector<eh_index> soln)
|
||||
template<unsigned int N, unsigned int K>
|
||||
bool Equihash<N,K>::IsValidSolution(const eh_HashState& base_state, std::vector<eh_index> soln)
|
||||
{
|
||||
eh_index soln_size { 1u << k };
|
||||
eh_index soln_size { 1u << K };
|
||||
if (soln.size() != soln_size) {
|
||||
LogPrint("pow", "Invalid solution size: %d\n", soln.size());
|
||||
return false;
|
||||
@@ -546,13 +528,13 @@ bool Equihash::IsValidSolution(const eh_HashState& base_state, std::vector<eh_in
|
||||
std::vector<FullStepRow> X;
|
||||
X.reserve(soln_size);
|
||||
for (eh_index i : soln) {
|
||||
X.emplace_back(n, base_state, i);
|
||||
X.emplace_back(N, base_state, i);
|
||||
}
|
||||
|
||||
while (X.size() > 1) {
|
||||
std::vector<FullStepRow> Xc;
|
||||
for (int i = 0; i < X.size(); i += 2) {
|
||||
if (!HasCollision(X[i], X[i+1], CollisionByteLength())) {
|
||||
if (!HasCollision(X[i], X[i+1], CollisionByteLength)) {
|
||||
LogPrint("pow", "Invalid solution: invalid collision length between StepRows\n");
|
||||
LogPrint("pow", "X[i] = %s\n", X[i].GetHex());
|
||||
LogPrint("pow", "X[i+1] = %s\n", X[i+1].GetHex());
|
||||
@@ -567,7 +549,7 @@ bool Equihash::IsValidSolution(const eh_HashState& base_state, std::vector<eh_in
|
||||
return false;
|
||||
}
|
||||
Xc.push_back(X[i] ^ X[i+1]);
|
||||
Xc.back().TrimHash(CollisionByteLength());
|
||||
Xc.back().TrimHash(CollisionByteLength);
|
||||
}
|
||||
X = Xc;
|
||||
}
|
||||
@@ -575,3 +557,15 @@ bool Equihash::IsValidSolution(const eh_HashState& base_state, std::vector<eh_in
|
||||
assert(X.size() == 1);
|
||||
return X[0].IsZero();
|
||||
}
|
||||
|
||||
// Explicit instantiations for Equihash<96,5>
|
||||
template int Equihash<96,5>::InitialiseState(eh_HashState& base_state);
|
||||
template std::set<std::vector<eh_index>> Equihash<96,5>::BasicSolve(const eh_HashState& base_state);
|
||||
template std::set<std::vector<eh_index>> Equihash<96,5>::OptimisedSolve(const eh_HashState& base_state);
|
||||
template bool Equihash<96,5>::IsValidSolution(const eh_HashState& base_state, std::vector<eh_index> soln);
|
||||
|
||||
// Explicit instantiations for Equihash<48,5>
|
||||
template int Equihash<48,5>::InitialiseState(eh_HashState& base_state);
|
||||
template std::set<std::vector<eh_index>> Equihash<48,5>::BasicSolve(const eh_HashState& base_state);
|
||||
template std::set<std::vector<eh_index>> Equihash<48,5>::OptimisedSolve(const eh_HashState& base_state);
|
||||
template bool Equihash<48,5>::IsValidSolution(const eh_HashState& base_state, std::vector<eh_index> soln);
|
||||
|
||||
Reference in New Issue
Block a user