15 #if defined(HAVE_CONFIG_H) 30 #include <boost/optional.hpp> 34 template<
unsigned int N,
unsigned int K>
39 unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {};
40 if( (le_N == 200 && le_K == 9) || (le_N == 96 && le_K == 5) )
41 memcpy(personalization,
"ZcashPoW", 8);
43 memcpy(personalization,
"FABcoin_", 8);
44 memcpy(personalization+8, &le_N, 4);
45 memcpy(personalization+12, &le_K, 4);
46 return crypto_generichash_blake2b_init_salt_personal(&base_state,
54 unsigned char* hash,
size_t hLen)
59 crypto_generichash_blake2b_update(&state, (
const unsigned char*) &lei,
61 crypto_generichash_blake2b_final(&state, hash, hLen);
65 unsigned char* out,
size_t out_len,
66 size_t bit_len,
size_t byte_pad)
71 size_t out_width { (bit_len+7)/8 + byte_pad };
75 uint32_t bit_len_mask { ((uint32_t)1 << bit_len) - 1 };
80 uint32_t acc_value = 0;
83 for (
size_t i = 0; i < in_len; i++) {
84 acc_value = (acc_value << 8) | in[i];
89 if (acc_bits >= bit_len) {
91 for (
size_t x = 0;
x < byte_pad;
x++) {
94 for (
size_t x = byte_pad;
x < out_width;
x++) {
97 acc_value >> (acc_bits+(8*(out_width-
x-1)))
100 (bit_len_mask >> (8*(out_width-
x-1))) & 0xFF
109 unsigned char* out,
size_t out_len,
110 size_t bit_len,
size_t byte_pad)
113 assert(8*
sizeof(uint32_t) >= 7+bit_len);
115 size_t in_width { (bit_len+7)/8 + byte_pad };
116 assert(out_len == bit_len*in_len/(8*in_width));
118 uint32_t bit_len_mask { ((uint32_t)1 << bit_len) - 1 };
123 uint32_t acc_value = 0;
126 for (
size_t i = 0; i < out_len; i++) {
130 acc_value = acc_value << bit_len;
131 for (
size_t x = byte_pad;
x < in_width;
x++) {
132 acc_value = acc_value | (
135 in[j+
x] & ((bit_len_mask >> (8*(in_width-
x-1))) & 0xFF)
136 ) << (8*(in_width-
x-1)));
143 out[i] = (acc_value >> acc_bits) & 0xFF;
151 BOOST_STATIC_ASSERT(
sizeof(
eh_index) == 4);
160 BOOST_STATIC_ASSERT(
sizeof(
eh_index) == 4);
169 BOOST_STATIC_ASSERT(
sizeof(
eh_trunc) == 1);
170 return (i >> (ilen - 8)) & 0xff;
176 return (i << (ilen - 8)) | r;
183 size_t lenIndices { 8*
sizeof(
eh_index)*minimal.size()/(cBitLen+1) };
184 size_t bytePad {
sizeof(
eh_index) - ((cBitLen+1)+7)/8 };
185 std::vector<unsigned char> array(lenIndices);
187 array.data(), lenIndices, cBitLen+1, bytePad);
188 std::vector<eh_index> ret;
189 for (
size_t i = 0; i < lenIndices; i +=
sizeof(
eh_index)) {
199 size_t lenIndices { indices.size()*
sizeof(
eh_index) };
200 size_t minLen { (cBitLen+1)*lenIndices/(8*
sizeof(
eh_index)) };
201 size_t bytePad {
sizeof(
eh_index) - ((cBitLen+1)+7)/8 };
202 std::vector<unsigned char> array(lenIndices);
203 for (
size_t i = 0; i < indices.size(); i++) {
206 std::vector<unsigned char> ret(minLen);
208 ret.data(), minLen, cBitLen+1, bytePad);
212 template<
size_t WIDTH>
214 size_t hLen,
size_t cBitLen)
220 template<
size_t WIDTH>
template<
size_t W>
223 BOOST_STATIC_ASSERT(W <= WIDTH);
227 template<
size_t WIDTH>
229 size_t hLen,
size_t cBitLen,
eh_index i) :
230 StepRow<WIDTH> {hashIn, hInLen, hLen, cBitLen}
235 template<
size_t WIDTH>
template<
size_t W>
239 assert(len+lenIndices <= W);
240 assert(len-trim+(2*lenIndices) <= WIDTH);
241 for (
size_t i = trim; i < len; i++)
242 hash[i-trim] =
a.hash[i] ^
b.hash[i];
243 if (
a.IndicesBefore(
b, len, lenIndices)) {
244 std::copy(
a.hash+len,
a.hash+len+lenIndices,
hash+len-trim);
245 std::copy(
b.hash+len,
b.hash+len+lenIndices,
hash+len-trim+lenIndices);
247 std::copy(
b.hash+len,
b.hash+len+lenIndices,
hash+len-trim);
248 std::copy(
a.hash+len,
a.hash+len+lenIndices,
hash+len-trim+lenIndices);
252 template<
size_t WIDTH>
259 template<
size_t WIDTH>
263 for (
size_t i = 0; i < len; i++) {
270 template<
size_t WIDTH>
272 size_t cBitLen)
const 275 size_t minLen { (cBitLen+1)*lenIndices/(8*
sizeof(
eh_index)) };
276 size_t bytePad {
sizeof(
eh_index) - ((cBitLen+1)+7)/8 };
277 std::vector<unsigned char> ret(minLen);
282 template<
size_t WIDTH>
286 for (
size_t j = 0; j < l; j++) {
293 template<
size_t WIDTH>
295 size_t hLen,
size_t cBitLen,
297 StepRow<WIDTH> {hashIn, hInLen, hLen, cBitLen}
302 template<
size_t WIDTH>
template<
size_t W>
306 assert(len+lenIndices <= W);
307 assert(len-trim+(2*lenIndices) <= WIDTH);
308 for (
size_t i = trim; i < len; i++)
309 hash[i-trim] =
a.hash[i] ^
b.hash[i];
310 if (
a.IndicesBefore(
b, len, lenIndices)) {
311 std::copy(
a.hash+len,
a.hash+len+lenIndices,
hash+len-trim);
312 std::copy(
b.hash+len,
b.hash+len+lenIndices,
hash+len-trim+lenIndices);
314 std::copy(
b.hash+len,
b.hash+len+lenIndices,
hash+len-trim);
315 std::copy(
a.hash+len,
a.hash+len+lenIndices,
hash+len-trim+lenIndices);
319 template<
size_t WIDTH>
326 template<
size_t WIDTH>
329 std::shared_ptr<eh_trunc> p (
new eh_trunc[lenIndices], std::default_delete<
eh_trunc[]>());
330 std::copy(
hash+len,
hash+len+lenIndices, p.get());
334 template<
unsigned int N,
unsigned int K>
336 const std::function<
bool(std::vector<unsigned char>)> validBlock,
339 eh_index init_size { 1 << (CollisionBitLength + 1) };
343 size_t hashLen = HashLength;
344 size_t lenIndices =
sizeof(
eh_index);
345 std::vector<FullStepRow<FullWidth>>
X;
346 X.reserve(init_size);
347 unsigned char tmpHash[HashOutput];
348 for (
eh_index g = 0; X.size() < init_size;
g++) {
350 for (
eh_index i = 0; i < IndicesPerHashOutput && X.size() < init_size; i++) {
351 X.emplace_back(tmpHash+(i*N/8), N/8, HashLength,
352 CollisionBitLength, (
g*IndicesPerHashOutput)+i);
358 for (
unsigned int r = 1; r < K && X.size() > 0; r++) {
362 std::sort(X.begin(), X.end(),
CompareSR(CollisionByteLength));
363 if (cancelled(
ListSorting))
throw solver_cancelled;
368 std::vector<FullStepRow<FullWidth>> Xc;
369 while (i < X.size() - 1) {
372 while (i+j < X.size() &&
378 for (
size_t l = 0; l < j - 1; l++) {
379 for (
size_t m = l + 1; m < j; m++) {
380 if (DistinctIndices(X[i+l], X[i+m], hashLen, lenIndices)) {
381 Xc.emplace_back(X[i+l], X[i+m], hashLen, lenIndices, CollisionByteLength);
387 while (posFree < i+j && Xc.size() > 0) {
388 X[posFree++] = Xc.back();
397 while (posFree < X.size() && Xc.size() > 0) {
398 X[posFree++] = Xc.back();
404 X.insert(X.end(), Xc.begin(), Xc.end());
405 }
else if (posFree < X.size()) {
407 X.erase(X.begin()+posFree, X.end());
411 hashLen -= CollisionByteLength;
420 std::sort(X.begin(), X.end(),
CompareSR(hashLen));
424 while (i < X.size() - 1) {
426 while (i+j < X.size() &&
431 for (
size_t l = 0; l < j - 1; l++) {
432 for (
size_t m = l + 1; m < j; m++) {
434 if (DistinctIndices(X[i+l], X[i+m], hashLen, lenIndices)) {
435 auto soln = res.
GetIndices(hashLen, 2*lenIndices, CollisionBitLength);
437 if (validBlock(soln)) {
454 template<
size_t WIDTH>
459 std::vector<FullStepRow<WIDTH>> Xc;
460 while (i <
X.size() - 1) {
463 while (i+j <
X.size() &&
469 for (
size_t l = 0; l < j - 1; l++) {
470 for (
size_t m = l + 1; m < j; m++) {
471 if (DistinctIndices(
X[i+l],
X[i+m], hlen, lenIndices)) {
472 if (IsValidBranch(
X[i+l], hlen, ilen, lt) && IsValidBranch(
X[i+m], hlen, ilen, rt)) {
473 Xc.emplace_back(
X[i+l],
X[i+m], hlen, lenIndices, clen);
474 }
else if (IsValidBranch(
X[i+m], hlen, ilen, lt) && IsValidBranch(
X[i+l], hlen, ilen, rt)) {
475 Xc.emplace_back(
X[i+m],
X[i+l], hlen, lenIndices, clen);
482 while (posFree < i+j && Xc.size() > 0) {
483 X[posFree++] = Xc.back();
491 while (posFree <
X.size() && Xc.size() > 0) {
492 X[posFree++] = Xc.back();
498 X.insert(
X.end(), Xc.begin(), Xc.end());
499 }
else if (posFree <
X.size()) {
501 X.erase(
X.begin()+posFree,
X.end());
506 template<
unsigned int N,
unsigned int K>
508 const std::function<
bool(std::vector<unsigned char>)> validBlock,
511 eh_index init_size { 1 << (CollisionBitLength + 1) };
516 const eh_index soln_size { 1 << K };
517 std::vector<std::shared_ptr<eh_trunc>> partialSolns;
518 size_t invalidCount = 0;
523 size_t hashLen = HashLength;
524 size_t lenIndices =
sizeof(
eh_trunc);
525 std::vector<TruncatedStepRow<TruncatedWidth>> Xt;
526 Xt.reserve(init_size);
527 unsigned char tmpHash[HashOutput];
528 for (
eh_index g = 0; Xt.size() < init_size;
g++) {
530 for (
eh_index i = 0; i < IndicesPerHashOutput && Xt.size() < init_size; i++) {
531 Xt.emplace_back(tmpHash+(i*N/8), N/8, HashLength, CollisionBitLength,
532 (
g*IndicesPerHashOutput)+i, CollisionBitLength + 1);
538 for (
size_t r = 1; r < K && Xt.size() > 0; r++) {
542 std::sort(Xt.begin(), Xt.end(),
CompareSR(CollisionByteLength));
543 if (cancelled(
ListSorting))
throw solver_cancelled;
548 std::vector<TruncatedStepRow<TruncatedWidth>> Xc;
549 while (i < Xt.size() - 1) {
552 while (i+j < Xt.size() &&
559 for (
size_t l = 0; l < j - 1; l++) {
560 for (
size_t m = l + 1; m < j; m++) {
564 CollisionByteLength};
565 if (!(Xi.IsZero(hashLen-CollisionByteLength) &&
566 IsProbablyDuplicate<soln_size>(Xi.GetTruncatedIndices(hashLen-CollisionByteLength, 2*lenIndices),
574 while (posFree < i+j && Xc.size() > 0) {
575 Xt[posFree++] = Xc.back();
584 while (posFree < Xt.size() && Xc.size() > 0) {
585 Xt[posFree++] = Xc.back();
591 Xt.insert(Xt.end(), Xc.begin(), Xc.end());
592 }
else if (posFree < Xt.size()) {
594 Xt.erase(Xt.begin()+posFree, Xt.end());
598 hashLen -= CollisionByteLength;
607 std::sort(Xt.begin(), Xt.end(),
CompareSR(hashLen));
611 while (i < Xt.size() - 1) {
613 while (i+j < Xt.size() &&
618 for (
size_t l = 0; l < j - 1; l++) {
619 for (
size_t m = l + 1; m < j; m++) {
621 hashLen, lenIndices, 0);
623 if (!IsProbablyDuplicate<soln_size>(soln, 2*lenIndices)) {
624 partialSolns.push_back(soln);
643 for (std::shared_ptr<eh_trunc> partialSoln : partialSolns) {
644 std::set<std::vector<unsigned char>> solns;
647 unsigned char tmpHash[HashOutput];
648 std::vector<boost::optional<std::vector<FullStepRow<FinalFullWidth>>>>
X;
652 for (
eh_index i = 0; i < soln_size; i++) {
654 std::vector<FullStepRow<FinalFullWidth>> icv;
655 icv.reserve(recreate_size);
656 for (
eh_index j = 0; j < recreate_size; j++) {
658 if (j == 0 || newIndex % IndicesPerHashOutput == 0) {
660 tmpHash, HashOutput);
662 icv.emplace_back(tmpHash+((newIndex % IndicesPerHashOutput) * N/8),
663 N/8, HashLength, CollisionBitLength, newIndex);
666 boost::optional<std::vector<FullStepRow<FinalFullWidth>>> ic = icv;
669 hashLen = HashLength;
672 for (
size_t r = 0; r <= K; r++) {
677 ic->reserve(ic->size() + X[r]->size());
678 ic->insert(ic->end(), X[r]->begin(), X[r]->end());
679 std::sort(ic->begin(), ic->end(),
CompareSR(hashLen));
681 size_t lti = rti-(1<<r);
684 CollisionBitLength + 1,
685 partialSoln.get()[lti], partialSoln.get()[rti]);
689 goto invalidsolution;
692 hashLen -= CollisionByteLength;
711 auto soln = row.GetIndices(hashLen, lenIndices, CollisionBitLength);
715 for (
auto soln : solns) {
716 if (validBlock(soln))
730 template<
unsigned int N,
unsigned int K>
733 if (soln.size() != SolutionWidth) {
735 soln.size(), SolutionWidth);
739 std::vector<FullStepRow<FinalFullWidth>>
X;
741 unsigned char tmpHash[HashOutput] = {};
743 GenerateHash(base_state, i/IndicesPerHashOutput, tmpHash, HashOutput);
744 X.emplace_back(tmpHash+((i % IndicesPerHashOutput) * HashLen),
745 HashLen, HashLength, CollisionBitLength, i);
748 size_t hashLen = HashLength;
749 size_t lenIndices =
sizeof(
eh_index);
750 while (X.size() > 1) {
751 std::vector<FullStepRow<FinalFullWidth>> Xc;
752 for (
size_t i = 0; i < X.size(); i += 2) {
754 LogPrint(
BCLog::POW,
"Invalid solution: invalid collision length between StepRows\n");
763 if (!DistinctIndices(X[i], X[i+1], hashLen, lenIndices)) {
767 Xc.emplace_back(X[i], X[i+1], hashLen, lenIndices, CollisionByteLength);
770 hashLen -= CollisionByteLength;
775 return X[0].IsZero(hashLen);
781 const std::function<
bool(std::vector<unsigned char>)> validBlock,
784 const std::function<
bool(std::vector<unsigned char>)> validBlock,
791 const std::function<
bool(std::vector<unsigned char>)> validBlock,
794 const std::function<
bool(std::vector<unsigned char>)> validBlock,
801 const std::function<
bool(std::vector<unsigned char>)> validBlock,
804 const std::function<
bool(std::vector<unsigned char>)> validBlock,
811 const std::function<
bool(std::vector<unsigned char>)> validBlock,
814 const std::function<
bool(std::vector<unsigned char>)> validBlock,
821 const std::function<
bool(std::vector<unsigned char>)> validBlock,
824 const std::function<
bool(std::vector<unsigned char>)> validBlock,
uint32_t htobe32(uint32_t host_32bits)
#define function(a, b, c, d, k, s)
std::vector< unsigned char > GetIndices(size_t len, size_t lenIndices, size_t cBitLen) const
bool IsValidSolution(const eh_HashState &base_state, std::vector< unsigned char > soln)
std::vector< unsigned char > GetMinimalFromIndices(std::vector< eh_index > indices, size_t cBitLen)
constexpr size_t equihash_solution_size(unsigned int N, unsigned int K)
assert(len-trim+(2 *lenIndices)<=WIDTH)
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)
if(a.IndicesBefore(b, len, lenIndices))
TruncatedStepRow & operator=(const TruncatedStepRow< WIDTH > &a)
friend class TruncatedStepRow
eh_trunc TruncateIndex(const eh_index i, const unsigned int ilen)
void EhIndexToArray(const eh_index i, unsigned char *array)
eh_index ArrayToEhIndex(const unsigned char *array)
void GenerateHash(const eh_HashState &base_state, eh_index g, unsigned char *hash, size_t hLen)
FullStepRow & operator=(const FullStepRow< WIDTH > &a)
bool IndicesBefore(const TruncatedStepRow< WIDTH > &a, size_t len, size_t lenIndices) const
std::string GetHex(size_t len)
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)
std::shared_ptr< eh_trunc > GetTruncatedIndices(size_t len, size_t lenIndices) const
int InitialiseState(eh_HashState &base_state)
bool BasicSolve(const eh_HashState &base_state, const std::function< bool(std::vector< unsigned char >)> validBlock, const std::function< bool(EhSolverCancelCheck)> cancelled)
std::vector< eh_index > GetIndicesFromMinimal(std::vector< unsigned char > minimal, size_t cBitLen)
#define LogPrint(category,...)
crypto_generichash_blake2b_state eh_HashState
unsigned char hash[WIDTH]
void * memcpy(void *a, const void *b, size_t c)
friend bool HasCollision(StepRow< W > &a, StepRow< W > &b, size_t l)
bool OptimisedSolve(const eh_HashState &base_state, const std::function< bool(std::vector< unsigned char >)> validBlock, const std::function< bool(EhSolverCancelCheck)> cancelled)
uint32_t htole32(uint32_t host_32bits)
EhSolverCancelledException solver_cancelled
void CollideBranches(std::vector< FullStepRow< WIDTH >> &X, const size_t hlen, const size_t lenIndices, const unsigned int clen, const unsigned int ilen, const eh_trunc lt, const eh_trunc rt)
eh_index UntruncateIndex(const eh_trunc t, const eh_index r, const unsigned int ilen)
uint32_t be32toh(uint32_t big_endian_32bits)