Skip to content

Commit

Permalink
Auto merge of zcash#1578 - daira:1570.tromp-equihash-with-libsodium-b…
Browse files Browse the repository at this point in the history
…lake.2, r=daira

1570.tromp equihash with libsodium blake.2

Remove BLAKE2b implementation from Tromp Equihash solver, and address almost all of @str4d's review comments on zcash#1570. Supercedes zcash#1576.

Signed-off-by: Daira Hopwood [email protected]
  • Loading branch information
zkbot committed Oct 21, 2016
2 parents f0f838f + 5f0009b commit dc21a8a
Show file tree
Hide file tree
Showing 6 changed files with 871 additions and 12 deletions.
10 changes: 8 additions & 2 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand All @@ -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 = \
Expand Down
1 change: 1 addition & 0 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ std::string HelpMessage(HelpMessageMode mode)
#ifdef ENABLE_WALLET
strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), 0));
strUsage += HelpMessageOpt("-genproclimit=<n>", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), 1));
strUsage += HelpMessageOpt("-equihashsolver=<name>", _("Specify the Equihash solver to be used if enabled (default: \"default\")"));
#endif
strUsage += HelpMessageOpt("-help-debug", _("Show all debugging options (usage: --help -help-debug)"));
strUsage += HelpMessageOpt("-logips", strprintf(_("Include IP addresses in debug output (default: %u)"), 0));
Expand Down
60 changes: 50 additions & 10 deletions src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -453,6 +454,10 @@ void static BitcoinMiner(CWallet *pwallet)
unsigned int n = chainparams.EquihashN();
unsigned int k = chainparams.EquihashK();

std::string solver = GetArg("-equihashsolver", "default");
assert(solver == "tromp" || solver == "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(
Expand Down Expand Up @@ -524,8 +529,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<bool(std::vector<unsigned char>)> validBlock =
[&pblock, &hashTarget, &pwallet, &reservekey, &m_cs, &cancelSolver, &chainparams]
Expand Down Expand Up @@ -559,14 +564,49 @@ void static BitcoinMiner(CWallet *pwallet)
std::lock_guard<std::mutex> 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<std::mutex> lock{m_cs};
cancelSolver = false;

// TODO: factor this out into a function with the same API for each solver.
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<eh_index> index_vector(PROOFSIZE);
for (size_t i = 0; i < PROOFSIZE; i++) {
index_vector[i] = eq.sols[s][i];
}
std::vector<unsigned char> 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<std::mutex> lock{m_cs};
cancelSolver = false;
}
}

// Check for stop or if block needs to be rebuilt
Expand Down
98 changes: 98 additions & 0 deletions src/pow/tromp/equi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Equihash solver
// Copyright (c) 2016-2016 John Tromp, The Zcash developers

#include "sodium.h"
#ifdef __APPLE__
#include "pow/tromp/osx_barrier.h"
#endif
#include "compat/endian.h"

#include <stdint.h> // for types uint32_t,uint64_t
#include <string.h> // for functions memset
#include <stdlib.h> // for function qsort

typedef uint32_t u32;
typedef unsigned char uchar;

// algorithm parameters, prefixed with W to reduce include file conflicts

#ifndef WN
#define WN 200
#endif

#ifndef WK
#define WK 9
#endif

#define NDIGITS (WK+1)
#define DIGITBITS (WN/(NDIGITS))

static const u32 PROOFSIZE = 1<<WK;
static const u32 BASE = 1<<DIGITBITS;
static const u32 NHASHES = 2*BASE;
static const u32 HASHESPERBLAKE = 512/WN;
static const u32 HASHOUT = HASHESPERBLAKE*WN/8;

typedef u32 proof[PROOFSIZE];


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(const crypto_generichash_blake2b_state *ctx, u32 idx, uchar *hash) {
crypto_generichash_blake2b_state state = *ctx;
u32 leb = htole32(idx / HASHESPERBLAKE);
crypto_generichash_blake2b_update(&state, (uchar *)&leb, sizeof(u32));
uchar blakehash[HASHOUT];
crypto_generichash_blake2b_final(&state, blakehash, HASHOUT);
memcpy(hash, blakehash + (idx % HASHESPERBLAKE) * WN/8, WN/8);
}

int verifyrec(const crypto_generichash_blake2b_state *ctx, u32 *indices, uchar *hash, int r) {
if (r == 0) {
genhash(ctx, *indices, hash);
return POW_OK;
}
u32 *indices1 = indices + (1 << (r-1));
if (*indices >= *indices1)
return POW_OUT_OF_ORDER;
uchar hash0[WN/8], hash1[WN/8];
int vrf0 = verifyrec(ctx, indices, hash0, r-1);
if (vrf0 != POW_OK)
return vrf0;
int vrf1 = verifyrec(ctx, indices1, hash1, r-1);
if (vrf1 != POW_OK)
return vrf1;
for (int i=0; i < WN/8; i++)
hash[i] = hash0[i] ^ hash1[i];
int i, b = r * DIGITBITS;
for (i = 0; i < b/8; i++)
if (hash[i])
return POW_NONZERO_XOR;
if ((b%8) && hash[i] >> (8-(b%8)))
return POW_NONZERO_XOR;
return POW_OK;
}

int compu32(const void *pa, const void *pb) {
u32 a = *(u32 *)pa, b = *(u32 *)pb;
return a<b ? -1 : a==b ? 0 : +1;
}

bool duped(proof prf) {
proof sortprf;
memcpy(sortprf, prf, sizeof(proof));
qsort(sortprf, PROOFSIZE, sizeof(u32), &compu32);
for (u32 i=1; i<PROOFSIZE; i++)
if (sortprf[i] <= sortprf[i-1])
return true;
return false;
}

// verify Wagner conditions
int verify(u32 indices[PROOFSIZE], const crypto_generichash_blake2b_state *ctx) {
if (duped(indices))
return POW_DUPLICATE;
uchar hash[WN/8];
return verifyrec(ctx, indices, hash, WK);
}
Loading

0 comments on commit dc21a8a

Please sign in to comment.