Skip to content

Commit

Permalink
Merge pull request #2696 from div72/rand
Browse files Browse the repository at this point in the history
random: port some upstream changes
  • Loading branch information
jamescowens authored Aug 20, 2023
2 parents 7909431 + 46f29ab commit bbe73e5
Show file tree
Hide file tree
Showing 15 changed files with 72 additions and 70 deletions.
7 changes: 0 additions & 7 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -877,13 +877,6 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <unistd.h>
[ AC_MSG_RESULT(no)]
)

AC_MSG_CHECKING(for getentropy)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <unistd.h>]],
[[ getentropy(nullptr, 32) ]])],
[ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_GETENTROPY, 1,[Define this symbol if the BSD getentropy system call is available]) ],
[ AC_MSG_RESULT(no)]
)

AC_MSG_CHECKING(for sysctl KERN_ARND)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
#include <sys/sysctl.h>]],
Expand Down
3 changes: 2 additions & 1 deletion src/addrdb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ template <typename Data>
bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data& data)
{
// Generate random temporary filename
std::string tmpfn = strprintf("%s.%" PRIx64, prefix, GetPerformanceCounter());
const uint16_t randv{GetRand<uint16_t>()};
std::string tmpfn = strprintf("%s.%04x", prefix, randv);

// open temp output file, and associate with CAutoFile
fs::path pathTmp = GetDataDir() / tmpfn;
Expand Down
10 changes: 5 additions & 5 deletions src/addrman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ void CAddrMan::Good_(const CService& addr, int64_t nTime)
return;

// find a bucket it is in now
int nRnd = GetRandInt(ADDRMAN_NEW_BUCKET_COUNT);
int nRnd = GetRand<int>(ADDRMAN_NEW_BUCKET_COUNT);
int nUBucket = -1;
for (unsigned int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
int nB = (n + nRnd) % ADDRMAN_NEW_BUCKET_COUNT;
Expand Down Expand Up @@ -278,7 +278,7 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP
int nFactor = 1;
for (int n = 0; n < pinfo->nRefCount; n++)
nFactor *= 2;
if (nFactor > 1 && (GetRandInt(nFactor) != 0))
if (nFactor > 1 && (GetRand<int>(nFactor) != 0))
return false;
} else {
pinfo = Create(addr, source, &nId);
Expand Down Expand Up @@ -467,7 +467,7 @@ void CAddrMan::GetAddr_(std::vector<CAddress> &vAddr)
if (vAddr.size() >= nNodes)
break;

int nRndPos = GetRandInt(vRandom.size() - n) + n;
int nRndPos = GetRand<int>(vRandom.size() - n) + n;
SwapRandom(n, nRndPos);
assert(mapInfo.count(vRandom[n]) == 1);

Expand Down Expand Up @@ -516,5 +516,5 @@ void CAddrMan::SetServices_(const CService& addr, ServiceFlags nServices)
}

int CAddrMan::RandomInt(int nMax){
return GetRandInt(nMax);
}
return GetRand<int>(nMax);
}
2 changes: 1 addition & 1 deletion src/addrman.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ class CAddrMan
//! Select an address to connect to, if newOnly is set to true, only the new table is selected from.
CAddrInfo Select_(bool newOnly);

//! Wraps GetRandInt to allow tests to override RandomInt and make it determinismistic.
//! Wraps GetRand to allow tests to override RandomInt and make it determinismistic.
virtual int RandomInt(int nMax);

#ifdef DEBUG_ADDRMAN
Expand Down
2 changes: 1 addition & 1 deletion src/gridcoin/scraper/scraper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6175,7 +6175,7 @@ UniValue testnewsb(const UniValue& params, bool fHelp)

