From c7aaab7aa3f64aa93f19607c15fc18c019f1419c Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Thu, 20 Oct 2016 06:03:16 +0100 Subject: [PATCH] Integrate Tromp solver into miner code and remove its dependency on extra BLAKE2b implementation. Signed-off-by: Daira Hopwood --- src/Makefile.am | 10 +++++-- src/miner.cpp | 58 +++++++++++++++++++++++++++++++------- src/pow/tromp/equi.h | 55 ++++++++---------------------------- src/pow/tromp/equi_miner.h | 22 +++++++-------- 4 files changed, 79 insertions(+), 66 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 9f8a18189..4f3deaea7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -243,8 +243,13 @@ libbitcoin_wallet_a_SOURCES = \ $(BITCOIN_CORE_H) \ $(LIBZCASH_H) +EQUIHASH_TROMP_SOURCES = \ + pow/tromp/equi_miner.h \ + pow/tromp/equi.h \ + pow/tromp/osx_barrier.h + # crypto primitives library -crypto_libbitcoin_crypto_a_CPPFLAGS = $(BITCOIN_CONFIG_INCLUDES) +crypto_libbitcoin_crypto_a_CPPFLAGS = $(BITCOIN_CONFIG_INCLUDES) -DEQUIHASH_TROMP_ATOMIC crypto_libbitcoin_crypto_a_SOURCES = \ crypto/common.h \ crypto/equihash.cpp \ @@ -261,7 +266,8 @@ crypto_libbitcoin_crypto_a_SOURCES = \ crypto/sha256.cpp \ crypto/sha256.h \ crypto/sha512.cpp \ - crypto/sha512.h + crypto/sha512.h \ + ${EQUIHASH_TROMP_SOURCES} # univalue JSON library univalue_libbitcoin_univalue_a_SOURCES = \ diff --git a/src/miner.cpp b/src/miner.cpp index 472e91482..5540b0972 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -4,6 +4,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "miner.h" +#include "pow/tromp/equi_miner.h" #include "amount.h" #include "chainparams.h" @@ -453,6 +454,9 @@ void static BitcoinMiner(CWallet *pwallet) unsigned int n = chainparams.EquihashN(); unsigned int k = chainparams.EquihashK(); + std::string solver = GetArg("-equihashsolver", "default"); + LogPrint("pow", "Using Equihash solver \"%s\" with n = %u, k = %u\n", solver, n, k); + std::mutex m_cs; bool cancelSolver = false; boost::signals2::connection c = uiInterface.NotifyBlockTip.connect( @@ -524,8 +528,8 @@ void static BitcoinMiner(CWallet *pwallet) pblock->nNonce.size()); // (x_1, x_2, ...) = A(I, V, n, k) - LogPrint("pow", "Running Equihash solver with nNonce = %s\n", - pblock->nNonce.ToString()); + LogPrint("pow", "Running Equihash solver \"%s\" with nNonce = %s\n", + solver, pblock->nNonce.ToString()); std::function)> validBlock = [&pblock, &hashTarget, &pwallet, &reservekey, &m_cs, &cancelSolver, &chainparams] @@ -559,14 +563,48 @@ void static BitcoinMiner(CWallet *pwallet) std::lock_guard lock{m_cs}; return cancelSolver; }; - try { - // If we find a valid block, we rebuild - if (EhOptimisedSolve(n, k, curr_state, validBlock, cancelled)) - break; - } catch (EhSolverCancelledException&) { - LogPrint("pow", "Equihash solver cancelled\n"); - std::lock_guard lock{m_cs}; - cancelSolver = false; + + if (solver == "tromp") { + // Create solver and initialize it. + equi eq(1); + eq.setstate(&curr_state); + + // Intialization done, start algo driver. + eq.digit0(0); + eq.xfull = eq.bfull = eq.hfull = 0; + eq.showbsizes(0); + for (u32 r = 1; r < WK; r++) { + (r&1) ? eq.digitodd(r, 0) : eq.digiteven(r, 0); + eq.xfull = eq.bfull = eq.hfull = 0; + eq.showbsizes(r); + } + eq.digitK(0); + + // Convert solution indices to byte array (decompress) and pass it to validBlock method. + for (size_t s = 0; s < eq.nsols; s++) { + LogPrint("pow", "Checking solution %d\n", s+1); + std::vector index_vector(PROOFSIZE); + for (size_t i = 0; i < PROOFSIZE; i++) { + index_vector[i] = eq.sols[s][i]; + } + std::vector sol_char = GetMinimalFromIndices(index_vector, DIGITBITS); + + if (validBlock(sol_char)) { + // If we find a POW solution, do not try other solutions + // because they become invalid as we created a new block in blockchain. + break; + } + } + } else { + try { + // If we find a valid block, we rebuild + if (EhOptimisedSolve(n, k, curr_state, validBlock, cancelled)) + break; + } catch (EhSolverCancelledException&) { + LogPrint("pow", "Equihash solver cancelled\n"); + std::lock_guard lock{m_cs}; + cancelSolver = false; + } } // Check for stop or if block needs to be rebuilt diff --git a/src/pow/tromp/equi.h b/src/pow/tromp/equi.h index 7a0355a73..f6d8803c2 100644 --- a/src/pow/tromp/equi.h +++ b/src/pow/tromp/equi.h @@ -1,15 +1,12 @@ // Equihash solver -// Copyright (c) 2016-2016 John Tromp +// Copyright (c) 2016-2016 John Tromp, The Zcash developers -#include "blake/blake2.h" +#include "sodium.h" #ifdef __APPLE__ -#include "osx_barrier.h" -#include -#include -#define htole32(x) OSSwapHostToLittleInt32(x) -#else -#include +#include "pow/tromp/osx_barrier.h" #endif +#include "compat/endian.h" + #include // for types uint32_t,uint64_t #include // for functions memset #include // for function qsort @@ -38,46 +35,20 @@ static const u32 HASHOUT = HASHESPERBLAKE*WN/8; typedef u32 proof[PROOFSIZE]; -void setheader(blake2b_state *ctx, const char *header, const u32 headerlen, u32 nce) { - uint32_t le_N = htole32(WN); - uint32_t le_K = htole32(WK); - uchar personal[] = "ZcashPoW01230123"; - memcpy(personal+8, &le_N, 4); - memcpy(personal+12, &le_K, 4); - blake2b_param P[1]; - P->digest_length = HASHOUT; - P->key_length = 0; - P->fanout = 1; - P->depth = 1; - P->leaf_length = 0; - P->node_offset = 0; - P->node_depth = 0; - P->inner_length = 0; - memset(P->reserved, 0, sizeof(P->reserved)); - memset(P->salt, 0, sizeof(P->salt)); - memcpy(P->personal, (const uint8_t *)personal, 16); - blake2b_init_param(ctx, P); - blake2b_update(ctx, (const uchar *)header, headerlen); - uchar nonce[32]; - memset(nonce, 0, 32); - uint32_t le_nonce = htole32(nce); - memcpy(nonce, &le_nonce, 4); - blake2b_update(ctx, nonce, 32); -} enum verify_code { POW_OK, POW_DUPLICATE, POW_OUT_OF_ORDER, POW_NONZERO_XOR }; const char *errstr[] = { "OK", "duplicate index", "indices out of order", "nonzero xor" }; -void genhash(blake2b_state *ctx, u32 idx, uchar *hash) { - blake2b_state state = *ctx; +void genhash(const crypto_generichash_blake2b_state *ctx, u32 idx, uchar *hash) { + crypto_generichash_blake2b_state state = *ctx; u32 leb = htole32(idx / HASHESPERBLAKE); - blake2b_update(&state, (uchar *)&leb, sizeof(u32)); + crypto_generichash_blake2b_update(&state, (uchar *)&leb, sizeof(u32)); uchar blakehash[HASHOUT]; - blake2b_final(&state, blakehash, HASHOUT); + crypto_generichash_blake2b_final(&state, blakehash, HASHOUT); memcpy(hash, blakehash + (idx % HASHESPERBLAKE) * WN/8, WN/8); } -int verifyrec(blake2b_state *ctx, u32 *indices, uchar *hash, int r) { +int verifyrec(const crypto_generichash_blake2b_state *ctx, u32 *indices, uchar *hash, int r) { if (r == 0) { genhash(ctx, *indices, hash); return POW_OK; @@ -119,11 +90,9 @@ bool duped(proof prf) { } // verify Wagner conditions -int verify(u32 indices[PROOFSIZE], const char *header, const u32 headerlen, const u32 nonce) { +int verify(u32 indices[PROOFSIZE], const crypto_generichash_blake2b_state *ctx) { if (duped(indices)) return POW_DUPLICATE; - blake2b_state ctx; - setheader(&ctx, header, headerlen, nonce); uchar hash[WN/8]; - return verifyrec(&ctx, indices, hash, WK); + return verifyrec(ctx, indices, hash, WK); } diff --git a/src/pow/tromp/equi_miner.h b/src/pow/tromp/equi_miner.h index db2b83098..2f6531fe8 100644 --- a/src/pow/tromp/equi_miner.h +++ b/src/pow/tromp/equi_miner.h @@ -1,5 +1,5 @@ // Equihash solver -// Copyright (c) 2016 John Tromp +// Copyright (c) 2016 John Tromp, The Zcash developers // Fix N, K, such that n = N/(k+1) is integer // Fix M = 2^{n+1} hashes each of length N bits, @@ -18,7 +18,7 @@ // the i*n 0s, each bucket having 4 * 2^RESTBITS slots, // twice the number of subtrees expected to land there. -#include "equi.h" +#include "pow/tromp/equi.h" #include #include #include @@ -27,7 +27,7 @@ typedef uint16_t u16; typedef uint64_t u64; -#ifdef ATOMIC +#ifdef EQUIHASH_TROMP_ATOMIC #include typedef std::atomic au32; #else @@ -204,7 +204,7 @@ u32 min(const u32 a, const u32 b) { } struct equi { - blake2b_state blake_ctx; + crypto_generichash_blake2b_state blake_ctx; htalloc hta; bsizes *nslots; // PUT IN BUCKET STRUCT proof *sols; @@ -228,13 +228,13 @@ struct equi { free(nslots); free(sols); } - void setnonce(const char *header, const u32 headerlen, const u32 nonce) { - setheader(&blake_ctx, header, headerlen, nonce); + void setstate(const crypto_generichash_blake2b_state *ctx) { + blake_ctx = *ctx; memset(nslots, 0, NBUCKETS * sizeof(au32)); // only nslots[0] needs zeroing nsols = 0; } u32 getslot(const u32 r, const u32 bucketi) { -#ifdef ATOMIC +#ifdef EQUIHASH_TROMP_ATOMIC return std::atomic_fetch_add_explicit(&nslots[r&1][bucketi], 1U, std::memory_order_relaxed); #else return nslots[r&1][bucketi]++; @@ -282,7 +282,7 @@ struct equi { for (u32 i=1; i