Merge #8914: Kill insecure_random and associated global state

5eaaa83 Kill insecure_random and associated global state (Wladimir J. van der Laan)
This commit is contained in:
Wladimir J. van der Laan 2016-10-18 15:38:44 +02:00
commit cdfb7755a6
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
28 changed files with 91 additions and 65 deletions

View File

@ -358,8 +358,8 @@ CAddrInfo CAddrMan::Select_(bool newOnly)
int nKBucket = RandomInt(ADDRMAN_TRIED_BUCKET_COUNT); int nKBucket = RandomInt(ADDRMAN_TRIED_BUCKET_COUNT);
int nKBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE); int nKBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE);
while (vvTried[nKBucket][nKBucketPos] == -1) { while (vvTried[nKBucket][nKBucketPos] == -1) {
nKBucket = (nKBucket + insecure_rand()) % ADDRMAN_TRIED_BUCKET_COUNT; nKBucket = (nKBucket + insecure_rand.rand32()) % ADDRMAN_TRIED_BUCKET_COUNT;
nKBucketPos = (nKBucketPos + insecure_rand()) % ADDRMAN_BUCKET_SIZE; nKBucketPos = (nKBucketPos + insecure_rand.rand32()) % ADDRMAN_BUCKET_SIZE;
} }
int nId = vvTried[nKBucket][nKBucketPos]; int nId = vvTried[nKBucket][nKBucketPos];
assert(mapInfo.count(nId) == 1); assert(mapInfo.count(nId) == 1);
@ -375,8 +375,8 @@ CAddrInfo CAddrMan::Select_(bool newOnly)
int nUBucket = RandomInt(ADDRMAN_NEW_BUCKET_COUNT); int nUBucket = RandomInt(ADDRMAN_NEW_BUCKET_COUNT);
int nUBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE); int nUBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE);
while (vvNew[nUBucket][nUBucketPos] == -1) { while (vvNew[nUBucket][nUBucketPos] == -1) {
nUBucket = (nUBucket + insecure_rand()) % ADDRMAN_NEW_BUCKET_COUNT; nUBucket = (nUBucket + insecure_rand.rand32()) % ADDRMAN_NEW_BUCKET_COUNT;
nUBucketPos = (nUBucketPos + insecure_rand()) % ADDRMAN_BUCKET_SIZE; nUBucketPos = (nUBucketPos + insecure_rand.rand32()) % ADDRMAN_BUCKET_SIZE;
} }
int nId = vvNew[nUBucket][nUBucketPos]; int nId = vvNew[nUBucket][nUBucketPos];
assert(mapInfo.count(nId) == 1); assert(mapInfo.count(nId) == 1);

View File

@ -211,6 +211,9 @@ protected:
//! secret key to randomize bucket select with //! secret key to randomize bucket select with
uint256 nKey; uint256 nKey;
//! Source of random numbers for randomization in inner loops
FastRandomContext insecure_rand;
//! Find an entry. //! Find an entry.
CAddrInfo* Find(const CNetAddr& addr, int *pnId = NULL); CAddrInfo* Find(const CNetAddr& addr, int *pnId = NULL);

View File