if (PastConvergencesSize > 1)
{
int i = GetRandInt(PastConvergencesSize - 1);
int i = GetRand<int>(PastConvergencesSize - 1);

_log(logattribute::INFO, "testnewsb",
"ValidateSuperblock random past RandomPastConvergedManifest index " + ToString(i) + " selected.");
Expand Down
5 changes: 2 additions & 3 deletions src/gridcoin/staking/spam.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,12 +201,11 @@ class SeenStakes
// ...to produce a distribution for values of x with a minimal rate of
// collision.
//
using limit_t = std::numeric_limits<size_t>;

static const size_t w = sizeof(size_t) * 8;
static const size_t M = std::log2(m_proofs_seen.size());
static const size_t a = (GetRand(limit_t::max()) * 2) + 1;
static const size_t b = GetRand(std::pow(2, w - M) - 1);
static const size_t a = (GetRand<size_t>() * 2) + 1;
static const size_t b = GetRand<size_t>(std::pow(2, w - M) - 1);

size_t x = 0;

Expand Down
6 changes: 3 additions & 3 deletions src/key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ bool CKey::Check(const unsigned char *vch) {

void CKey::MakeNewKey(bool fCompressedIn) {
do {
GetStrongRandBytes(keydata.data(), keydata.size());
GetStrongRandBytes(keydata);
} while (!Check(keydata.data()));
fValid = true;
fCompressed = fCompressedIn;
Expand Down Expand Up @@ -250,7 +250,7 @@ bool CKey::VerifyPubKey(const CPubKey& pubkey) const {
}
unsigned char rnd[8];
std::string str = "Bitcoin key verification\n";
GetRandBytes(rnd, sizeof(rnd));
GetRandBytes(rnd);
uint256 hash;
CHash256().Write(MakeUCharSpan(str)).Write(rnd).Finalize(hash);
std::vector<unsigned char> vchSig;
Expand Down Expand Up @@ -378,7 +378,7 @@ void ECC_Start() {
{
// Pass in a random blinding seed to the secp256k1 context.
std::vector<unsigned char, secure_allocator<unsigned char>> vseed(32);
GetRandBytes(vseed.data(), 32);
GetRandBytes(vseed);
bool ret = secp256k1_context_randomize(ctx, vseed.data());
assert(ret);
}
Expand Down
2 changes: 1 addition & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2929,7 +2929,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
{
uint64_t nonce = 0;
while (nonce == 0) {
GetRandBytes((unsigned char*)&nonce, sizeof(nonce));
GetRandBytes({(unsigned char*)&nonce, sizeof(nonce)});
}
pto->fPingQueued = false;
pto->nPingUsecStart = GetTimeMicros();
Expand Down
4 changes: 2 additions & 2 deletions src/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ void AdvertiseLocal(CNode *pnode)
// If discovery is enabled, sometimes give our peer the address it
// tells us that it sees us as in case it has a better idea of our
// address than we do.
const int randomNumber = GetRandInt((GetnScore(addrLocal) > LOCAL_MANUAL) ? 3+1 : 1+1);
const int randomNumber = GetRand<int>((GetnScore(addrLocal) > LOCAL_MANUAL) ? 3+1 : 1+1);
if (IsPeerAddrLocalGood(pnode) && (!addrLocal.IsRoutable() ||
randomNumber == 0))
{
Expand Down Expand Up @@ -486,7 +486,7 @@ void CNode::PushVersion()
int64_t nTime = GetAdjustedTime();
CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(LookupNumeric("0.0.0.0", 0)));
CAddress addrMe = CAddress(CService(), nLocalServices);
GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
GetRandBytes({(unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)});
LogPrint(BCLog::LogFlags::NET, "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%s",
PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), addr.ToString());

Expand Down
41 changes: 20 additions & 21 deletions src/random.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
#include <logging.h> // for LogPrintf()
#include <randomenv.h>
#include <support/allocators/secure.h>
#include <span.h>
#include <sync.h> // for Mutex
#include <util/time.h> // for GetTimeMicros()

#include <cmath>
#include <stdlib.h>
#include <thread>

Expand All @@ -31,10 +33,8 @@
#include <sys/syscall.h>
#include <linux/random.h>
#endif
#if defined(HAVE_GETENTROPY) || (defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX))
#include <unistd.h>
#endif
#if defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX)
#include <unistd.h>
#include <sys/random.h>
#endif
#ifdef HAVE_SYSCTL_ARND
Expand Down Expand Up @@ -304,16 +304,14 @@ void GetOSRand(unsigned char *ent32)
RandFailure();
}
}
#elif defined(HAVE_GETENTROPY) && defined(__OpenBSD__)
/* On OpenBSD this can return up to 256 bytes of entropy, will return an
* error if more are requested.
* The call cannot return less than the requested number of bytes.
getentropy is explicitly limited to openbsd here, as a similar (but not
the same) function may exist on other platforms via glibc.
#elif defined(__OpenBSD__)
/* OpenBSD. From the arc4random(3) man page:
"Use of these functions is encouraged for almost all random number
consumption because the other interfaces are deficient in either
quality, portability, standardization, or availability."
The function call is always successful.
*/
if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) {
RandFailure();
}
arc4random_buf(ent32, NUM_OS_RANDOM_BYTES);
// Silence a compiler warning about unused function.
(void)GetDevURandom;
#elif defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX)
Expand Down Expand Up @@ -581,27 +579,22 @@ static void ProcRand(unsigned char* out, int num, RNGLevel level) noexcept
}
}

void GetRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::FAST); }
void GetStrongRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::SLOW); }
void GetRandBytes(Span<unsigned char> bytes) noexcept { ProcRand(bytes.data(), bytes.size(), RNGLevel::FAST); }
void GetStrongRandBytes(Span<unsigned char> bytes) noexcept { ProcRand(bytes.data(), bytes.size(), RNGLevel::SLOW); }
void RandAddPeriodic() noexcept { ProcRand(nullptr, 0, RNGLevel::PERIODIC); }
void RandAddEvent(const uint32_t event_info) noexcept { GetRNGState().AddEvent(event_info); }

bool g_mock_deterministic_tests{false};

uint64_t GetRand(uint64_t nMax) noexcept
uint64_t GetRandInternal(uint64_t nMax) noexcept
{
return FastRandomContext(g_mock_deterministic_tests).randrange(nMax);
}

int GetRandInt(int nMax) noexcept
{
return GetRand(nMax);
}

uint256 GetRandHash() noexcept
{
uint256 hash;
GetRandBytes((unsigned char*)&hash, sizeof(hash));
GetRandBytes(hash);
return hash;
}

Expand Down Expand Up @@ -714,3 +707,9 @@ void RandomInit()

ReportHardwareRand();
}

std::chrono::microseconds GetExponentialRand(std::chrono::microseconds now, std::chrono::seconds average_interval)
{
double unscaled = -std::log1p(GetRand(uint64_t{1} << 48) * -0.0000000000000035527136788 /* -1/2^48 */);
return now + std::chrono::duration_cast<std::chrono::microseconds>(unscaled * average_interval + 0.5us);
}
31 changes: 27 additions & 4 deletions src/random.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@

#include <crypto/chacha20.h>
#include <crypto/common.h>
#include <span.h>
#include <uint256.h>

#include <chrono> // For std::chrono::microseconds
#include <chrono>
#include <cstdint>
#include <limits>

Expand Down Expand Up @@ -66,9 +67,19 @@
*
* Thread-safe.
*/
void GetRandBytes(unsigned char* buf, int num) noexcept;
void GetRandBytes(Span<unsigned char> bytes) noexcept;
/** Generate a uniform random integer in the range [0..range). Precondition: range > 0 */
uint64_t GetRand(uint64_t nMax) noexcept;
uint64_t GetRandInternal(uint64_t nMax) noexcept;
/** Generate a uniform random integer of type T in the range [0..nMax)
* nMax defaults to std::numeric_limits<T>::max()
* Precondition: nMax > 0, T is an integral type, no larger than uint64_t
*/
template<typename T>
T GetRand(T nMax=std::numeric_limits<T>::max()) noexcept {
static_assert(std::is_integral<T>(), "T must be integral");
static_assert(std::numeric_limits<T>::max() <= std::numeric_limits<uint64_t>::max(), "GetRand only supports up to uint64_t");
return T(GetRandInternal(nMax));
}
/** Generate a uniform random duration in the range [0..max). Precondition: max.count() > 0 */
template <typename D>
D GetRandomDuration(typename std::common_type<D>::type max) noexcept
Expand All @@ -82,6 +93,18 @@ D GetRandomDuration(typename std::common_type<D>::type max) noexcept
};
constexpr auto GetRandMicros = GetRandomDuration<std::chrono::microseconds>;
constexpr auto GetRandMillis = GetRandomDuration<std::chrono::milliseconds>;

/**
* Return a timestamp in the future sampled from an exponential distribution
* (https://en.wikipedia.org/wiki/Exponential_distribution). This distribution
* is memoryless and should be used for repeated network events (e.g. sending a
* certain type of message) to minimize leaking information to observers.
*
* The probability of an event occuring before time x is 1 - e^-(x/a) where a
* is the average interval between events.
* */
std::chrono::microseconds GetExponentialRand(std::chrono::microseconds now, std::chrono::seconds average_interval);

