Fabcoin Core  0.16.2
P2P Digital Currency
equihash.h
Go to the documentation of this file.
1 // Copyright (c) 2016 Jack Grigg
2 // Copyright (c) 2016 The Zcash developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #ifndef BITCOIN_EQUIHASH_H
7 #define BITCOIN_EQUIHASH_H
8 
9 #include "compat/endian.h"
10 #include "crypto/sha256.h"
11 #include "utilstrencodings.h"
12 
13 #include "sodium.h"
14 
15 #include <cstring>
16 #include <exception>
17 #include <functional>
18 #include <memory>
19 #include <set>
20 #include <vector>
21 
22 #include <boost/static_assert.hpp>
23 
24 typedef crypto_generichash_blake2b_state eh_HashState;
25 typedef uint32_t eh_index;
26 typedef uint8_t eh_trunc;
27 
28 void ExpandArray(const unsigned char* in, size_t in_len,
29  unsigned char* out, size_t out_len,
30  size_t bit_len, size_t byte_pad=0);
31 void CompressArray(const unsigned char* in, size_t in_len,
32  unsigned char* out, size_t out_len,
33  size_t bit_len, size_t byte_pad=0);
34 
35 eh_index ArrayToEhIndex(const unsigned char* array);
36 eh_trunc TruncateIndex(const eh_index i, const unsigned int ilen);
37 
38 std::vector<eh_index> GetIndicesFromMinimal(std::vector<unsigned char> minimal,
39  size_t cBitLen);
40 std::vector<unsigned char> GetMinimalFromIndices(std::vector<eh_index> indices,
41  size_t cBitLen);
42 
43 template<size_t WIDTH>
44 class StepRow
45 {
46  template<size_t W>
47  friend class StepRow;
48  friend class CompareSR;
49 
50 protected:
51  unsigned char hash[WIDTH];
52 
53 public:
54  StepRow(const unsigned char* hashIn, size_t hInLen,
55  size_t hLen, size_t cBitLen);
56  ~StepRow() { }
57 
58  template<size_t W>
59  StepRow(const StepRow<W>& a);
60 
61  bool IsZero(size_t len);
62  std::string GetHex(size_t len) { return HexStr(hash, hash+len); }
63 
64  template<size_t W>
65  friend bool HasCollision(StepRow<W>& a, StepRow<W>& b, size_t l);
66 };
67 
68 class CompareSR
69 {
70 private:
71  size_t len;
72 
73 public:
74  CompareSR(size_t l) : len {l} { }
75 
76  template<size_t W>
77  inline bool operator()(const StepRow<W>& a, const StepRow<W>& b) { return memcmp(a.hash, b.hash, len) < 0; }
78 };
79 
80 template<size_t WIDTH>
81 bool HasCollision(StepRow<WIDTH>& a, StepRow<WIDTH>& b, size_t l);
82 
83 template<size_t WIDTH>
84 class FullStepRow : public StepRow<WIDTH>
85 {
86  template<size_t W>
87  friend class FullStepRow;
88 
90 
91 public:
92  FullStepRow(const unsigned char* hashIn, size_t hInLen,
93  size_t hLen, size_t cBitLen, eh_index i);
95 
96  FullStepRow(const FullStepRow<WIDTH>& a) : StepRow<WIDTH> {a} { }
97  template<size_t W>
98  FullStepRow(const FullStepRow<W>& a, const FullStepRow<W>& b, size_t len, size_t lenIndices, size_t trim);
99  FullStepRow& operator=(const FullStepRow<WIDTH>& a);
100 
101  inline bool IndicesBefore(const FullStepRow<WIDTH>& a, size_t len, size_t lenIndices) const { return memcmp(hash+len, a.hash+len, lenIndices) < 0; }
102  std::vector<unsigned char> GetIndices(size_t len, size_t lenIndices,
103  size_t cBitLen) const;
104 
105  template<size_t W>
106  friend bool DistinctIndices(const FullStepRow<W>& a, const FullStepRow<W>& b,
107  size_t len, size_t lenIndices);
108  template<size_t W>
109  friend bool IsValidBranch(const FullStepRow<W>& a, const size_t len, const unsigned int ilen, const eh_trunc t);
110 };
111 
112 template<size_t WIDTH>
113 class TruncatedStepRow : public StepRow<WIDTH>
114 {
115  template<size_t W>
116  friend class TruncatedStepRow;
117 
118  using StepRow<WIDTH>::hash;
119 
120 public:
121  TruncatedStepRow(const unsigned char* hashIn, size_t hInLen,
122  size_t hLen, size_t cBitLen,
123  eh_index i, unsigned int ilen);
125 
127  template<size_t W>
128  TruncatedStepRow(const TruncatedStepRow<W>& a, const TruncatedStepRow<W>& b, size_t len, size_t lenIndices, size_t trim);
129  TruncatedStepRow& operator=(const TruncatedStepRow<WIDTH>& a);
130 
131  inline bool IndicesBefore(const TruncatedStepRow<WIDTH>& a, size_t len, size_t lenIndices) const { return memcmp(hash+len, a.hash+len, lenIndices) < 0; }
132  std::shared_ptr<eh_trunc> GetTruncatedIndices(size_t len, size_t lenIndices) const;
133 };
134 
136 {
148 };
149 
150 class EhSolverCancelledException : public std::exception
151 {
152  virtual const char* what() const throw() {
153  return "Equihash solver was cancelled";
154  }
155 };
156 
157 inline constexpr size_t max(const size_t A, const size_t B) { return A > B ? A : B; }
158 
159 inline constexpr size_t equihash_solution_size(unsigned int N, unsigned int K) {
160  return (1 << K)*(N/(K+1)+1)/8;
161 }
162 
163 template<unsigned int N, unsigned int K>
164 class Equihash
165 {
166 private:
167  BOOST_STATIC_ASSERT(K < N);
168  //BOOST_STATIC_ASSERT(N % 8 == 0);
169  BOOST_STATIC_ASSERT((N/(K+1)) + 1 < 8*sizeof(eh_index));
170 
171 public:
172  enum : size_t { IndicesPerHashOutput=512/N };
173  enum : size_t { HashLen=(N+7)/8 };
174  enum : size_t { HashOutput=IndicesPerHashOutput*HashLen };
175  enum : size_t { CollisionBitLength=N/(K+1) };
176  enum : size_t { CollisionByteLength=(CollisionBitLength+7)/8 };
177  enum : size_t { HashLength=(K+1)*CollisionByteLength };
178  enum : size_t { FullWidth=2*CollisionByteLength+sizeof(eh_index)*(1 << (K-1)) };
179  enum : size_t { FinalFullWidth=2*CollisionByteLength+sizeof(eh_index)*(1 << (K)) };
180  enum : size_t { TruncatedWidth=max(HashLength+sizeof(eh_trunc), 2*CollisionByteLength+sizeof(eh_trunc)*(1 << (K-1))) };
181  enum : size_t { FinalTruncatedWidth=max(HashLength+sizeof(eh_trunc), 2*CollisionByteLength+sizeof(eh_trunc)*(1 << (K))) };
182  enum : size_t { SolutionWidth=(1 << K)*(CollisionBitLength+1)/8 };
183 
184  Equihash() { }
185 
186  int InitialiseState(eh_HashState& base_state);
187  bool BasicSolve(const eh_HashState& base_state,
188  const std::function<bool(std::vector<unsigned char>)> validBlock,
189  const std::function<bool(EhSolverCancelCheck)> cancelled);
190  bool OptimisedSolve(const eh_HashState& base_state,
191  const std::function<bool(std::vector<unsigned char>)> validBlock,
192  const std::function<bool(EhSolverCancelCheck)> cancelled);
193  bool IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln);
194 };
195 
196 #include "equihash.tcc"
197 
198 static Equihash<96,3> Eh96_3;
199 static Equihash<200,9> Eh200_9;
200 static Equihash<96,5> Eh96_5;
201 static Equihash<48,5> Eh48_5;
202 static Equihash<184,7> Eh184_7;
203 
204 #define EhInitialiseState(n, k, base_state) \
205  if (n == 96 && k == 3) { \
206  Eh96_3.InitialiseState(base_state); \
207  } else if (n == 200 && k == 9) { \
208  Eh200_9.InitialiseState(base_state); \
209  } else if (n == 96 && k == 5) { \
210  Eh96_5.InitialiseState(base_state); \
211  } else if (n == 48 && k == 5) { \
212  Eh48_5.InitialiseState(base_state); \
213  } else if (n == 184 && k == 7) { \
214  Eh184_7.InitialiseState(base_state); \
215  } else { \
216  throw std::invalid_argument("Unsupported Equihash parameters"); \
217  }
218 
219 inline bool EhBasicSolve(unsigned int n, unsigned int k, const eh_HashState& base_state,
220  const std::function<bool(std::vector<unsigned char>)> validBlock,
221  const std::function<bool(EhSolverCancelCheck)> cancelled)
222 {
223  if (n == 96 && k == 3) {
224  return Eh96_3.BasicSolve(base_state, validBlock, cancelled);
225  } else if (n == 200 && k == 9) {
226  return Eh200_9.BasicSolve(base_state, validBlock, cancelled);
227  } else if (n == 96 && k == 5) {
228  return Eh96_5.BasicSolve(base_state, validBlock, cancelled);
229  } else if (n == 48 && k == 5) {
230  return Eh48_5.BasicSolve(base_state, validBlock, cancelled);
231  } else if (n == 184 && k == 7) {
232  return Eh184_7.BasicSolve(base_state, validBlock, cancelled);
233  } else {
234  throw std::invalid_argument("Unsupported Equihash parameters");
235  }
236 }
237 
238 inline bool EhBasicSolveUncancellable(unsigned int n, unsigned int k, const eh_HashState& base_state,
239  const std::function<bool(std::vector<unsigned char>)> validBlock)
240 {
241  return EhBasicSolve(n, k, base_state, validBlock,
242  [](EhSolverCancelCheck pos) { return false; });
243 }
244 
245 inline bool EhOptimisedSolve(unsigned int n, unsigned int k, const eh_HashState& base_state,
246  const std::function<bool(std::vector<unsigned char>)> validBlock,
247  const std::function<bool(EhSolverCancelCheck)> cancelled)
248 {
249  if (n == 96 && k == 3) {
250  return Eh96_3.OptimisedSolve(base_state, validBlock, cancelled);
251  } else if (n == 200 && k == 9) {
252  return Eh200_9.OptimisedSolve(base_state, validBlock, cancelled);
253  } else if (n == 96 && k == 5) {
254  return Eh96_5.OptimisedSolve(base_state, validBlock, cancelled);
255  } else if (n == 48 && k == 5) {
256  return Eh48_5.OptimisedSolve(base_state, validBlock, cancelled);
257  } else if (n == 184 && k == 7) {
258  return Eh184_7.OptimisedSolve(base_state, validBlock, cancelled);
259  } else {
260  throw std::invalid_argument("Unsupported Equihash parameters");
261  }
262 }
263 
264 inline bool EhOptimisedSolveUncancellable(unsigned int n, unsigned int k, const eh_HashState& base_state,
265  const std::function<bool(std::vector<unsigned char>)> validBlock)
266 {
267  return EhOptimisedSolve(n, k, base_state, validBlock,
268  [](EhSolverCancelCheck pos) { return false; });
269 }
270 
271 #define EhIsValidSolution(n, k, base_state, soln, ret) \
272  if (n == 96 && k == 3) { \
273  ret = Eh96_3.IsValidSolution(base_state, soln); \
274  } else if (n == 200 && k == 9) { \
275  ret = Eh200_9.IsValidSolution(base_state, soln); \
276  } else if (n == 96 && k == 5) { \
277  ret = Eh96_5.IsValidSolution(base_state, soln); \
278  } else if (n == 48 && k == 5) { \
279  ret = Eh48_5.IsValidSolution(base_state, soln); \
280  } else if (n == 184 && k == 7) { \
281  ret = Eh184_7.IsValidSolution(base_state, soln); \
282  } else { \
283  throw std::invalid_argument("Unsupported Equihash parameters"); \
284  }
285 
286 #endif // BITCOIN_EQUIHASH_H
Equihash()
Definition: equihash.h:184
#define function(a, b, c, d, k, s)
std::vector< unsigned char > GetIndices(size_t len, size_t lenIndices, size_t cBitLen) const
Definition: equihash.cpp:271
~StepRow()
Definition: equihash.h:56
friend class StepRow
Definition: equihash.h:47
void ExpandArray(const unsigned char *in, size_t in_len, unsigned char *out, size_t out_len, size_t bit_len, size_t byte_pad=0)
Definition: equihash.cpp:64
constexpr size_t equihash_solution_size(unsigned int N, unsigned int K)
Definition: equihash.h:159
eh_trunc TruncateIndex(const eh_index i, const unsigned int ilen)
Definition: equihash.cpp:166
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
friend class FullStepRow
Definition: equihash.h:87
bool EhOptimisedSolveUncancellable(unsigned int n, unsigned int k, const eh_HashState &base_state, const std::function< bool(std::vector< unsigned char >)> validBlock)
Definition: equihash.h:264
eh_index ArrayToEhIndex(const unsigned char *array)
Definition: equihash.cpp:158
TruncatedStepRow & operator=(const TruncatedStepRow< WIDTH > &a)
Definition: equihash.cpp:320
friend class TruncatedStepRow
Definition: equihash.h:116
friend bool DistinctIndices(const FullStepRow< W > &a, const FullStepRow< W > &b, size_t len, size_t lenIndices)
#define a(i)
FullStepRow(const FullStepRow< WIDTH > &a)
Definition: equihash.h:96
bool operator()(const StepRow< W > &a, const StepRow< W > &b)
Definition: equihash.h:77
friend bool IsValidBranch(const FullStepRow< W > &a, const size_t len, const unsigned int ilen, const eh_trunc t)
bool EhOptimisedSolve(unsigned int n, unsigned int k, const eh_HashState &base_state, const std::function< bool(std::vector< unsigned char >)> validBlock, const std::function< bool(EhSolverCancelCheck)> cancelled)
Definition: equihash.h:245
std::vector< unsigned char > GetMinimalFromIndices(std::vector< eh_index > indices, size_t cBitLen)
Definition: equihash.cpp:195
FullStepRow & operator=(const FullStepRow< WIDTH > &a)
Definition: equihash.cpp:253
~FullStepRow()
Definition: equihash.h:94
bool IndicesBefore(const TruncatedStepRow< WIDTH > &a, size_t len, size_t lenIndices) const
Definition: equihash.h:131
std::string GetHex(size_t len)
Definition: equihash.h:62
std::vector< eh_index > GetIndicesFromMinimal(std::vector< unsigned char > minimal, size_t cBitLen)
Definition: equihash.cpp:179
std::shared_ptr< eh_trunc > GetTruncatedIndices(size_t len, size_t lenIndices) const
Definition: equihash.cpp:327
bool EhBasicSolveUncancellable(unsigned int n, unsigned int k, const eh_HashState &base_state, const std::function< bool(std::vector< unsigned char >)> validBlock)
Definition: equihash.h:238
CompareSR(size_t l)
Definition: equihash.h:74
void CompressArray(const unsigned char *in, size_t in_len, unsigned char *out, size_t out_len, size_t bit_len, size_t byte_pad=0)
Definition: equihash.cpp:108
bool BasicSolve(const eh_HashState &base_state, const std::function< bool(std::vector< unsigned char >)> validBlock, const std::function< bool(EhSolverCancelCheck)> cancelled)
Definition: equihash.cpp:335
constexpr size_t max(const size_t A, const size_t B)
Definition: equihash.h:157
#define b(i, j)
virtual const char * what() const
Definition: equihash.h:152
crypto_generichash_blake2b_state eh_HashState
Definition: equihash.h:24
unsigned char hash[WIDTH]
Definition: equihash.h:51
uint8_t eh_trunc
Definition: equihash.h:26
friend bool HasCollision(StepRow< W > &a, StepRow< W > &b, size_t l)
size_t len
Definition: equihash.h:71
EhSolverCancelCheck
Definition: equihash.h:135
bool OptimisedSolve(const eh_HashState &base_state, const std::function< bool(std::vector< unsigned char >)> validBlock, const std::function< bool(EhSolverCancelCheck)> cancelled)
Definition: equihash.cpp:507
bool IsZero(size_t len)
Definition: equihash.cpp:260
uint32_t eh_index
Definition: equihash.h:25
TruncatedStepRow(const TruncatedStepRow< WIDTH > &a)
Definition: equihash.h:126
bool EhBasicSolve(unsigned int n, unsigned int k, const eh_HashState &base_state, const std::function< bool(std::vector< unsigned char >)> validBlock, const std::function< bool(EhSolverCancelCheck)> cancelled)
Definition: equihash.h:219
bool IndicesBefore(const FullStepRow< WIDTH > &a, size_t len, size_t lenIndices) const
Definition: equihash.h:101