@ -4762,6 +4762,7 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma
uint64_t hashAddr = addr.GetHash(); uint64_t hashAddr = addr.GetHash();
std::multimap<uint64_t, CNode*> mapMix; std::multimap<uint64_t, CNode*> mapMix;
const CSipHasher hasher = connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60)); const CSipHasher hasher = connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60));
FastRandomContext insecure_rand;
auto sortfunc = [&mapMix, &hasher](CNode* pnode) { auto sortfunc = [&mapMix, &hasher](CNode* pnode) {
if (pnode->nVersion >= CADDR_TIME_VERSION) { if (pnode->nVersion >= CADDR_TIME_VERSION) {
@ -4770,9 +4771,9 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma
} }
}; };
auto pushfunc = [&addr, &mapMix, &nRelayNodes] { auto pushfunc = [&addr, &mapMix, &nRelayNodes, &insecure_rand] {
for (auto mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi) for (auto mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
mi->second->PushAddress(addr); mi->second->PushAddress(addr, insecure_rand);
}; };
connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc)); connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));
@ -5082,14 +5083,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (fListen && !IsInitialBlockDownload()) if (fListen && !IsInitialBlockDownload())
{ {
CAddress addr = GetLocalAddress(&pfrom->addr, pfrom->GetLocalServices()); CAddress addr = GetLocalAddress(&pfrom->addr, pfrom->GetLocalServices());
FastRandomContext insecure_rand;
if (addr.IsRoutable()) if (addr.IsRoutable())
{ {
LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString()); LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString());
pfrom->PushAddress(addr); pfrom->PushAddress(addr, insecure_rand);
} else if (IsPeerAddrLocalGood(pfrom)) { } else if (IsPeerAddrLocalGood(pfrom)) {
addr.SetIP(pfrom->addrLocal); addr.SetIP(pfrom->addrLocal);
LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString()); LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString());
pfrom->PushAddress(addr); pfrom->PushAddress(addr, insecure_rand);
} }
} }
@ -6012,8 +6014,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->vAddrToSend.clear(); pfrom->vAddrToSend.clear();
vector<CAddress> vAddr = connman.GetAddresses(); vector<CAddress> vAddr = connman.GetAddresses();
FastRandomContext insecure_rand;
BOOST_FOREACH(const CAddress &addr, vAddr) BOOST_FOREACH(const CAddress &addr, vAddr)
pfrom->PushAddress(addr); pfrom->PushAddress(addr, insecure_rand);
} }
@ -6846,7 +6849,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
// until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY. // until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY.
else if (timeNow + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < pto->nextSendTimeFeeFilter && else if (timeNow + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < pto->nextSendTimeFeeFilter &&
(currentFilter < 3 * pto->lastSentFeeFilter / 4 || currentFilter > 4 * pto->lastSentFeeFilter / 3)) { (currentFilter < 3 * pto->lastSentFeeFilter / 4 || currentFilter > 4 * pto->lastSentFeeFilter / 3)) {
pto->nextSendTimeFeeFilter = timeNow + (insecure_rand() % MAX_FEEFILTER_CHANGE_DELAY) * 1000000; pto->nextSendTimeFeeFilter = timeNow + GetRandInt(MAX_FEEFILTER_CHANGE_DELAY) * 1000000;
} }
} }
} }

View File

@ -187,7 +187,8 @@ void AdvertiseLocal(CNode *pnode)
if (addrLocal.IsRoutable()) if (addrLocal.IsRoutable())
{ {
LogPrint("net", "AdvertiseLocal: advertising address %s\n", addrLocal.ToString()); LogPrint("net", "AdvertiseLocal: advertising address %s\n", addrLocal.ToString());
pnode->PushAddress(addrLocal); FastRandomContext insecure_rand;
pnode->PushAddress(addrLocal, insecure_rand);
} }
} }
} }

View File

