Replace libsodium's crypto_generichash_blake2b with blake2b_simd

This commit is contained in:
Jack Grigg 2020-07-14 22:43:09 +12:00
parent ad56e9c2e9
commit 2d172e121f
24 changed files with 273 additions and 163 deletions

1
Cargo.lock generated
View File

@ -495,6 +495,7 @@ name = "librustzcash"
version = "0.2.0" version = "0.2.0"
dependencies = [ dependencies = [
"bellman", "bellman",
"blake2b_simd",
"blake2s_simd", "blake2s_simd",
"bls12_381", "bls12_381",
"ed25519-zebra", "ed25519-zebra",

View File

@ -21,6 +21,7 @@ crate-type = ["staticlib"]
[dependencies] [dependencies]
bellman = "0.8" bellman = "0.8"
blake2b_simd = "0.5"
blake2s_simd = "0.5" blake2s_simd = "0.5"
bls12_381 = "0.3" bls12_381 = "0.3"
group = "0.8" group = "0.8"

View File

@ -593,7 +593,7 @@ endif
libzcashconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS) libzcashconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS)
libzcashconsensus_la_LIBADD = $(LIBSECP256K1) libzcashconsensus_la_LIBADD = $(LIBSECP256K1)
libzcashconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL libzcashconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/rust/include -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL
libzcashconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libzcashconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
endif endif

View File

@ -21,6 +21,16 @@
#include "util.h" #include "util.h"
void eh_HashState::Update(const unsigned char *input, size_t inputLen)
{
blake2b_update(inner.get(), input, inputLen);
}
void eh_HashState::Finalize(unsigned char *hash, size_t hLen)
{
blake2b_finalize(inner.get(), hash, hLen);
}
// Used in TestEquihashValidator. // Used in TestEquihashValidator.
void CompressArray(const unsigned char* in, size_t in_len, void CompressArray(const unsigned char* in, size_t in_len,
@ -143,30 +153,24 @@ std::vector<unsigned char> GetMinimalFromIndices(std::vector<eh_index> indices,
static EhSolverCancelledException solver_cancelled; static EhSolverCancelledException solver_cancelled;
template<unsigned int N, unsigned int K> template<unsigned int N, unsigned int K>
int Equihash<N,K>::InitialiseState(eh_HashState& base_state) void Equihash<N,K>::InitialiseState(eh_HashState& base_state)
{ {
uint32_t le_N = htole32(N); uint32_t le_N = htole32(N);
uint32_t le_K = htole32(K); uint32_t le_K = htole32(K);
unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {}; unsigned char personalization[BLAKE2bPersonalBytes] = {};
memcpy(personalization, "ZcashPoW", 8); memcpy(personalization, "ZcashPoW", 8);
memcpy(personalization+8, &le_N, 4); memcpy(personalization+8, &le_N, 4);
memcpy(personalization+12, &le_K, 4); memcpy(personalization+12, &le_K, 4);
return crypto_generichash_blake2b_init_salt_personal(&base_state, base_state = eh_HashState((512/N)*N/8, personalization);
NULL, 0, // No key.
(512/N)*N/8,
NULL, // No salt.
personalization);
} }
void GenerateHash(const eh_HashState& base_state, eh_index g, void GenerateHash(const eh_HashState& base_state, eh_index g,
unsigned char* hash, size_t hLen) unsigned char* hash, size_t hLen)
{ {
eh_HashState state; eh_HashState state(base_state);
state = base_state;
eh_index lei = htole32(g); eh_index lei = htole32(g);
crypto_generichash_blake2b_update(&state, (const unsigned char*) &lei, state.Update((const unsigned char*) &lei, sizeof(eh_index));
sizeof(eh_index)); state.Finalize(hash, hLen);
crypto_generichash_blake2b_final(&state, hash, hLen);
} }
// Big-endian so that lexicographic array comparison is equivalent to integer // Big-endian so that lexicographic array comparison is equivalent to integer
@ -724,7 +728,7 @@ invalidsolution:
} }
// Explicit instantiations for Equihash<96,3> // Explicit instantiations for Equihash<96,3>
template int Equihash<96,3>::InitialiseState(eh_HashState& base_state); template void Equihash<96,3>::InitialiseState(eh_HashState& base_state);
template bool Equihash<96,3>::BasicSolve(const eh_HashState& base_state, template bool Equihash<96,3>::BasicSolve(const eh_HashState& base_state,
const std::function<bool(std::vector<unsigned char>)> validBlock, const std::function<bool(std::vector<unsigned char>)> validBlock,
const std::function<bool(EhSolverCancelCheck)> cancelled); const std::function<bool(EhSolverCancelCheck)> cancelled);
@ -733,7 +737,7 @@ template bool Equihash<96,3>::OptimisedSolve(const eh_HashState& base_state,
const std::function<bool(EhSolverCancelCheck)> cancelled); const std::function<bool(EhSolverCancelCheck)> cancelled);
// Explicit instantiations for Equihash<200,9> // Explicit instantiations for Equihash<200,9>
template int Equihash<200,9>::InitialiseState(eh_HashState& base_state); template void Equihash<200,9>::InitialiseState(eh_HashState& base_state);
template bool Equihash<200,9>::BasicSolve(const eh_HashState& base_state, template bool Equihash<200,9>::BasicSolve(const eh_HashState& base_state,
const std::function<bool(std::vector<unsigned char>)> validBlock, const std::function<bool(std::vector<unsigned char>)> validBlock,
const std::function<bool(EhSolverCancelCheck)> cancelled); const std::function<bool(EhSolverCancelCheck)> cancelled);
@ -742,7 +746,7 @@ template bool Equihash<200,9>::OptimisedSolve(const eh_HashState& base_state,
const std::function<bool(EhSolverCancelCheck)> cancelled); const std::function<bool(EhSolverCancelCheck)> cancelled);
// Explicit instantiations for Equihash<96,5> // Explicit instantiations for Equihash<96,5>
template int Equihash<96,5>::InitialiseState(eh_HashState& base_state); template void Equihash<96,5>::InitialiseState(eh_HashState& base_state);
template bool Equihash<96,5>::BasicSolve(const eh_HashState& base_state, template bool Equihash<96,5>::BasicSolve(const eh_HashState& base_state,
const std::function<bool(std::vector<unsigned char>)> validBlock, const std::function<bool(std::vector<unsigned char>)> validBlock,
const std::function<bool(EhSolverCancelCheck)> cancelled); const std::function<bool(EhSolverCancelCheck)> cancelled);
@ -751,7 +755,7 @@ template bool Equihash<96,5>::OptimisedSolve(const eh_HashState& base_state,
const std::function<bool(EhSolverCancelCheck)> cancelled); const std::function<bool(EhSolverCancelCheck)> cancelled);
// Explicit instantiations for Equihash<48,5> // Explicit instantiations for Equihash<48,5>
template int Equihash<48,5>::InitialiseState(eh_HashState& base_state); template void Equihash<48,5>::InitialiseState(eh_HashState& base_state);
template bool Equihash<48,5>::BasicSolve(const eh_HashState& base_state, template bool Equihash<48,5>::BasicSolve(const eh_HashState& base_state,
const std::function<bool(std::vector<unsigned char>)> validBlock, const std::function<bool(std::vector<unsigned char>)> validBlock,
const std::function<bool(EhSolverCancelCheck)> cancelled); const std::function<bool(EhSolverCancelCheck)> cancelled);

