Skip to content

Commit 4fd2d2f

Browse files
committed
Add a FastRandomContext::randrange and use it
1 parent 1632922 commit 4fd2d2f

File tree

7 files changed

+75
-2
lines changed

7 files changed

+75
-2
lines changed

configure.ac

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,8 @@ AC_CHECK_DECLS([bswap_16, bswap_32, bswap_64],,,
550550
#include <byteswap.h>
551551
#endif])
552552

553+
AC_CHECK_DECLS([__builtin_clz, __builtin_clzl, __builtin_clzll])
554+
553555
dnl Check for MSG_NOSIGNAL
554556
AC_MSG_CHECKING(for MSG_NOSIGNAL)
555557
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>]],

src/bench/checkqueue.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::State& state)
6868
PrevectorJob(){
6969
}
7070
PrevectorJob(FastRandomContext& insecure_rand){
71-
p.resize(insecure_rand.rand32() % (PREVECTOR_SIZE*2));
71+
p.resize(insecure_rand.randrange(PREVECTOR_SIZE*2));
7272
}
7373
bool operator()()
7474
{

src/crypto/common.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,25 @@ void static inline WriteBE64(unsigned char* ptr, uint64_t x)
7979
memcpy(ptr, (char*)&v, 8);
8080
}
8181

82+
/** Return the smallest number n such that (x >> n) == 0 (or 64 if the highest bit in x is set. */
83+
uint64_t static inline CountBits(uint64_t x)
84+
{
85+
#ifdef HAVE_DECL___BUILTIN_CLZL
86+
if (sizeof(unsigned long) >= sizeof(uint64_t)) {
87+
return x ? 8 * sizeof(unsigned long) - __builtin_clzl(x) : 0;
88+
}
89+
#endif
90+
#ifdef HAVE_DECL___BUILTIN_CLZLL
91+
if (sizeof(unsigned long long) >= sizeof(uint64_t)) {
92+
return x ? 8 * sizeof(unsigned long long) - __builtin_clzll(x) : 0;
93+
}
94+
#endif
95+
int ret = 0;
96+
while (x) {
97+
x >>= 1;
98+
++ret;
99+
}
100+
return ret;
101+
}
102+
82103
#endif // BITCOIN_CRYPTO_COMMON_H

src/net.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -760,7 +760,7 @@ class CNode
760760
// after addresses were pushed.
761761
if (_addr.IsValid() && !addrKnown.contains(_addr.GetKey())) {
762762
if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) {
763-
vAddrToSend[insecure_rand.rand32() % vAddrToSend.size()] = _addr;
763+
vAddrToSend[insecure_rand.randrange(vAddrToSend.size())] = _addr;
764764
} else {
765765
vAddrToSend.push_back(_addr);
766766
}

src/random.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#define BITCOIN_RANDOM_H
88

99
#include "crypto/chacha20.h"
10+
#include "crypto/common.h"
1011
#include "uint256.h"
1112

1213
#include <stdint.h>
@@ -91,6 +92,17 @@ class FastRandomContext {
9192
}
9293
}
9394

95+
/** Generate a random integer in the range [0..range). */
96+
uint64_t randrange(uint64_t range)
97+
{
98+
--range;
99+
int bits = CountBits(range);
100+
while (true) {
101+
uint64_t ret = randbits(bits);
102+
if (ret <= range) return ret;
103+
}
104+
}
105+
94106
/** Generate a random 32-bit integer. */
95107
uint32_t rand32() { return randbits(32); }
96108

src/test/crypto_tests.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "crypto/sha512.h"
1111
#include "crypto/hmac_sha256.h"
1212
#include "crypto/hmac_sha512.h"
13+
#include "random.h"
1314
#include "utilstrencodings.h"
1415
#include "test/test_bitcoin.h"
1516
#include "test/test_random.h"
@@ -484,4 +485,26 @@ BOOST_AUTO_TEST_CASE(chacha20_testvector)
484485
"fab78c9");
485486
}
486487

488+
BOOST_AUTO_TEST_CASE(countbits_tests)
489+
{
490+
FastRandomContext ctx;
491+
for (int i = 0; i <= 64; ++i) {
492+
if (i == 0) {
493+
// Check handling of zero.
494+
BOOST_CHECK_EQUAL(CountBits(0), 0);
495+
} else if (i < 10) {
496+
for (uint64_t j = 1 << (i - 1); (j >> i) == 0; ++j) {
497+
// Exhaustively test up to 10 bits
498+
BOOST_CHECK_EQUAL(CountBits(j), i);
499+
}
500+
} else {
501+
for (int k = 0; k < 1000; k++) {
502+
// Randomly test 1000 samples of each length above 10 bits.
503+
uint64_t j = ((uint64_t)1) << (i - 1) | ctx.randbits(i - 1);
504+
BOOST_CHECK_EQUAL(CountBits(j), i);
505+
}
506+
}
507+
}
508+
}
509+
487510
BOOST_AUTO_TEST_SUITE_END()

src/test/random_tests.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,19 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests)
3535
BOOST_CHECK(ctx3.rand64() != ctx4.rand64()); // extremely unlikely to be equal
3636
}
3737

38+
BOOST_AUTO_TEST_CASE(fastrandom_randbits)
39+
{
40+
FastRandomContext ctx1;
41+
FastRandomContext ctx2;
42+
for (int bits = 0; bits < 63; ++bits) {
43+
for (int j = 0; j < 1000; ++j) {
44+
uint64_t rangebits = ctx1.randbits(bits);
45+
BOOST_CHECK_EQUAL(rangebits >> bits, 0);
46+
uint64_t range = ((uint64_t)1) << bits | rangebits;
47+
uint64_t rand = ctx2.randrange(range);
48+
BOOST_CHECK(rand < range);
49+
}
50+
}
51+
}
52+
3853
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)