@ -735,14 +735,14 @@ public:
addrKnown.insert(_addr.GetKey()); addrKnown.insert(_addr.GetKey());
} }
void PushAddress(const CAddress& _addr) void PushAddress(const CAddress& _addr, FastRandomContext &insecure_rand)
{ {
// Known checking here is only to save space from duplicates. // Known checking here is only to save space from duplicates.
// SendMessages will filter it again for knowns that were added // SendMessages will filter it again for knowns that were added
// after addresses were pushed. // after addresses were pushed.
if (_addr.IsValid() && !addrKnown.contains(_addr.GetKey())) { if (_addr.IsValid() && !addrKnown.contains(_addr.GetKey())) {
if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) { if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) {
vAddrToSend[insecure_rand() % vAddrToSend.size()] = _addr; vAddrToSend[insecure_rand.rand32() % vAddrToSend.size()] = _addr;
} else { } else {
vAddrToSend.push_back(_addr); vAddrToSend.push_back(_addr);
} }

View File

@ -596,8 +596,8 @@ static bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDe
// do socks negotiation // do socks negotiation
if (proxy.randomize_credentials) { if (proxy.randomize_credentials) {
ProxyCredentials random_auth; ProxyCredentials random_auth;
random_auth.username = strprintf("%i", insecure_rand()); static std::atomic_int counter;
random_auth.password = strprintf("%i", insecure_rand()); random_auth.username = random_auth.password = strprintf("%i", counter++);
if (!Socks5(strDest, (unsigned short)port, &random_auth, hSocket)) if (!Socks5(strDest, (unsigned short)port, &random_auth, hSocket))
return false; return false;
} else { } else {

View File

@ -594,7 +594,7 @@ FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)
CAmount FeeFilterRounder::round(CAmount currentMinFee) CAmount FeeFilterRounder::round(CAmount currentMinFee)
{ {
std::set<double>::iterator it = feeset.lower_bound(currentMinFee); std::set<double>::iterator it = feeset.lower_bound(currentMinFee);
if ((it != feeset.begin() && insecure_rand() % 3 != 0) || it == feeset.end()) { if ((it != feeset.begin() && insecure_rand.rand32() % 3 != 0) || it == feeset.end()) {
it--; it--;
} }
return *it; return *it;

View File

@ -7,6 +7,7 @@
#include "amount.h" #include "amount.h"
#include "uint256.h" #include "uint256.h"
#include "random.h"
#include <map> #include <map>
#include <string> #include <string>
@ -298,5 +299,6 @@ public:
private: private:
std::set<double> feeset; std::set<double> feeset;
FastRandomContext insecure_rand;
}; };
#endif /*BITCOIN_POLICYESTIMATOR_H */ #endif /*BITCOIN_POLICYESTIMATOR_H */

View File

@ -178,22 +178,21 @@ uint256 GetRandHash()
return hash; return hash;
} }
uint32_t insecure_rand_Rz = 11; FastRandomContext::FastRandomContext(bool fDeterministic)
uint32_t insecure_rand_Rw = 11;
void seed_insecure_rand(bool fDeterministic)
{ {
// The seed values have some unlikely fixed points which we avoid. // The seed values have some unlikely fixed points which we avoid.
if (fDeterministic) { if (fDeterministic) {
insecure_rand_Rz = insecure_rand_Rw = 11; Rz = Rw = 11;
} else { } else {
uint32_t tmp; uint32_t tmp;
do { do {
GetRandBytes((unsigned char*)&tmp, 4); GetRandBytes((unsigned char*)&tmp, 4);
} while (tmp == 0 || tmp == 0x9068ffffU); } while (tmp == 0 || tmp == 0x9068ffffU);
insecure_rand_Rz = tmp; Rz = tmp;
do { do {
GetRandBytes((unsigned char*)&tmp, 4); GetRandBytes((unsigned char*)&tmp, 4);
} while (tmp == 0 || tmp == 0x464fffffU); } while (tmp == 0 || tmp == 0x464fffffU);
insecure_rand_Rw = tmp; Rw = tmp;
} }
} }

View File

@ -28,25 +28,22 @@ uint256 GetRandHash();
void GetStrongRandBytes(unsigned char* buf, int num); void GetStrongRandBytes(unsigned char* buf, int num);
/** /**
* Seed insecure_rand using the random pool. * Fast randomness source. This is seeded once with secure random data, but
* @param Deterministic Use a deterministic seed * is completely deterministic and insecure after that.
* This class is not thread-safe.
*/ */
void seed_insecure_rand(bool fDeterministic = false); class FastRandomContext {
public:
explicit FastRandomContext(bool fDeterministic=false);
/** uint32_t rand32() {
* MWC RNG of George Marsaglia Rz = 36969 * (Rz & 65535) + (Rz >> 16);
* This is intended to be fast. It has a period of 2^59.3, though the Rw = 18000 * (Rw & 65535) + (Rw >> 16);
* least significant 16 bits only have a period of about 2^30.1. return (Rw << 16) + Rz;
* }
* @return random value
*/ uint32_t Rz;
extern uint32_t insecure_rand_Rz; uint32_t Rw;
extern uint32_t insecure_rand_Rw; };
static inline uint32_t insecure_rand(void)
{
insecure_rand_Rz = 36969 * (insecure_rand_Rz & 65535) + (insecure_rand_Rz >> 16);
insecure_rand_Rw = 18000 * (insecure_rand_Rw & 65535) + (insecure_rand_Rw >> 16);
return (insecure_rand_Rw << 16) + insecure_rand_Rz;
}
#endif // BITCOIN_RANDOM_H #endif // BITCOIN_RANDOM_H

View File

@ -26,7 +26,7 @@ public:
void MakeDeterministic() void MakeDeterministic()
{ {
nKey.SetNull(); nKey.SetNull();
seed_insecure_rand(true); insecure_rand = FastRandomContext(true);
} }
int RandomInt(int nMax) int RandomInt(int nMax)

View File

@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "coins.h" #include "coins.h"
#include "random.h" #include "test_random.h"
#include "script/standard.h" #include "script/standard.h"
#include "uint256.h" #include "uint256.h"
#include "utilstrencodings.h" #include "utilstrencodings.h"

View File

@ -9,7 +9,7 @@
#include "crypto/sha512.h" #include "crypto/sha512.h"
#include "crypto/hmac_sha256.h" #include "crypto/hmac_sha256.h"
#include "crypto/hmac_sha512.h" #include "crypto/hmac_sha512.h"
#include "random.h" #include "test_random.h"
#include "utilstrencodings.h" #include "utilstrencodings.h"
#include "test/test_bitcoin.h" #include "test/test_bitcoin.h"

View File

@ -4,7 +4,7 @@
#include "consensus/merkle.h" #include "consensus/merkle.h"
#include "test/test_bitcoin.h" #include "test/test_bitcoin.h"
#include "random.h" #include "test_random.h"
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>

View File

@ -23,7 +23,7 @@ public:
void MakeDeterministic() void MakeDeterministic()
{ {
nKey.SetNull(); nKey.SetNull();
seed_insecure_rand(true); insecure_rand = FastRandomContext(true);
} }
}; };