View File

@ -32,8 +32,6 @@ void EhIndexToArray(const eh_index i, unsigned char* array);
#include "crypto/sha256.h" #include "crypto/sha256.h"
#include "utilstrencodings.h" #include "utilstrencodings.h"
#include "sodium.h"
#include <cstring> #include <cstring>
#include <exception> #include <exception>
#include <stdexcept> #include <stdexcept>
@ -41,8 +39,35 @@ void EhIndexToArray(const eh_index i, unsigned char* array);
#include <set> #include <set>
#include <boost/static_assert.hpp> #include <boost/static_assert.hpp>
#include <rust/blake2b.h>
typedef crypto_generichash_blake2b_state eh_HashState; struct eh_HashState {
std::unique_ptr<BLAKE2bState, decltype(&blake2b_free)> inner;
eh_HashState() : inner(nullptr, blake2b_free) {}
eh_HashState(size_t length, unsigned char personalization[BLAKE2bPersonalBytes]) : inner(blake2b_init(length, personalization), blake2b_free) {}
eh_HashState(eh_HashState&& baseState) : inner(std::move(baseState.inner)) {}
eh_HashState(const eh_HashState& baseState) : inner(blake2b_clone(baseState.inner.get()), blake2b_free) {}
eh_HashState& operator=(eh_HashState&& baseState)
{
if (this != &baseState) {
inner = std::move(baseState.inner);
}
return *this;
}
eh_HashState& operator=(const eh_HashState& baseState)
{
if (this != &baseState) {
inner.reset(blake2b_clone(baseState.inner.get()));
}
return *this;
}
void Update(const unsigned char *input, size_t inputLen);
void Finalize(unsigned char *hash, size_t hLen);
};
eh_index ArrayToEhIndex(const unsigned char* array); eh_index ArrayToEhIndex(const unsigned char* array);
eh_trunc TruncateIndex(const eh_index i, const unsigned int ilen); eh_trunc TruncateIndex(const eh_index i, const unsigned int ilen);
@ -188,7 +213,7 @@ public:
Equihash() { } Equihash() { }
int InitialiseState(eh_HashState& base_state); void InitialiseState(eh_HashState& base_state);
bool BasicSolve(const eh_HashState& base_state, bool BasicSolve(const eh_HashState& base_state,
const std::function<bool(std::vector<unsigned char>)> validBlock, const std::function<bool(std::vector<unsigned char>)> validBlock,
const std::function<bool(EhSolverCancelCheck)> cancelled); const std::function<bool(EhSolverCancelCheck)> cancelled);

View File

@ -86,10 +86,10 @@ TEST(EquihashTests, IsProbablyDuplicate) {
TEST(EquihashTests, CheckBasicSolverCancelled) { TEST(EquihashTests, CheckBasicSolverCancelled) {
Equihash<48,5> Eh48_5; Equihash<48,5> Eh48_5;
crypto_generichash_blake2b_state state; eh_HashState state;
Eh48_5.InitialiseState(state); Eh48_5.InitialiseState(state);
uint256 V = uint256S("0x00"); uint256 V = uint256S("0x00");
crypto_generichash_blake2b_update(&state, V.begin(), V.size()); state.Update(V.begin(), V.size());
{ {
ASSERT_NO_THROW(Eh48_5.BasicSolve(state, [](std::vector<unsigned char> soln) { ASSERT_NO_THROW(Eh48_5.BasicSolve(state, [](std::vector<unsigned char> soln) {
@ -190,10 +190,10 @@ TEST(EquihashTests, CheckBasicSolverCancelled) {
TEST(EquihashTests, CheckOptimisedSolverCancelled) { TEST(EquihashTests, CheckOptimisedSolverCancelled) {
Equihash<48,5> Eh48_5; Equihash<48,5> Eh48_5;
crypto_generichash_blake2b_state state; eh_HashState state;
Eh48_5.InitialiseState(state); Eh48_5.InitialiseState(state);
uint256 V = uint256S("0x00"); uint256 V = uint256S("0x00");
crypto_generichash_blake2b_update(&state, V.begin(), V.size()); state.Update(V.begin(), V.size());
{ {
ASSERT_NO_THROW(Eh48_5.OptimisedSolve(state, [](std::vector<unsigned char> soln) { ASSERT_NO_THROW(Eh48_5.OptimisedSolve(state, [](std::vector<unsigned char> soln) {

View File

@ -13,10 +13,10 @@
#include "uint256.h" #include "uint256.h"
#include "version.h" #include "version.h"
#include "sodium.h"
#include <vector> #include <vector>
#include <rust/blake2b.h>
typedef uint256 ChainCode; typedef uint256 ChainCode;
/** A hasher class for Bitcoin's 256-bit hash (double SHA-256). */ /** A hasher class for Bitcoin's 256-bit hash (double SHA-256). */
@ -167,33 +167,31 @@ public:
class CBLAKE2bWriter class CBLAKE2bWriter
{ {
private: private:
crypto_generichash_blake2b_state state; BLAKE2bState* state;
public: public:
int nType; int nType;
int nVersion; int nVersion;
CBLAKE2bWriter(int nTypeIn, int nVersionIn, const unsigned char* personal) : nType(nTypeIn), nVersion(nVersionIn) { CBLAKE2bWriter(int nTypeIn, int nVersionIn, const unsigned char* personal) : nType(nTypeIn), nVersion(nVersionIn) {
assert(crypto_generichash_blake2b_init_salt_personal( state = blake2b_init(32, personal);
&state, }
NULL, 0, // No key. ~CBLAKE2bWriter() {
32, blake2b_free(state);
NULL, // No salt.
personal) == 0);
} }
int GetType() const { return nType; } int GetType() const { return nType; }
int GetVersion() const { return nVersion; } int GetVersion() const { return nVersion; }
CBLAKE2bWriter& write(const char *pch, size_t size) { CBLAKE2bWriter& write(const char *pch, size_t size) {
crypto_generichash_blake2b_update(&state, (const unsigned char*)pch, size); blake2b_update(state, (const unsigned char*)pch, size);
return (*this); return (*this);
} }
// invalidates the object // invalidates the object
uint256 GetHash() { uint256 GetHash() {
uint256 result; uint256 result;
crypto_generichash_blake2b_final(&state, (unsigned char*)&result, 32); blake2b_finalize(state, (unsigned char*)&result, 32);
return result; return result;
} }

View File

@ -35,7 +35,6 @@
#include "validationinterface.h" #include "validationinterface.h"
#include <librustzcash.h> #include <librustzcash.h>
#include "sodium.h"
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp> #include <boost/tuple/tuple.hpp>
@ -796,7 +795,7 @@ void static BitcoinMiner(const CChainParams& chainparams)
while (true) { while (true) {
// Hash state // Hash state
crypto_generichash_blake2b_state state; eh_HashState state;
EhInitialiseState(n, k, state); EhInitialiseState(n, k, state);
// I = the block header minus nonce and solution. // I = the block header minus nonce and solution.
@ -805,14 +804,12 @@ void static BitcoinMiner(const CChainParams& chainparams)
ss << I; ss << I;
// H(I||... // H(I||...
crypto_generichash_blake2b_update(&state, (unsigned char*)&ss[0], ss.size()); state.Update((unsigned char*)&ss[0], ss.size());
// H(I||V||... // H(I||V||...
crypto_generichash_blake2b_state curr_state; eh_HashState curr_state;
curr_state = state; curr_state = state;
crypto_generichash_blake2b_update(&curr_state, curr_state.Update(pblock->nNonce.begin(), pblock->nNonce.size());
pblock->nNonce.begin(),
pblock->nNonce.size());
// (x_1, x_2, ...) = A(I, V, n, k) // (x_1, x_2, ...) = A(I, V, n, k)
LogPrint("pow", "Running Equihash solver \"%s\" with nNonce = %s\n", LogPrint("pow", "Running Equihash solver \"%s\" with nNonce = %s\n",
@ -860,7 +857,7 @@ void static BitcoinMiner(const CChainParams& chainparams)
if (solver == "tromp") { if (solver == "tromp") {
// Create solver and initialize it. // Create solver and initialize it.
equi eq(1); equi eq(1);
eq.setstate(&curr_state); eq.setstate(curr_state.inner.get());
// Initialization done, start algo driver. // Initialization done, start algo driver.
eq.digit0(0); eq.digit0(0);

View File

@ -1,7 +1,6 @@
// Equihash solver // Equihash solver
// Copyright (c) 2016-2016 John Tromp, The Zcash developers // Copyright (c) 2016-2016 John Tromp, The Zcash developers
#include "sodium.h"
#ifdef __APPLE__ #ifdef __APPLE__
#include "pow/tromp/osx_barrier.h" #include "pow/tromp/osx_barrier.h"
#endif #endif
@ -11,6 +10,8 @@
#include <string.h> // for functions memset #include <string.h> // for functions memset
#include <stdlib.h> // for function qsort #include <stdlib.h> // for function qsort
#include <rust/blake2b.h>
typedef uint32_t u32; typedef uint32_t u32;
typedef unsigned char uchar; typedef unsigned char uchar;
@ -39,16 +40,17 @@ typedef u32 proof[PROOFSIZE];
enum verify_code { POW_OK, POW_DUPLICATE, POW_OUT_OF_ORDER, POW_NONZERO_XOR }; 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" }; const char *errstr[] = { "OK", "duplicate index", "indices out of order", "nonzero xor" };
void genhash(const crypto_generichash_blake2b_state *ctx, u32 idx, uchar *hash) { void genhash(const BLAKE2bState *ctx, u32 idx, uchar *hash) {
crypto_generichash_blake2b_state state = *ctx; auto state = blake2b_clone(ctx);
u32 leb = htole32(idx / HASHESPERBLAKE); u32 leb = htole32(idx / HASHESPERBLAKE);
crypto_generichash_blake2b_update(&state, (uchar *)&leb, sizeof(u32)); blake2b_update(state, (uchar *)&leb, sizeof(u32));
uchar blakehash[HASHOUT]; uchar blakehash[HASHOUT];
crypto_generichash_blake2b_final(&state, blakehash, HASHOUT); blake2b_finalize(state, blakehash, HASHOUT);
blake2b_free(state);
memcpy(hash, blakehash + (idx % HASHESPERBLAKE) * WN/8, WN/8); memcpy(hash, blakehash + (idx % HASHESPERBLAKE) * WN/8, WN/8);
} }
int verifyrec(const crypto_generichash_blake2b_state *ctx, u32 *indices, uchar *hash, int r) { int verifyrec(const BLAKE2bState *ctx, u32 *indices, uchar *hash, int r) {
if (r == 0) { if (r == 0) {
genhash(ctx, *indices, hash); genhash(ctx, *indices, hash);
return POW_OK; return POW_OK;
@ -90,7 +92,7 @@ bool duped(proof prf) {
} }
// verify Wagner conditions // verify Wagner conditions
int verify(u32 indices[PROOFSIZE], const crypto_generichash_blake2b_state *ctx) { int verify(u32 indices[PROOFSIZE], const BLAKE2bState *ctx) {
if (duped(indices)) if (duped(indices))
return POW_DUPLICATE; return POW_DUPLICATE;
uchar hash[WN/8]; uchar hash[WN/8];

View File

@ -204,7 +204,7 @@ u32 min(const u32 a, const u32 b) {
} }
struct equi { struct equi {
crypto_generichash_blake2b_state blake_ctx; BLAKE2bState* blake_ctx;
htalloc hta; htalloc hta;
bsizes *nslots; // PUT IN BUCKET STRUCT bsizes *nslots; // PUT IN BUCKET STRUCT
proof *sols; proof *sols;
@ -227,9 +227,10 @@ struct equi {
hta.dealloctrees(); hta.dealloctrees();
free(nslots); free(nslots);
free(sols); free(sols);
blake2b_free(blake_ctx);
} }
void setstate(const crypto_generichash_blake2b_state *ctx) { void setstate(const BLAKE2bState *ctx) {
blake_ctx = *ctx; blake_ctx = blake2b_clone(ctx);
memset(nslots, 0, NBUCKETS * sizeof(au32)); // only nslots[0] needs zeroing memset(nslots, 0, NBUCKETS * sizeof(au32)); // only nslots[0] needs zeroing
nsols = 0; nsols = 0;
} }
@ -431,14 +432,15 @@ struct equi {
void digit0(const u32 id) { void digit0(const u32 id) {
uchar hash[HASHOUT]; uchar hash[HASHOUT];
crypto_generichash_blake2b_state state; BLAKE2bState* state;
htlayout htl(this, 0); htlayout htl(this, 0);
const u32 hashbytes = hashsize(0); const u32 hashbytes = hashsize(0);
for (u32 block = id; block < NBLOCKS; block += nthreads) { for (u32 block = id; block < NBLOCKS; block += nthreads) {
state = blake_ctx; state = blake2b_clone(blake_ctx);
u32 leb = htole32(block); u32 leb = htole32(block);
crypto_generichash_blake2b_update(&state, (uchar *)&leb, sizeof(u32)); blake2b_update(state, (uchar *)&leb, sizeof(u32));
crypto_generichash_blake2b_final(&state, hash, HASHOUT); blake2b_finalize(state, hash, HASHOUT);
blake2b_free(state);
for (u32 i = 0; i<HASHESPERBLAKE; i++) { for (u32 i = 0; i<HASHESPERBLAKE; i++) {
const uchar *ph = hash + i * WN/8; const uchar *ph = hash + i * WN/8;
#if BUCKBITS == 16 && RESTBITS == 4 #if BUCKBITS == 16 && RESTBITS == 4

View File

@ -214,7 +214,7 @@ UniValue generate(const UniValue& params, bool fHelp)
} }
// Hash state // Hash state
crypto_generichash_blake2b_state eh_state; eh_HashState eh_state;
EhInitialiseState(n, k, eh_state); EhInitialiseState(n, k, eh_state);
// I = the block header minus nonce and solution. // I = the block header minus nonce and solution.
@ -223,7 +223,7 @@ UniValue generate(const UniValue& params, bool fHelp)
ss << I; ss << I;
// H(I||... // H(I||...
crypto_generichash_blake2b_update(&eh_state, (unsigned char*)&ss[0], ss.size()); eh_state.Update((unsigned char*)&ss[0], ss.size());
while (true) { while (true) {
// Yes, there is a chance every nonce could fail to satisfy the -regtest // Yes, there is a chance every nonce could fail to satisfy the -regtest
@ -231,11 +231,8 @@ UniValue generate(const UniValue& params, bool fHelp)
pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1); pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1);
// H(I||V||... // H(I||V||...
crypto_generichash_blake2b_state curr_state; eh_HashState curr_state(eh_state);
curr_state = eh_state; curr_state.Update(pblock->nNonce.begin(), pblock->nNonce.size());
crypto_generichash_blake2b_update(&curr_state,
pblock->nNonce.begin(),
pblock->nNonce.size());
// (x_1, x_2, ...) = A(I, V, n, k) // (x_1, x_2, ...) = A(I, V, n, k)
std::function<bool(std::vector<unsigned char>)> validBlock = std::function<bool(std::vector<unsigned char>)> validBlock =

View File

@ -0,0 +1,59 @@
// Copyright (c) 2020 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
#ifndef BLAKE2B_INCLUDE_H_
#define BLAKE2B_INCLUDE_H_
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
struct BLAKE2bState;
typedef struct BLAKE2bState BLAKE2bState;
#define BLAKE2bPersonalBytes 16U
/// Initializes a BLAKE2b state with no key and no salt.
///
/// `personalization` MUST be a pointer to a 16-byte array.
///
/// Please free this with `blake2b_free` when you are done.
BLAKE2bState* blake2b_init(
size_t output_len,
const unsigned char* personalization);
/// Clones the given BLAKE2b state.
///
/// Both states need to be separately freed with `blake2b_free` when you are
/// done.
BLAKE2bState* blake2b_clone(const BLAKE2bState* state);
/// Frees a BLAKE2b state returned by `blake2b_init`.
void blake2b_free(BLAKE2bState* state);
/// Adds input to the hash. You can call this any number of times.
void blake2b_update(
BLAKE2bState* state,
const unsigned char* input,
size_t input_len);
/// Finalizes the `state` and stores the result in `output`.
///
/// `output_len` MUST be the same value as was passed as the first parameter to
/// `blake2b_init`.
///
/// This method is idempotent, and calling it multiple times will give the same
/// result. It's also possible to call `blake2b_update` with more input in
/// between.
void blake2b_finalize(
BLAKE2bState* state,
unsigned char* output,
size_t output_len);
#ifdef __cplusplus
}
#endif
#endif // BLAKE2B_INCLUDE_H_

53
src/rust/src/blake2b.rs Normal file
View File

@ -0,0 +1,53 @@
// Copyright (c) 2020 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
use blake2b_simd::{State, PERSONALBYTES};
use libc::{c_uchar, size_t};
use std::ptr;
use std::slice;
#[no_mangle]
pub extern "C" fn blake2b_init(
output_len: size_t,
personalization: *const [c_uchar; PERSONALBYTES],
) -> *mut State {
let personalization = unsafe { personalization.as_ref().unwrap() };
Box::into_raw(Box::new(
blake2b_simd::Params::new()
.hash_length(output_len)
.personal(personalization)
.to_state(),
))
}
#[no_mangle]
pub extern "C" fn blake2b_clone(state: *const State) -> *mut State {
unsafe { state.as_ref() }
.map(|state| Box::into_raw(Box::new(state.clone())))
.unwrap_or(ptr::null_mut())
}
#[no_mangle]
pub extern "C" fn blake2b_free(state: *mut State) {
if !state.is_null() {
drop(unsafe { Box::from_raw(state) });
}
}
#[no_mangle]
pub extern "C" fn blake2b_update(state: *mut State, input: *const c_uchar, input_len: size_t) {
let state = unsafe { state.as_mut().unwrap() };
let input = unsafe { slice::from_raw_parts(input, input_len) };
state.update(input);
}
#[no_mangle]
pub extern "C" fn blake2b_finalize(state: *mut State, output: *mut c_uchar, output_len: size_t) {
let state = unsafe { state.as_mut().unwrap() };
let output = unsafe { slice::from_raw_parts_mut(output, output_len) };
output.copy_from_slice(state.finalize().as_bytes());
}

View File

@ -61,6 +61,7 @@ use zcash_proofs::{
use zcash_history::{Entry as MMREntry, NodeData as MMRNodeData, Tree as MMRTree}; use zcash_history::{Entry as MMREntry, NodeData as MMRNodeData, Tree as MMRTree};
mod blake2b;
mod ed25519; mod ed25519;
mod tracing_ffi; mod tracing_ffi;

View File

@ -14,6 +14,8 @@
#include "script/script.h" #include "script/script.h"
#include "uint256.h" #include "uint256.h"
#include <librustzcash.h>
using namespace std; using namespace std;
typedef vector<unsigned char> valtype; typedef vector<unsigned char> valtype;
@ -1057,17 +1059,17 @@ public:
} }
}; };
const unsigned char ZCASH_PREVOUTS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] = const unsigned char ZCASH_PREVOUTS_HASH_PERSONALIZATION[BLAKE2bPersonalBytes] =
{'Z','c','a','s','h','P','r','e','v','o','u','t','H','a','s','h'}; {'Z','c','a','s','h','P','r','e','v','o','u','t','H','a','s','h'};
const unsigned char ZCASH_SEQUENCE_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] = const unsigned char ZCASH_SEQUENCE_HASH_PERSONALIZATION[BLAKE2bPersonalBytes] =
{'Z','c','a','s','h','S','e','q','u','e','n','c','H','a','s','h'}; {'Z','c','a','s','h','S','e','q','u','e','n','c','H','a','s','h'};
const unsigned char ZCASH_OUTPUTS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] = const unsigned char ZCASH_OUTPUTS_HASH_PERSONALIZATION[BLAKE2bPersonalBytes] =
{'Z','c','a','s','h','O','u','t','p','u','t','s','H','a','s','h'}; {'Z','c','a','s','h','O','u','t','p','u','t','s','H','a','s','h'};
const unsigned char ZCASH_JOINSPLITS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] = const unsigned char ZCASH_JOINSPLITS_HASH_PERSONALIZATION[BLAKE2bPersonalBytes] =
{'Z','c','a','s','h','J','S','p','l','i','t','s','H','a','s','h'}; {'Z','c','a','s','h','J','S','p','l','i','t','s','H','a','s','h'};
const unsigned char ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] = const unsigned char ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION[BLAKE2bPersonalBytes] =
{'Z','c','a','s','h','S','S','p','e','n','d','s','H','a','s','h'}; {'Z','c','a','s','h','S','S','p','e','n','d','s','H','a','s','h'};
const unsigned char ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] = const unsigned char ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION[BLAKE2bPersonalBytes] =
{'Z','c','a','s','h','S','O','u','t','p','u','t','H','a','s','h'}; {'Z','c','a','s','h','S','O','u','t','p','u','t','H','a','s','h'};
uint256 GetPrevoutHash(const CTransaction& txTo) { uint256 GetPrevoutHash(const CTransaction& txTo) {

View File

@ -13,8 +13,6 @@
#include "test/test_bitcoin.h" #include "test/test_bitcoin.h"
#include "uint256.h" #include "uint256.h"
#include "sodium.h"
#include "librustzcash.h" #include "librustzcash.h"
#include <sstream> #include <sstream>
@ -49,12 +47,12 @@ void PrintSolutions(std::stringstream &strm, std::set<std::vector<uint32_t>> sol
#ifdef ENABLE_MINING #ifdef ENABLE_MINING
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) {
size_t cBitLen { n/(k+1) }; size_t cBitLen { n/(k+1) };
crypto_generichash_blake2b_state state; eh_HashState state;
EhInitialiseState(n, k, 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()); state.Update((unsigned char*)&I[0], I.size());
crypto_generichash_blake2b_update(&state, V.begin(), V.size()); state.Update(V.begin(), V.size());
// First test the basic solver // First test the basic solver
std::set<std::vector<uint32_t>> ret; std::set<std::vector<uint32_t>> ret;

View File

@ -199,7 +199,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
unsigned int k = Params().GetConsensus().nEquihashK; unsigned int k = Params().GetConsensus().nEquihashK;
// Hash state // Hash state
crypto_generichash_blake2b_state eh_state; eh_HashState eh_state;
EhInitialiseState(n, k, eh_state); EhInitialiseState(n, k, eh_state);
// I = the block header minus nonce and solution. // I = the block header minus nonce and solution.
@ -208,21 +208,18 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
ss << I; ss << I;
// H(I||... // H(I||...
crypto_generichash_blake2b_update(&eh_state, (unsigned char*)&ss[0], ss.size()); eh_state.Update((unsigned char*)&ss[0], ss.size());
while (true) { while (true) {
pblock->nNonce = ArithToUint256(try_nonce); pblock->nNonce = ArithToUint256(try_nonce);
// H(I||V||... // H(I||V||...
crypto_generichash_blake2b_state curr_state; eh_HashState curr_state(eh_state);
curr_state = eh_state; curr_state.Update(pblock->nNonce.begin(), pblock->nNonce.size());
crypto_generichash_blake2b_update(&curr_state,
pblock->nNonce.begin(),
pblock->nNonce.size());
// Create solver and initialize it. // Create solver and initialize it.
equi eq(1); equi eq(1);
eq.setstate(&curr_state); eq.setstate(curr_state.state);
// Intialization done, start algo driver. // Intialization done, start algo driver.
eq.digit0(0); eq.digit0(0);

View File

@ -163,7 +163,7 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>&
IncrementExtraNonce(&block, chainActive.Tip(), extraNonce); IncrementExtraNonce(&block, chainActive.Tip(), extraNonce);
// Hash state // Hash state
crypto_generichash_blake2b_state eh_state; eh_HashState eh_state;
EhInitialiseState(n, k, eh_state); EhInitialiseState(n, k, eh_state);
// I = the block header minus nonce and solution. // I = the block header minus nonce and solution.
@ -172,18 +172,15 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>&
ss << I; ss << I;
// H(I||... // H(I||...
crypto_generichash_blake2b_update(&eh_state, (unsigned char*)&ss[0], ss.size()); eh_state.Update((unsigned char*)&ss[0], ss.size());
bool found = false; bool found = false;
do { do {
block.nNonce = ArithToUint256(UintToArith256(block.nNonce) + 1); block.nNonce = ArithToUint256(UintToArith256(block.nNonce) + 1);
// H(I||V||... // H(I||V||...
crypto_generichash_blake2b_state curr_state; eh_HashState curr_state(eh_state);
curr_state = eh_state; curr_state.Update(block.nNonce.begin(), block.nNonce.size());
crypto_generichash_blake2b_update(&curr_state,
block.nNonce.begin(),
block.nNonce.size());
// (x_1, x_2, ...) = A(I, V, n, k) // (x_1, x_2, ...) = A(I, V, n, k)
std::function<bool(std::vector<unsigned char>)> validBlock = std::function<bool(std::vector<unsigned char>)> validBlock =

View File

@ -1,6 +1,5 @@
#include "JoinSplit.hpp" #include "JoinSplit.hpp"
#include "prf.h" #include "prf.h"
#include "sodium.h"
#include "zcash/util.h" #include "zcash/util.h"
@ -18,6 +17,8 @@
#include "streams.h" #include "streams.h"
#include "version.h" #include "version.h"
#include <rust/blake2b.h>
namespace libzcash { namespace libzcash {
template<size_t NumInputs, size_t NumOutputs> template<size_t NumInputs, size_t NumOutputs>
@ -207,7 +208,7 @@ uint256 JoinSplit<NumInputs, NumOutputs>::h_sig(
const std::array<uint256, NumInputs>& nullifiers, const std::array<uint256, NumInputs>& nullifiers,
const Ed25519VerificationKey& joinSplitPubKey const Ed25519VerificationKey& joinSplitPubKey
) { ) {
const unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] const unsigned char personalization[BLAKE2bPersonalBytes]
= {'Z','c','a','s','h','C','o','m','p','u','t','e','h','S','i','g'}; = {'Z','c','a','s','h','C','o','m','p','u','t','e','h','S','i','g'};
std::vector<unsigned char> block(randomSeed.begin(), randomSeed.end()); std::vector<unsigned char> block(randomSeed.begin(), randomSeed.end());
@ -220,15 +221,10 @@ uint256 JoinSplit<NumInputs, NumOutputs>::h_sig(
uint256 output; uint256 output;
if (crypto_generichash_blake2b_salt_personal(output.begin(), 32, auto state = blake2b_init(32, personalization);
&block[0], block.size(), blake2b_update(state, &block[0], block.size());
NULL, 0, // No key. blake2b_finalize(state, output.begin(), 32);
NULL, // No salt. blake2b_free(state);
personalization
) != 0)
{
throw std::logic_error("hash function failure");
}
return output; return output;
} }

View File

@ -8,6 +8,8 @@
#include "prf.h" #include "prf.h"
#include "librustzcash.h" #include "librustzcash.h"
#include <rust/blake2b.h>
#define NOTEENCRYPTION_CIPHER_KEYSIZE 32 #define NOTEENCRYPTION_CIPHER_KEYSIZE 32
void clamp_curve25519(unsigned char key[crypto_scalarmult_SCALARBYTES]) void clamp_curve25519(unsigned char key[crypto_scalarmult_SCALARBYTES])
@ -31,18 +33,13 @@ void PRF_ock(
memcpy(block+64, cm.begin(), 32); memcpy(block+64, cm.begin(), 32);
memcpy(block+96, epk.begin(), 32); memcpy(block+96, epk.begin(), 32);
unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {}; unsigned char personalization[BLAKE2bPersonalBytes] = {};
memcpy(personalization, "Zcash_Derive_ock", 16); memcpy(personalization, "Zcash_Derive_ock", 16);
if (crypto_generichash_blake2b_salt_personal(K, NOTEENCRYPTION_CIPHER_KEYSIZE, auto state = blake2b_init(NOTEENCRYPTION_CIPHER_KEYSIZE, personalization);
block, 128, blake2b_update(state, block, 128);
NULL, 0, // No key. blake2b_finalize(state, K, NOTEENCRYPTION_CIPHER_KEYSIZE);
NULL, // No salt. blake2b_free(state);
personalization
) != 0)
{
throw std::logic_error("hash function failure");
}
} }
void KDF_Sapling( void KDF_Sapling(
@ -55,18 +52,13 @@ void KDF_Sapling(
memcpy(block+0, dhsecret.begin(), 32); memcpy(block+0, dhsecret.begin(), 32);
memcpy(block+32, epk.begin(), 32); memcpy(block+32, epk.begin(), 32);
unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {}; unsigned char personalization[BLAKE2bPersonalBytes] = {};
memcpy(personalization, "Zcash_SaplingKDF", 16); memcpy(personalization, "Zcash_SaplingKDF", 16);
if (crypto_generichash_blake2b_salt_personal(K, NOTEENCRYPTION_CIPHER_KEYSIZE, auto state = blake2b_init(NOTEENCRYPTION_CIPHER_KEYSIZE, personalization);
block, 64, blake2b_update(state, block, 64);
NULL, 0, // No key. blake2b_finalize(state, K, NOTEENCRYPTION_CIPHER_KEYSIZE);
NULL, // No salt. blake2b_free(state);
personalization
) != 0)
{
throw std::logic_error("hash function failure");
}
} }
void KDF(unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE], void KDF(unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE],
@ -87,19 +79,14 @@ void KDF(unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE],
memcpy(block+64, epk.begin(), 32); memcpy(block+64, epk.begin(), 32);
memcpy(block+96, pk_enc.begin(), 32); memcpy(block+96, pk_enc.begin(), 32);
unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {}; unsigned char personalization[BLAKE2bPersonalBytes] = {};
memcpy(personalization, "ZcashKDF", 8); memcpy(personalization, "ZcashKDF", 8);
memcpy(personalization+8, &nonce, 1); memcpy(personalization+8, &nonce, 1);
if (crypto_generichash_blake2b_salt_personal(K, NOTEENCRYPTION_CIPHER_KEYSIZE, auto state = blake2b_init(NOTEENCRYPTION_CIPHER_KEYSIZE, personalization);
block, 128, blake2b_update(state, block, 128);
NULL, 0, // No key. blake2b_finalize(state, K, NOTEENCRYPTION_CIPHER_KEYSIZE);
NULL, // No salt. blake2b_free(state);
personalization
) != 0)
{
throw std::logic_error("hash function failure");
}
} }
namespace libzcash { namespace libzcash {

View File

@ -13,7 +13,7 @@
namespace libzcash { namespace libzcash {
const unsigned char ZCASH_SAPLING_FVFP_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] = const unsigned char ZCASH_SAPLING_FVFP_PERSONALIZATION[BLAKE2bPersonalBytes] =
{'Z', 'c', 'a', 's', 'h', 'S', 'a', 'p', 'l', 'i', 'n', 'g', 'F', 'V', 'F', 'P'}; {'Z', 'c', 'a', 's', 'h', 'S', 'a', 'p', 'l', 'i', 'n', 'g', 'F', 'V', 'F', 'P'};
//! Sapling //! Sapling

View File

@ -11,12 +11,12 @@
#include "zcash/prf.h" #include "zcash/prf.h"
#include <librustzcash.h> #include <librustzcash.h>
#include <sodium.h> #include <rust/blake2b.h>
const unsigned char ZCASH_HD_SEED_FP_PERSONAL[crypto_generichash_blake2b_PERSONALBYTES] = const unsigned char ZCASH_HD_SEED_FP_PERSONAL[BLAKE2bPersonalBytes] =
{'Z', 'c', 'a', 's', 'h', '_', 'H', 'D', '_', 'S', 'e', 'e', 'd', '_', 'F', 'P'}; {'Z', 'c', 'a', 's', 'h', '_', 'H', 'D', '_', 'S', 'e', 'e', 'd', '_', 'F', 'P'};
const unsigned char ZCASH_TADDR_OVK_PERSONAL[crypto_generichash_blake2b_PERSONALBYTES] = const unsigned char ZCASH_TADDR_OVK_PERSONAL[BLAKE2bPersonalBytes] =
{'Z', 'c', 'T', 'a', 'd', 'd', 'r', 'T', 'o', 'S', 'a', 'p', 'l', 'i', 'n', 'g'}; {'Z', 'c', 'T', 'a', 'd', 'd', 'r', 'T', 'o', 'S', 'a', 'p', 'l', 'i', 'n', 'g'};
HDSeed HDSeed::Random(size_t len) HDSeed HDSeed::Random(size_t len)
@ -38,16 +38,11 @@ uint256 ovkForShieldingFromTaddr(HDSeed& seed) {
auto rawSeed = seed.RawSeed(); auto rawSeed = seed.RawSeed();
// I = BLAKE2b-512("ZcTaddrToSapling", seed) // I = BLAKE2b-512("ZcTaddrToSapling", seed)
crypto_generichash_blake2b_state state; auto state = blake2b_init(64, ZCASH_TADDR_OVK_PERSONAL);
assert(crypto_generichash_blake2b_init_salt_personal( blake2b_update(state, rawSeed.data(), rawSeed.size());
&state,
NULL, 0, // No key.
64,
NULL, // No salt.
ZCASH_TADDR_OVK_PERSONAL) == 0);
crypto_generichash_blake2b_update(&state, rawSeed.data(), rawSeed.size());
auto intermediate = std::array<unsigned char, 64>(); auto intermediate = std::array<unsigned char, 64>();
crypto_generichash_blake2b_final(&state, intermediate.data(), 64); blake2b_finalize(state, intermediate.data(), 64);
blake2b_free(state);
// I_L = I[0..32] // I_L = I[0..32]
uint256 intermediate_L; uint256 intermediate_L;

View File

@ -4,8 +4,9 @@
#include <array> #include <array>
#include <librustzcash.h> #include <librustzcash.h>
#include <rust/blake2b.h>
const unsigned char ZCASH_EXPANDSEED_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] = {'Z','c','a','s','h','_','E','x','p','a','n','d','S','e','e','d'}; const unsigned char ZCASH_EXPANDSEED_PERSONALIZATION[BLAKE2bPersonalBytes] = {'Z','c','a','s','h','_','E','x','p','a','n','d','S','e','e','d'};
// Sapling // Sapling
std::array<unsigned char, 64> PRF_expand(const uint256& sk, unsigned char t) std::array<unsigned char, 64> PRF_expand(const uint256& sk, unsigned char t)
@ -15,12 +16,12 @@ std::array<unsigned char, 64> PRF_expand(const uint256& sk, unsigned char t)
memcpy(&blob[0], sk.begin(), 32); memcpy(&blob[0], sk.begin(), 32);
blob[32] = t; blob[32] = t;
crypto_generichash_blake2b_state state; auto state = blake2b_init(64, ZCASH_EXPANDSEED_PERSONALIZATION);
crypto_generichash_blake2b_init_salt_personal(&state, nullptr, 0, 64, nullptr, ZCASH_EXPANDSEED_PERSONALIZATION); blake2b_update(state, blob, 33);
crypto_generichash_blake2b_update(&state, blob, 33); blake2b_finalize(state, res.data(), 64);
crypto_generichash_blake2b_final(&state, res.data(), 64); blake2b_free(state);
return res; return res;
} }
@ -74,11 +75,11 @@ std::array<unsigned char, 11> default_diversifier(const uint256& sk)
blob[33] = 0; blob[33] = 0;
while (true) { while (true) {
crypto_generichash_blake2b_state state; auto state = blake2b_init(64, ZCASH_EXPANDSEED_PERSONALIZATION);
crypto_generichash_blake2b_init_salt_personal(&state, nullptr, 0, 64, nullptr, ZCASH_EXPANDSEED_PERSONALIZATION); blake2b_update(state, blob, 34);
crypto_generichash_blake2b_update(&state, blob, 34); blake2b_finalize(state, res.data(), 11);
crypto_generichash_blake2b_final(&state, res.data(), 11); blake2b_free(state);
if (librustzcash_check_diversifier(res.data())) { if (librustzcash_check_diversifier(res.data())) {
break; break;
} else if (blob[33] == 255) { } else if (blob[33] == 255) {

View File

@ -23,7 +23,6 @@
#include "random.h" #include "random.h"
#include "rpc/server.h" #include "rpc/server.h"
#include "script/sign.h" #include "script/sign.h"
#include "sodium.h"
#include "streams.h" #include "streams.h"
#include "txdb.h" #include "txdb.h"
#include "utiltest.h" #include "utiltest.h"
@ -160,14 +159,12 @@ double benchmark_solve_equihash()
auto params = Params(CBaseChainParams::MAIN).GetConsensus(); auto params = Params(CBaseChainParams::MAIN).GetConsensus();
unsigned int n = params.nEquihashN; unsigned int n = params.nEquihashN;
unsigned int k = params.nEquihashK; unsigned int k = params.nEquihashK;
crypto_generichash_blake2b_state eh_state; eh_HashState eh_state;
EhInitialiseState(n, k, eh_state); EhInitialiseState(n, k, eh_state);
crypto_generichash_blake2b_update(&eh_state, (unsigned char*)&ss[0], ss.size()); eh_state.Update((unsigned char*)&ss[0], ss.size());
uint256 nonce = GetRandHash(); uint256 nonce = GetRandHash();
crypto_generichash_blake2b_update(&eh_state, eh_state.Update(nonce.begin(), nonce.size());
nonce.begin(),
nonce.size());
struct timeval tv_start; struct timeval tv_start;
timer_start(tv_start); timer_start(tv_start);