int GetRandInt(int nMax) noexcept;
uint256 GetRandHash() noexcept;

Expand All @@ -93,7 +116,7 @@ uint256 GetRandHash() noexcept;
*
* Thread-safe.
*/
void GetStrongRandBytes(unsigned char* buf, int num) noexcept;
void GetStrongRandBytes(Span<unsigned char> bytes) noexcept;

/**
* Gather entropy from various expensive sources, and feed them to the PRNG state.
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ void StartRPCThreads()
(gArgs.GetArg("-rpcuser", "") == gArgs.GetArg("-rpcpassword", ""))))
{
unsigned char rand_pwd[32];
GetRandBytes(rand_pwd, sizeof(rand_pwd));
GetRandBytes({rand_pwd, sizeof(rand_pwd)});
string strWhatAmI = "To use gridcoind";
if (gArgs.IsArgSet("-server"))
strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
Expand Down
8 changes: 4 additions & 4 deletions src/test/random_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests)
FastRandomContext ctx2(true);

for (int i = 10; i > 0; --i) {
BOOST_CHECK_EQUAL(GetRand(std::numeric_limits<uint64_t>::max()), uint64_t{10393729187455219830U});
BOOST_CHECK_EQUAL(GetRandInt(std::numeric_limits<int>::max()), int{769702006});
BOOST_CHECK_EQUAL(GetRand<uint64_t>(), uint64_t{10393729187455219830U});
BOOST_CHECK_EQUAL(GetRand<int>(), int{769702006});
BOOST_CHECK_EQUAL(GetRandMicros(std::chrono::hours{1}).count(), 2917185654);
BOOST_CHECK_EQUAL(GetRandMillis(std::chrono::hours{1}).count(), 2144374);
}
Expand All @@ -49,8 +49,8 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests)
// Check that a nondeterministic ones are not
g_mock_deterministic_tests = false;
for (int i = 10; i > 0; --i) {
BOOST_CHECK(GetRand(std::numeric_limits<uint64_t>::max()) != uint64_t{10393729187455219830U});
BOOST_CHECK(GetRandInt(std::numeric_limits<int>::max()) != int{769702006});
BOOST_CHECK(GetRand<uint64_t>() != uint64_t{10393729187455219830U});
BOOST_CHECK(GetRand<int>() != int{769702006});
BOOST_CHECK(GetRandMicros(std::chrono::hours{1}) != std::chrono::microseconds{2917185654});
BOOST_CHECK(GetRandMillis(std::chrono::hours{1}) != std::chrono::milliseconds{2144374});
}
Expand Down
13 changes: 0 additions & 13 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,19 +208,6 @@ inline std::string leftTrim(std::string src, char chr)
return src;
}

inline int64_t GetPerformanceCounter()
{
int64_t nCounter = 0;
#ifdef WIN32
QueryPerformanceCounter((LARGE_INTEGER*)&nCounter);
#else
timeval t;
gettimeofday(&t, nullptr);
nCounter = (int64_t) t.tv_sec * 1000000 + t.tv_usec;
#endif
return nCounter;
}

/** Median filter over a stream of values.
* Returns the median of the last N numbers
*/
Expand Down
6 changes: 3 additions & 3 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,12 +322,12 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
CKeyingMaterial vMasterKey;

vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
GetStrongRandBytes(vMasterKey.data(), WALLET_CRYPTO_KEY_SIZE);
GetStrongRandBytes(vMasterKey);

CMasterKey kMasterKey(nDerivationMethodIndex);

kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
GetStrongRandBytes(kMasterKey.vchSalt.data(), WALLET_CRYPTO_SALT_SIZE);
GetStrongRandBytes(kMasterKey.vchSalt);

CCrypter crypter;
int64_t nStartTime = GetTimeMillis();
Expand Down Expand Up @@ -2178,7 +2178,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
}

// Insert change output at random position in the transaction:
vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
vector<CTxOut>::iterator position = wtxNew.vout.begin() + GetRand<int>(wtxNew.vout.size());
wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));
}
else
Expand Down

0 comments on commit bbe73e5

Please sign in to comment.