View File

@ -9,7 +9,7 @@
#include "uint256.h" #include "uint256.h"
#include "arith_uint256.h" #include "arith_uint256.h"
#include "version.h" #include "version.h"
#include "random.h" #include "test_random.h"
#include "test/test_bitcoin.h" #include "test/test_bitcoin.h"
#include <vector> #include <vector>

View File

@ -4,7 +4,7 @@
#include <vector> #include <vector>
#include "prevector.h" #include "prevector.h"
#include "random.h" #include "test_random.h"
#include "serialize.h" #include "serialize.h"
#include "streams.h" #include "streams.h"
@ -27,8 +27,7 @@ class prevector_tester {
typedef typename pretype::size_type Size; typedef typename pretype::size_type Size;
bool passed = true; bool passed = true;
uint32_t insecure_rand_Rz_cache; FastRandomContext rand_cache;
uint32_t insecure_rand_Rw_cache;
template <typename A, typename B> template <typename A, typename B>
@ -171,15 +170,14 @@ public:
test(); test();
} }
~prevector_tester() { ~prevector_tester() {
BOOST_CHECK_MESSAGE(passed, "insecure_rand_Rz: " BOOST_CHECK_MESSAGE(passed, "insecure_rand_Rz: "
<< insecure_rand_Rz_cache << rand_cache.Rz
<< ", insecure_rand_Rw: " << ", insecure_rand_Rw: "
<< insecure_rand_Rw_cache); << rand_cache.Rw);
} }
prevector_tester() { prevector_tester() {
seed_insecure_rand(); seed_insecure_rand();
insecure_rand_Rz_cache = insecure_rand_Rz; rand_cache = insecure_rand_ctx;
insecure_rand_Rw_cache = insecure_rand_Rw;
} }
}; };

View File

