Use template parameters to statically initialise Equihash
This commit is contained in:
parent
39f5cb35f9
commit
e95747288a
|
@ -19,31 +19,18 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
void validate_params(int n, int k)
|
template<unsigned int N, unsigned int K>
|
||||||
{
|
int Equihash<N,K>::InitialiseState(eh_HashState& base_state)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
|
unsigned int n = N;
|
||||||
|
unsigned int k = K;
|
||||||
unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {};
|
unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {};
|
||||||
memcpy(personalization, "ZcashPOW", 8);
|
memcpy(personalization, "ZcashPOW", 8);
|
||||||
memcpy(personalization+8, &n, 4);
|
memcpy(personalization+8, &n, 4);
|
||||||
memcpy(personalization+12, &k, 4);
|
memcpy(personalization+12, &k, 4);
|
||||||
return crypto_generichash_blake2b_init_salt_personal(&base_state,
|
return crypto_generichash_blake2b_init_salt_personal(&base_state,
|
||||||
NULL, 0, // No key.
|
NULL, 0, // No key.
|
||||||
n/8,
|
N/8,
|
||||||
NULL, // No salt.
|
NULL, // No salt.
|
||||||
personalization);
|
personalization);
|
||||||
}
|
}
|
||||||
|
@ -238,27 +225,21 @@ eh_trunc* TruncatedStepRow::GetPartialSolution(eh_index soln_size) const
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
Equihash::Equihash(unsigned int n, unsigned int k) :
|
template<unsigned int N, unsigned int K>
|
||||||
n(n), k(k)
|
std::set<std::vector<eh_index>> Equihash<N,K>::BasicSolve(const eh_HashState& base_state)
|
||||||
{
|
{
|
||||||
validate_params(n, k);
|
eh_index init_size { 1 << (CollisionBitLength + 1) };
|
||||||
}
|
|
||||||
|
|
||||||
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) };
|
|
||||||
|
|
||||||
// 1) Generate first list
|
// 1) Generate first list
|
||||||
LogPrint("pow", "Generating first list\n");
|
LogPrint("pow", "Generating first list\n");
|
||||||
std::vector<FullStepRow> X;
|
std::vector<FullStepRow> 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(N, base_state, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) Repeat step 2 until 2n/(k+1) bits remain
|
// 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);
|
LogPrint("pow", "Round %d:\n", r);
|
||||||
// 2a) Sort the list
|
// 2a) Sort the list
|
||||||
LogPrint("pow", "- Sorting list\n");
|
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
|
// 2b) Find next set of unordered pairs with collisions on the next n/(k+1) bits
|
||||||
int j = 1;
|
int j = 1;
|
||||||
while (i+j < X.size() &&
|
while (i+j < X.size() &&
|
||||||
HasCollision(X[i], X[i+j], CollisionByteLength())) {
|
HasCollision(X[i], X[i+j], CollisionByteLength)) {
|
||||||
j++;
|
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++) {
|
for (int m = l + 1; m < j; m++) {
|
||||||
if (DistinctIndices(X[i+l], X[i+m])) {
|
if (DistinctIndices(X[i+l], X[i+m])) {
|
||||||
Xc.push_back(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
|
// First run the algorithm with truncated indices
|
||||||
|
|
||||||
eh_index soln_size { 1 << k };
|
eh_index soln_size { 1 << K };
|
||||||
std::vector<eh_trunc*> partialSolns;
|
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;
|
std::vector<TruncatedStepRow> 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(N, base_state, i, CollisionBitLength + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) Repeat step 2 until 2n/(k+1) bits remain
|
// 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);
|
LogPrint("pow", "Round %d:\n", r);
|
||||||
// 2a) Sort the list
|
// 2a) Sort the list
|
||||||
LogPrint("pow", "- Sorting list\n");
|
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
|
// 2b) Find next set of unordered pairs with collisions on the next n/(k+1) bits
|
||||||
int j = 1;
|
int j = 1;
|
||||||
while (i+j < Xt.size() &&
|
while (i+j < Xt.size() &&
|
||||||
HasCollision(Xt[i], Xt[i+j], CollisionByteLength())) {
|
HasCollision(Xt[i], Xt[i+j], CollisionByteLength)) {
|
||||||
j++;
|
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++) {
|
for (int m = l + 1; m < j; m++) {
|
||||||
// We truncated, so don't check for distinct indices here
|
// We truncated, so don't check for distinct indices here
|
||||||
Xc.push_back(Xt[i+l] ^ Xt[i+m]);
|
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
|
// Now for each solution run the algorithm again to recreate the indices
|
||||||
LogPrint("pow", "Culling solutions\n");
|
LogPrint("pow", "Culling solutions\n");
|
||||||
std::set<std::vector<eh_index>> solns;
|
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;
|
int invalidCount = 0;
|
||||||
for (eh_trunc* partialSoln : partialSolns) {
|
for (eh_trunc* partialSoln : partialSolns) {
|
||||||
// 1) Generate first list of possibilities
|
// 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;
|
std::vector<FullStepRow> ic;
|
||||||
ic.reserve(recreate_size);
|
ic.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[i], j, CollisionBitLength() + 1) };
|
eh_index newIndex { UntruncateIndex(partialSoln[i], j, CollisionBitLength + 1) };
|
||||||
ic.emplace_back(n, base_state, newIndex);
|
ic.emplace_back(N, base_state, newIndex);
|
||||||
}
|
}
|
||||||
X.push_back(ic);
|
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.reserve(X[v].size() + X[v+1].size());
|
||||||
ic.insert(ic.end(), X[v+1].begin(), X[v+1].end());
|
ic.insert(ic.end(), X[v+1].begin(), X[v+1].end());
|
||||||
std::sort(ic.begin(), ic.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
|
// 2v) Check if this has become an invalid solution
|
||||||
if (ic.size() == 0)
|
if (ic.size() == 0)
|
||||||
|
@ -535,9 +516,10 @@ deletesolution:
|
||||||
return solns;
|
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) {
|
if (soln.size() != soln_size) {
|
||||||
LogPrint("pow", "Invalid solution size: %d\n", soln.size());
|
LogPrint("pow", "Invalid solution size: %d\n", soln.size());
|
||||||
return false;
|
return false;
|
||||||
|
@ -546,13 +528,13 @@ bool Equihash::IsValidSolution(const eh_HashState& base_state, std::vector<eh_in
|
||||||
std::vector<FullStepRow> X;
|
std::vector<FullStepRow> 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(N, base_state, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (X.size() > 1) {
|
while (X.size() > 1) {
|
||||||
std::vector<FullStepRow> Xc;
|
std::vector<FullStepRow> Xc;
|
||||||
for (int i = 0; i < X.size(); i += 2) {
|
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", "Invalid solution: invalid collision length between StepRows\n");
|
||||||
LogPrint("pow", "X[i] = %s\n", X[i].GetHex());
|
LogPrint("pow", "X[i] = %s\n", X[i].GetHex());
|
||||||
LogPrint("pow", "X[i+1] = %s\n", X[i+1].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;
|
return false;
|
||||||
}
|
}
|
||||||
Xc.push_back(X[i] ^ X[i+1]);
|
Xc.push_back(X[i] ^ X[i+1]);
|
||||||
Xc.back().TrimHash(CollisionByteLength());
|
Xc.back().TrimHash(CollisionByteLength);
|
||||||
}
|
}
|
||||||
X = Xc;
|
X = Xc;
|
||||||
}
|
}
|
||||||
|
@ -575,3 +557,15 @@ bool Equihash::IsValidSolution(const eh_HashState& base_state, std::vector<eh_in
|
||||||
assert(X.size() == 1);
|
assert(X.size() == 1);
|
||||||
return X[0].IsZero();
|
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);
|
||||||
|
|
|
@ -15,12 +15,12 @@
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <boost/static_assert.hpp>
|
||||||
|
|
||||||
typedef crypto_generichash_blake2b_state eh_HashState;
|
typedef crypto_generichash_blake2b_state eh_HashState;
|
||||||
typedef uint32_t eh_index;
|
typedef uint32_t eh_index;
|
||||||
typedef uint8_t eh_trunc;
|
typedef uint8_t eh_trunc;
|
||||||
|
|
||||||
struct invalid_params { };
|
|
||||||
|
|
||||||
class StepRow
|
class StepRow
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
@ -96,17 +96,20 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<unsigned int N, unsigned int K>
|
||||||
class Equihash
|
class Equihash
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
unsigned int n;
|
BOOST_STATIC_ASSERT(K < N);
|
||||||
unsigned int k;
|
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:
|
public:
|
||||||
Equihash(unsigned int n, unsigned int k);
|
enum { CollisionBitLength=N/(K+1) };
|
||||||
|
enum { CollisionByteLength=CollisionBitLength/8 };
|
||||||
|
|
||||||
inline unsigned int CollisionBitLength() { return n/(k+1); }
|
Equihash() { }
|
||||||
inline unsigned int CollisionByteLength() { return CollisionBitLength()/8; }
|
|
||||||
|
|
||||||
int InitialiseState(eh_HashState& base_state);
|
int InitialiseState(eh_HashState& base_state);
|
||||||
std::set<std::vector<eh_index>> BasicSolve(const eh_HashState& base_state);
|
std::set<std::vector<eh_index>> BasicSolve(const eh_HashState& base_state);
|
||||||
|
@ -114,4 +117,43 @@ public:
|
||||||
bool IsValidSolution(const eh_HashState& base_state, std::vector<eh_index> soln);
|
bool IsValidSolution(const eh_HashState& base_state, std::vector<eh_index> soln);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static Equihash<96,5> Eh965;
|
||||||
|
static Equihash<48,5> Eh485;
|
||||||
|
|
||||||
|
#define EhInitialiseState(n, k, base_state) \
|
||||||
|
if (n == 96 && k == 5) { \
|
||||||
|
Eh965.InitialiseState(base_state); \
|
||||||
|
} else if (n == 48 && k == 5) { \
|
||||||
|
Eh485.InitialiseState(base_state); \
|
||||||
|
} else { \
|
||||||
|
throw std::invalid_argument("Unsupported Equihash parameters"); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EhBasicSolve(n, k, base_state, solns) \
|
||||||
|
if (n == 96 && k == 5) { \
|
||||||
|
solns = Eh965.BasicSolve(base_state); \
|
||||||
|
} else if (n == 48 && k == 5) { \
|
||||||
|
solns = Eh485.BasicSolve(base_state); \
|
||||||
|
} else { \
|
||||||
|
throw std::invalid_argument("Unsupported Equihash parameters"); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EhOptimisedSolve(n, k, base_state, solns) \
|
||||||
|
if (n == 96 && k == 5) { \
|
||||||
|
solns = Eh965.OptimisedSolve(base_state); \
|
||||||
|
} else if (n == 48 && k == 5) { \
|
||||||
|
solns = Eh485.OptimisedSolve(base_state); \
|
||||||
|
} else { \
|
||||||
|
throw std::invalid_argument("Unsupported Equihash parameters"); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EhIsValidSolution(n, k, base_state, soln, ret) \
|
||||||
|
if (n == 96 && k == 5) { \
|
||||||
|
ret = Eh965.IsValidSolution(base_state, soln); \
|
||||||
|
} else if (n == 48 && k == 5) { \
|
||||||
|
ret = Eh485.IsValidSolution(base_state, soln); \
|
||||||
|
} else { \
|
||||||
|
throw std::invalid_argument("Unsupported Equihash parameters"); \
|
||||||
|
}
|
||||||
|
|
||||||
#endif // BITCOIN_EQUIHASH_H
|
#endif // BITCOIN_EQUIHASH_H
|
||||||
|
|
|
@ -443,7 +443,8 @@ void static BitcoinMiner(CWallet *pwallet)
|
||||||
CReserveKey reservekey(pwallet);
|
CReserveKey reservekey(pwallet);
|
||||||
unsigned int nExtraNonce = 0;
|
unsigned int nExtraNonce = 0;
|
||||||
|
|
||||||
Equihash eh {chainparams.EquihashN(), chainparams.EquihashK()};
|
unsigned int n = chainparams.EquihashN();
|
||||||
|
unsigned int k = chainparams.EquihashK();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -489,7 +490,7 @@ void static BitcoinMiner(CWallet *pwallet)
|
||||||
while (true) {
|
while (true) {
|
||||||
// Hash state
|
// Hash state
|
||||||
crypto_generichash_blake2b_state state;
|
crypto_generichash_blake2b_state state;
|
||||||
eh.InitialiseState(state);
|
EhInitialiseState(n, k, state);
|
||||||
|
|
||||||
// I = the block header minus nonce and solution.
|
// I = the block header minus nonce and solution.
|
||||||
CEquihashInput I{*pblock};
|
CEquihashInput I{*pblock};
|
||||||
|
@ -512,7 +513,8 @@ void static BitcoinMiner(CWallet *pwallet)
|
||||||
// (x_1, x_2, ...) = A(I, V, n, k)
|
// (x_1, x_2, ...) = A(I, V, n, k)
|
||||||
LogPrint("pow", "Running Equihash solver with nNonce = %s\n",
|
LogPrint("pow", "Running Equihash solver with nNonce = %s\n",
|
||||||
pblock->nNonce.ToString());
|
pblock->nNonce.ToString());
|
||||||
std::set<std::vector<unsigned int>> solns = eh.BasicSolve(curr_state);
|
std::set<std::vector<unsigned int>> solns;
|
||||||
|
EhBasicSolve(n, k, curr_state, solns);
|
||||||
LogPrint("pow", "Solutions: %d\n", solns.size());
|
LogPrint("pow", "Solutions: %d\n", solns.size());
|
||||||
|
|
||||||
// Write the solution to the hash and compute the result.
|
// Write the solution to the hash and compute the result.
|
||||||
|
|
|
@ -88,11 +88,12 @@ unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nF
|
||||||
|
|
||||||
bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams& params)
|
bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams& params)
|
||||||
{
|
{
|
||||||
Equihash eh {params.EquihashN(), params.EquihashK()};
|
unsigned int n = params.EquihashN();
|
||||||
|
unsigned int k = params.EquihashK();
|
||||||
|
|
||||||
// Hash state
|
// Hash state
|
||||||
crypto_generichash_blake2b_state state;
|
crypto_generichash_blake2b_state state;
|
||||||
eh.InitialiseState(state);
|
EhInitialiseState(n, k, state);
|
||||||
|
|
||||||
// I = the block header minus nonce and solution.
|
// I = the block header minus nonce and solution.
|
||||||
CEquihashInput I{*pblock};
|
CEquihashInput I{*pblock};
|
||||||
|
@ -104,7 +105,9 @@ bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams& param
|
||||||
// H(I||V||...
|
// H(I||V||...
|
||||||
crypto_generichash_blake2b_update(&state, (unsigned char*)&ss[0], ss.size());
|
crypto_generichash_blake2b_update(&state, (unsigned char*)&ss[0], ss.size());
|
||||||
|
|
||||||
if (!eh.IsValidSolution(state, pblock->nSolution))
|
bool isValid;
|
||||||
|
EhIsValidSolution(n, k, state, pblock->nSolution, isValid);
|
||||||
|
if (!isValid)
|
||||||
return error("CheckEquihashSolution(): invalid solution");
|
return error("CheckEquihashSolution(): invalid solution");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -150,7 +150,8 @@ Value generate(const Array& params, bool fHelp)
|
||||||
}
|
}
|
||||||
unsigned int nExtraNonce = 0;
|
unsigned int nExtraNonce = 0;
|
||||||
Array blockHashes;
|
Array blockHashes;
|
||||||
Equihash eh {Params().EquihashN(), Params().EquihashK()};
|
unsigned int n = Params().EquihashN();
|
||||||
|
unsigned int k = Params().EquihashK();
|
||||||
while (nHeight < nHeightEnd)
|
while (nHeight < nHeightEnd)
|
||||||
{
|
{
|
||||||
auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));
|
auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));
|
||||||
|
@ -164,7 +165,7 @@ Value generate(const Array& params, bool fHelp)
|
||||||
|
|
||||||
// Hash state
|
// Hash state
|
||||||
crypto_generichash_blake2b_state eh_state;
|
crypto_generichash_blake2b_state eh_state;
|
||||||
eh.InitialiseState(eh_state);
|
EhInitialiseState(n, k, eh_state);
|
||||||
|
|
||||||
// I = the block header minus nonce and solution.
|
// I = the block header minus nonce and solution.
|
||||||
CEquihashInput I{*pblock};
|
CEquihashInput I{*pblock};
|
||||||
|
@ -187,10 +188,13 @@ Value generate(const Array& params, bool fHelp)
|
||||||
pblock->nNonce.size());
|
pblock->nNonce.size());
|
||||||
|
|
||||||
// (x_1, x_2, ...) = A(I, V, n, k)
|
// (x_1, x_2, ...) = A(I, V, n, k)
|
||||||
std::set<std::vector<unsigned int>> solns = eh.BasicSolve(curr_state);
|
std::set<std::vector<unsigned int>> solns;
|
||||||
|
EhBasicSolve(n, k, curr_state, solns);
|
||||||
|
|
||||||
for (auto soln : solns) {
|
for (auto soln : solns) {
|
||||||
assert(eh.IsValidSolution(curr_state, soln));
|
bool isValid;
|
||||||
|
EhIsValidSolution(n, k, curr_state, soln, isValid);
|
||||||
|
assert(isValid);
|
||||||
pblock->nSolution = soln;
|
pblock->nSolution = soln;
|
||||||
|
|
||||||
if (CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) {
|
if (CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) {
|
||||||
|
|
|
@ -41,16 +41,16 @@ void PrintSolutions(std::stringstream &strm, std::set<std::vector<uint32_t>> sol
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestEquihashSolvers(unsigned int n, unsigned int k, const std::string &I, const arith_uint256 &nonce, const std::set<std::vector<uint32_t>> &solns) {
|
void TestEquihashSolvers(unsigned int n, unsigned int k, const std::string &I, const arith_uint256 &nonce, const std::set<std::vector<uint32_t>> &solns) {
|
||||||
Equihash eh {n, k};
|
|
||||||
crypto_generichash_blake2b_state state;
|
crypto_generichash_blake2b_state state;
|
||||||
eh.InitialiseState(state);
|
EhInitialiseState(n, k, state);
|
||||||
uint256 V = ArithToUint256(nonce);
|
uint256 V = ArithToUint256(nonce);
|
||||||
BOOST_TEST_MESSAGE("Running solver: n = " << n << ", k = " << k << ", I = " << I << ", V = " << V.GetHex());
|
BOOST_TEST_MESSAGE("Running solver: n = " << n << ", k = " << k << ", I = " << I << ", V = " << V.GetHex());
|
||||||
crypto_generichash_blake2b_update(&state, (unsigned char*)&I[0], I.size());
|
crypto_generichash_blake2b_update(&state, (unsigned char*)&I[0], I.size());
|
||||||
crypto_generichash_blake2b_update(&state, V.begin(), V.size());
|
crypto_generichash_blake2b_update(&state, V.begin(), V.size());
|
||||||
|
|
||||||
// First test the basic solver
|
// First test the basic solver
|
||||||
std::set<std::vector<uint32_t>> ret = eh.BasicSolve(state);
|
std::set<std::vector<uint32_t>> ret;
|
||||||
|
EhBasicSolve(n, k, state, ret);
|
||||||
BOOST_TEST_MESSAGE("[Basic] Number of solutions: " << ret.size());
|
BOOST_TEST_MESSAGE("[Basic] Number of solutions: " << ret.size());
|
||||||
std::stringstream strm;
|
std::stringstream strm;
|
||||||
PrintSolutions(strm, ret);
|
PrintSolutions(strm, ret);
|
||||||
|
@ -58,7 +58,8 @@ void TestEquihashSolvers(unsigned int n, unsigned int k, const std::string &I, c
|
||||||
BOOST_CHECK(ret == solns);
|
BOOST_CHECK(ret == solns);
|
||||||
|
|
||||||
// The optimised solver should have the exact same result
|
// The optimised solver should have the exact same result
|
||||||
std::set<std::vector<uint32_t>> retOpt = eh.OptimisedSolve(state);
|
std::set<std::vector<uint32_t>> retOpt;
|
||||||
|
EhOptimisedSolve(n, k, state, retOpt);
|
||||||
BOOST_TEST_MESSAGE("[Optimised] Number of solutions: " << retOpt.size());
|
BOOST_TEST_MESSAGE("[Optimised] Number of solutions: " << retOpt.size());
|
||||||
strm.str("");
|
strm.str("");
|
||||||
PrintSolutions(strm, retOpt);
|
PrintSolutions(strm, retOpt);
|
||||||
|
@ -68,9 +69,8 @@ void TestEquihashSolvers(unsigned int n, unsigned int k, const std::string &I, c
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestEquihashValidator(unsigned int n, unsigned int k, const std::string &I, const arith_uint256 &nonce, std::vector<uint32_t> soln, bool expected) {
|
void TestEquihashValidator(unsigned int n, unsigned int k, const std::string &I, const arith_uint256 &nonce, std::vector<uint32_t> soln, bool expected) {
|
||||||
Equihash eh {n, k};
|
|
||||||
crypto_generichash_blake2b_state state;
|
crypto_generichash_blake2b_state state;
|
||||||
eh.InitialiseState(state);
|
EhInitialiseState(n, k, state);
|
||||||
uint256 V = ArithToUint256(nonce);
|
uint256 V = ArithToUint256(nonce);
|
||||||
crypto_generichash_blake2b_update(&state, (unsigned char*)&I[0], I.size());
|
crypto_generichash_blake2b_update(&state, (unsigned char*)&I[0], I.size());
|
||||||
crypto_generichash_blake2b_update(&state, V.begin(), V.size());
|
crypto_generichash_blake2b_update(&state, V.begin(), V.size());
|
||||||
|
@ -78,7 +78,9 @@ void TestEquihashValidator(unsigned int n, unsigned int k, const std::string &I,
|
||||||
std::stringstream strm;
|
std::stringstream strm;
|
||||||
PrintSolution(strm, soln);
|
PrintSolution(strm, soln);
|
||||||
BOOST_TEST_MESSAGE(strm.str());
|
BOOST_TEST_MESSAGE(strm.str());
|
||||||
BOOST_CHECK(eh.IsValidSolution(state, soln) == expected);
|
bool isValid;
|
||||||
|
EhIsValidSolution(n, k, state, soln, isValid);
|
||||||
|
BOOST_CHECK(isValid == expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(solver_testvectors) {
|
BOOST_AUTO_TEST_CASE(solver_testvectors) {
|
||||||
|
|
|
@ -100,9 +100,10 @@ double benchmark_solve_equihash()
|
||||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
ss << I;
|
ss << I;
|
||||||
|
|
||||||
Equihash eh {Params(CBaseChainParams::MAIN).EquihashN(), Params(CBaseChainParams::MAIN).EquihashK()};
|
unsigned int n = Params(CBaseChainParams::MAIN).EquihashN();
|
||||||
|
unsigned int k = Params(CBaseChainParams::MAIN).EquihashK();
|
||||||
crypto_generichash_blake2b_state eh_state;
|
crypto_generichash_blake2b_state eh_state;
|
||||||
eh.InitialiseState(eh_state);
|
EhInitialiseState(n, k, eh_state);
|
||||||
crypto_generichash_blake2b_update(&eh_state, (unsigned char*)&ss[0], ss.size());
|
crypto_generichash_blake2b_update(&eh_state, (unsigned char*)&ss[0], ss.size());
|
||||||
|
|
||||||
uint256 nonce;
|
uint256 nonce;
|
||||||
|
@ -112,7 +113,8 @@ double benchmark_solve_equihash()
|
||||||
nonce.size());
|
nonce.size());
|
||||||
|
|
||||||
timer_start();
|
timer_start();
|
||||||
eh.BasicSolve(eh_state);
|
std::set<std::vector<unsigned int>> solns;
|
||||||
|
EhBasicSolve(n, k, eh_state, solns);
|
||||||
return timer_stop();
|
return timer_stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue