diff options
-rw-r--r-- | qa/rpc-tests/test_framework/util.py | 22 | ||||
-rw-r--r-- | src/Makefile.am | 3 | ||||
-rw-r--r-- | src/Makefile.bench.include | 3 | ||||
-rw-r--r-- | src/bench/base58.cpp | 56 | ||||
-rw-r--r-- | src/bench/crypto_hash.cpp | 25 | ||||
-rw-r--r-- | src/init.cpp | 2 | ||||
-rw-r--r-- | src/key.cpp | 3 | ||||
-rw-r--r-- | src/main.cpp | 1 | ||||
-rw-r--r-- | src/random.cpp | 66 | ||||
-rw-r--r-- | src/random.h | 11 | ||||
-rw-r--r-- | src/rpc/rawtransaction.cpp | 2 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 8 |
12 files changed, 172 insertions, 30 deletions
diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index 3948b664e3..fc66ef287d 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -121,30 +121,34 @@ def hex_str_to_bytes(hex_str): def str_to_b64str(string): return b64encode(string.encode('utf-8')).decode('ascii') -def sync_blocks(rpc_connections, wait=1): +def sync_blocks(rpc_connections, wait=1, timeout=60): """ - Wait until everybody has the same block count + Wait until everybody has the same tip """ - while True: - counts = [ x.getblockcount() for x in rpc_connections ] - if counts == [ counts[0] ]*len(counts): - break + while timeout > 0: + tips = [ x.getbestblockhash() for x in rpc_connections ] + if tips == [ tips[0] ]*len(tips): + return True time.sleep(wait) + timeout -= wait + raise AssertionError("Block sync failed") -def sync_mempools(rpc_connections, wait=1): +def sync_mempools(rpc_connections, wait=1, timeout=60): """ Wait until everybody has the same transactions in their memory pools """ - while True: + while timeout > 0: pool = set(rpc_connections[0].getrawmempool()) num_match = 1 for i in range(1, len(rpc_connections)): if set(rpc_connections[i].getrawmempool()) == pool: num_match = num_match+1 if num_match == len(rpc_connections): - break + return True time.sleep(wait) + timeout -= wait + raise AssertionError("Mempool sync failed") bitcoind_processes = {} diff --git a/src/Makefile.am b/src/Makefile.am index 3c056386fa..f630ad4aa1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -374,7 +374,8 @@ endif bitcoin_cli_LDADD = \ $(LIBBITCOIN_CLI) \ $(LIBUNIVALUE) \ - $(LIBBITCOIN_UTIL) + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_CRYPTO) bitcoin_cli_LDADD += $(BOOST_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_LIBS) # diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index 65fd24e051..4067ceb399 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -9,7 +9,8 @@ bench_bench_bitcoin_SOURCES = \ bench/bench.h \ bench/Examples.cpp \ bench/rollingbloom.cpp \ - bench/crypto_hash.cpp + bench/crypto_hash.cpp \ + bench/base58.cpp bench_bench_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CLFAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/ bench_bench_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) diff --git a/src/bench/base58.cpp b/src/bench/base58.cpp new file mode 100644 index 0000000000..1279c3e7df --- /dev/null +++ b/src/bench/base58.cpp @@ -0,0 +1,56 @@ +// Copyright (c) 2016 the Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bench.h" + +#include "main.h" +#include "base58.h" + +#include <vector> +#include <string> + + +static void Base58Encode(benchmark::State& state) +{ + unsigned char buff[32] = { + 17, 79, 8, 99, 150, 189, 208, 162, 22, 23, 203, 163, 36, 58, 147, + 227, 139, 2, 215, 100, 91, 38, 11, 141, 253, 40, 117, 21, 16, 90, + 200, 24 + }; + unsigned char* b = buff; + while (state.KeepRunning()) { + EncodeBase58(b, b + 32); + } +} + + +static void Base58CheckEncode(benchmark::State& state) +{ + unsigned char buff[32] = { + 17, 79, 8, 99, 150, 189, 208, 162, 22, 23, 203, 163, 36, 58, 147, + 227, 139, 2, 215, 100, 91, 38, 11, 141, 253, 40, 117, 21, 16, 90, + 200, 24 + }; + unsigned char* b = buff; + std::vector<unsigned char> vch; + vch.assign(b, b + 32); + while (state.KeepRunning()) { + EncodeBase58Check(vch); + } +} + + +static void Base58Decode(benchmark::State& state) +{ + const char* addr = "17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem"; + std::vector<unsigned char> vch; + while (state.KeepRunning()) { + DecodeBase58(addr, vch); + } +} + + +BENCHMARK(Base58Encode); +BENCHMARK(Base58CheckEncode); +BENCHMARK(Base58Decode); diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp index 6b753f6308..168006154f 100644 --- a/src/bench/crypto_hash.cpp +++ b/src/bench/crypto_hash.cpp @@ -6,6 +6,8 @@ #include "bench.h" #include "bloom.h" +#include "hash.h" +#include "uint256.h" #include "utiltime.h" #include "crypto/ripemd160.h" #include "crypto/sha1.h" @@ -39,6 +41,16 @@ static void SHA256(benchmark::State& state) CSHA256().Write(begin_ptr(in), in.size()).Finalize(hash); } +static void SHA256_32b(benchmark::State& state) +{ + std::vector<uint8_t> in(32,0); + while (state.KeepRunning()) { + for (int i = 0; i < 1000000; i++) { + CSHA256().Write(begin_ptr(in), in.size()).Finalize(&in[0]); + } + } +} + static void SHA512(benchmark::State& state) { uint8_t hash[CSHA512::OUTPUT_SIZE]; @@ -47,7 +59,20 @@ static void SHA512(benchmark::State& state) CSHA512().Write(begin_ptr(in), in.size()).Finalize(hash); } +static void SipHash_32b(benchmark::State& state) +{ + uint256 x; + while (state.KeepRunning()) { + for (int i = 0; i < 1000000; i++) { + *((uint64_t*)x.begin()) = SipHashUint256(0, i, x); + } + } +} + BENCHMARK(RIPEMD160); BENCHMARK(SHA1); BENCHMARK(SHA256); BENCHMARK(SHA512); + +BENCHMARK(SHA256_32b); +BENCHMARK(SipHash_32b); diff --git a/src/init.cpp b/src/init.cpp index 9b6943c586..98c0894122 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1401,8 +1401,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (!strErrors.str().empty()) return InitError(strErrors.str()); - RandAddSeedPerfmon(); - //// debug print LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size()); LogPrintf("nBestHeight = %d\n", chainActive.Height()); diff --git a/src/key.cpp b/src/key.cpp index 6a3d9aa140..79023566c3 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -124,9 +124,8 @@ bool CKey::Check(const unsigned char *vch) { } void CKey::MakeNewKey(bool fCompressedIn) { - RandAddSeedPerfmon(); do { - GetRandBytes(vch, sizeof(vch)); + GetStrongRandBytes(vch, sizeof(vch)); } while (!Check(vch)); fValid = true; fCompressed = fCompressedIn; diff --git a/src/main.cpp b/src/main.cpp index ed157b53dc..ffc57d48be 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4547,7 +4547,6 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams) { - RandAddSeedPerfmon(); LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id); if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0) { diff --git a/src/random.cpp b/src/random.cpp index 6155c0d8cf..d9a8cc145e 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -5,14 +5,17 @@ #include "random.h" +#include "crypto/sha512.h" #include "support/cleanse.h" #ifdef WIN32 #include "compat.h" // for Windows API +#include <wincrypt.h> #endif #include "serialize.h" // for begin_ptr(vec) #include "util.h" // for LogPrint() #include "utilstrencodings.h" // for GetTime() +#include <stdlib.h> #include <limits> #ifndef WIN32 @@ -22,6 +25,12 @@ #include <openssl/err.h> #include <openssl/rand.h> +static void RandFailure() +{ + LogPrintf("Failed to read randomness, aborting\n"); + abort(); +} + static inline int64_t GetPerformanceCounter() { int64_t nCounter = 0; @@ -43,7 +52,7 @@ void RandAddSeed() memory_cleanse((void*)&nCounter, sizeof(nCounter)); } -void RandAddSeedPerfmon() +static void RandAddSeedPerfmon() { RandAddSeed(); @@ -83,14 +92,65 @@ void RandAddSeedPerfmon() #endif } +/** Get 32 bytes of system entropy. */ +static void GetOSRand(unsigned char *ent32) +{ +#ifdef WIN32 + HCRYPTPROV hProvider; + int ret = CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + if (!ret) { + RandFailure(); + } + ret = CryptGenRandom(hProvider, 32, ent32); + if (!ret) { + RandFailure(); + } + CryptReleaseContext(hProvider, 0); +#else + int f = open("/dev/urandom", O_RDONLY); + if (f == -1) { + RandFailure(); + } + int have = 0; + do { + ssize_t n = read(f, ent32 + have, 32 - have); + if (n <= 0 || n + have > 32) { + RandFailure(); + } + have += n; + } while (have < 32); + close(f); +#endif +} + void GetRandBytes(unsigned char* buf, int num) { if (RAND_bytes(buf, num) != 1) { - LogPrintf("%s: OpenSSL RAND_bytes() failed with error: %s\n", __func__, ERR_error_string(ERR_get_error(), NULL)); - assert(false); + RandFailure(); } } +void GetStrongRandBytes(unsigned char* out, int num) +{ + assert(num <= 32); + CSHA512 hasher; + unsigned char buf[64]; + + // First source: OpenSSL's RNG + RandAddSeedPerfmon(); + GetRandBytes(buf, 32); + hasher.Write(buf, 32); + + // Second source: OS RNG + GetOSRand(buf); + hasher.Write(buf, 32); + + // Produce output + hasher.Finalize(buf); + memcpy(out, buf, num); + memory_cleanse(buf, 64); +} + uint64_t GetRand(uint64_t nMax) { if (nMax == 0) diff --git a/src/random.h b/src/random.h index 1a2d3e8ee2..31b80bd565 100644 --- a/src/random.h +++ b/src/random.h @@ -10,11 +10,8 @@ #include <stdint.h> -/** - * Seed OpenSSL PRNG with additional entropy data - */ +/* Seed OpenSSL PRNG with additional entropy data */ void RandAddSeed(); -void RandAddSeedPerfmon(); /** * Functions to gather random data via the OpenSSL PRNG @@ -25,6 +22,12 @@ int GetRandInt(int nMax); uint256 GetRandHash(); /** + * Function to gather random data from multiple sources, failing whenever any + * of those source fail to provide a result. + */ +void GetStrongRandBytes(unsigned char* buf, int num); + +/** * Seed insecure_rand using the random pool. * @param Deterministic Use a deterministic seed */ diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index bec7ebe55f..483fe746ca 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -211,7 +211,7 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp) "\nNOTE: By default this function only works sometimes. This is when there is an\n" "unspent output in the utxo for this transaction. To make it always work,\n" "you need to maintain a transaction index, using the -txindex command line option or\n" - "specify the block in which the transaction is included in manually (by blockhash).\n" + "specify the block in which the transaction is included manually (by blockhash).\n" "\nReturn the raw transaction data.\n" "\nArguments:\n" "1. \"txids\" (string) A json array of txids to filter\n" diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 5d1a431190..da0d6f272b 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -509,16 +509,14 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) return false; CKeyingMaterial vMasterKey; - RandAddSeedPerfmon(); vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE); - GetRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE); + GetStrongRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE); CMasterKey kMasterKey; - RandAddSeedPerfmon(); kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE); - GetRandBytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE); + GetStrongRandBytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE); CCrypter crypter; int64_t nStartTime = GetTimeMillis(); @@ -3147,8 +3145,6 @@ bool CWallet::InitLoadWallet() if (fFirstRun) { // Create new keyUser and set as default key - RandAddSeedPerfmon(); - CPubKey newDefaultKey; if (walletInstance->GetKeyFromPool(newDefaultKey)) { walletInstance->SetDefaultKey(newDefaultKey); |