@ -42,8 +42,6 @@ static void MicroSleep(uint64_t n)
BOOST_AUTO_TEST_CASE(manythreads) BOOST_AUTO_TEST_CASE(manythreads)
{ {
seed_insecure_rand(false);
// Stress test: hundreds of microsecond-scheduled tasks, // Stress test: hundreds of microsecond-scheduled tasks,
// serviced by 10 threads. // serviced by 10 threads.
// //
@ -58,7 +56,7 @@ BOOST_AUTO_TEST_CASE(manythreads)
boost::mutex counterMutex[10]; boost::mutex counterMutex[10];
int counter[10] = { 0 }; int counter[10] = { 0 };
boost::random::mt19937 rng(insecure_rand()); boost::random::mt19937 rng(42);
boost::random::uniform_int_distribution<> zeroToNine(0, 9); boost::random::uniform_int_distribution<> zeroToNine(0, 9);
boost::random::uniform_int_distribution<> randomMsec(-11, 1000); boost::random::uniform_int_distribution<> randomMsec(-11, 1000);
boost::random::uniform_int_distribution<> randomDelta(-1000, 1000); boost::random::uniform_int_distribution<> randomDelta(-1000, 1000);

View File

@ -6,7 +6,7 @@
#include "data/sighash.json.h" #include "data/sighash.json.h"
#include "hash.h" #include "hash.h"
#include "main.h" // For CheckTransaction #include "main.h" // For CheckTransaction
#include "random.h" #include "test_random.h"
#include "script/interpreter.h" #include "script/interpreter.h"
#include "script/script.h" #include "script/script.h"
#include "serialize.h" #include "serialize.h"

View File

@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "chain.h" #include "chain.h"
#include "random.h" #include "test_random.h"
#include "util.h" #include "util.h"
#include "test/test_bitcoin.h" #include "test/test_bitcoin.h"

View File

@ -27,6 +27,7 @@
#include <boost/thread.hpp> #include <boost/thread.hpp>
std::unique_ptr<CConnman> g_connman; std::unique_ptr<CConnman> g_connman;
FastRandomContext insecure_rand_ctx(true);
extern bool fPrintToConsole; extern bool fPrintToConsole;
extern void noui_connect(); extern void noui_connect();

23
src/test/test_random.h Normal file
View File

@ -0,0 +1,23 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_TEST_RANDOM_H
#define BITCOIN_TEST_RANDOM_H
#include "random.h"
extern FastRandomContext insecure_rand_ctx;
static inline void seed_insecure_rand(bool fDeterministic = false)
{
insecure_rand_ctx = FastRandomContext(fDeterministic);
}
static inline uint32_t insecure_rand(void)
{
return insecure_rand_ctx.rand32();
}
#endif

View File

@ -6,7 +6,7 @@
#include "clientversion.h" #include "clientversion.h"
#include "primitives/transaction.h" #include "primitives/transaction.h"
#include "random.h" #include "test_random.h"
#include "sync.h" #include "sync.h"
#include "utilstrencodings.h" #include "utilstrencodings.h"
#include "utilmoneystr.h" #include "utilmoneystr.h"

View File

@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "chain.h" #include "chain.h"
#include "random.h" #include "test_random.h"
#include "versionbits.h" #include "versionbits.h"
#include "test/test_bitcoin.h" #include "test/test_bitcoin.h"
#include "chainparams.h" #include "chainparams.h"

View File

@ -647,7 +647,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
if (nCheckFrequency == 0) if (nCheckFrequency == 0)
return; return;
if (insecure_rand() >= nCheckFrequency) if (GetRand(std::numeric_limits<uint32_t>::max()) >= nCheckFrequency)
return; return;
LogPrint("mempool", "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size()); LogPrint("mempool", "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size());

View File

@ -15,6 +15,7 @@
#include "indirectmap.h" #include "indirectmap.h"
#include "primitives/transaction.h" #include "primitives/transaction.h"
#include "sync.h" #include "sync.h"
#include "random.h"
#undef foreach #undef foreach
#include "boost/multi_index_container.hpp" #include "boost/multi_index_container.hpp"

View File

@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "random.h" #include "test/test_random.h"
#include "utilstrencodings.h" #include "utilstrencodings.h"
#include "test/test_bitcoin.h" #include "test/test_bitcoin.h"
#include "wallet/crypter.h" #include "wallet/crypter.h"

View File

@ -1907,7 +1907,7 @@ static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,uns
vfBest.assign(vValue.size(), true); vfBest.assign(vValue.size(), true);
nBest = nTotalLower; nBest = nTotalLower;
seed_insecure_rand(); FastRandomContext insecure_rand;
for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++) for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++)
{ {
@ -1924,7 +1924,7 @@ static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,uns
//that the rng is fast. We do not use a constant random sequence, //that the rng is fast. We do not use a constant random sequence,
//because there may be some privacy improvement by making //because there may be some privacy improvement by making
//the selection random. //the selection random.
if (nPass == 0 ? insecure_rand()&1 : !vfIncluded[i]) if (nPass == 0 ? insecure_rand.rand32()&1 : !vfIncluded[i])
{ {
nTotal += vValue[i].first; nTotal += vValue[i].first;
vfIncluded[i] = true; vfIncluded[i] = true;