Skip to content

Commit ddb7d26

Browse files
committed
random: add RandomMixin::randbits with compile-known bits
In many cases, it is known at compile time how many bits are requested from randbits. Provide a variant of randbits that accepts this number as a template, to make sure the compiler can make use of this knowledge. This is used immediately in rand32() and randbool(), and a few further call sites.
1 parent 21ce9d8 commit ddb7d26

File tree

6 files changed

+52
-9
lines changed

6 files changed

+52
-9
lines changed

src/addrman.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ std::pair<CAddress, NodeSeconds> AddrManImpl::Select_(bool new_only, std::option
776776
const AddrInfo& info{it_found->second};
777777

778778
// With probability GetChance() * chance_factor, return the entry.
779-
if (insecure_rand.randbits(30) < chance_factor * info.GetChance() * (1 << 30)) {
779+
if (insecure_rand.randbits<30>() < chance_factor * info.GetChance() * (1 << 30)) {
780780
LogPrint(BCLog::ADDRMAN, "Selected %s from %s\n", info.ToStringAddrPort(), search_tried ? "tried" : "new");
781781
return {info, info.m_last_try};
782782
}

src/random.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,6 @@ void RandomInit()
741741

742742
std::chrono::microseconds GetExponentialRand(std::chrono::microseconds now, std::chrono::seconds average_interval)
743743
{
744-
double unscaled = -std::log1p(GetRand(uint64_t{1} << 48) * -0.0000000000000035527136788 /* -1/2^48 */);
744+
double unscaled = -std::log1p(FastRandomContext().randbits<48>() * -0.0000000000000035527136788 /* -1/2^48 */);
745745
return now + std::chrono::duration_cast<std::chrono::microseconds>(unscaled * average_interval + 0.5us);
746746
}

src/random.h

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,30 @@ class RandomMixin
223223
return ret & ((uint64_t{1} << bits) - 1);
224224
}
225225

226+
/** Same as above, but with compile-time fixed bits count. */
227+
template<int Bits>
228+
uint64_t randbits() noexcept
229+
{
230+
static_assert(Bits >= 0 && Bits <= 64);
231+
if constexpr (Bits == 64) {
232+
return Impl().rand64();
233+
} else {
234+
uint64_t ret;
235+
if (Bits <= bitbuf_size) {
236+
ret = bitbuf;
237+
bitbuf >>= Bits;
238+
bitbuf_size -= Bits;
239+
} else {
240+
uint64_t gen = Impl().rand64();
241+
ret = (gen << bitbuf_size) | bitbuf;
242+
bitbuf = gen >> (Bits - bitbuf_size);
243+
bitbuf_size = 64 + bitbuf_size - Bits;
244+
}
245+
constexpr uint64_t MASK = (uint64_t{1} << Bits) - 1;
246+
return ret & MASK;
247+
}
248+
}
249+
226250
/** Generate a random integer in the range [0..range).
227251
* Precondition: range > 0.
228252
*/
@@ -247,7 +271,7 @@ class RandomMixin
247271
}
248272

249273
/** Generate a random 32-bit integer. */
250-
uint32_t rand32() noexcept { return Impl().randbits(32); }
274+
uint32_t rand32() noexcept { return Impl().template randbits<32>(); }
251275

252276
/** generate a random uint256. */
253277
uint256 rand256() noexcept
@@ -258,7 +282,7 @@ class RandomMixin
258282
}
259283

260284
/** Generate a random boolean. */
261-
bool randbool() noexcept { return Impl().randbits(1); }
285+
bool randbool() noexcept { return Impl().template randbits<1>(); }
262286

263287
/** Return the time point advanced by a uniform random duration. */
264288
template <typename Tp>

src/test/crypto_tests.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,7 +1195,7 @@ BOOST_AUTO_TEST_CASE(muhash_tests)
11951195
uint256 res;
11961196
int table[4];
11971197
for (int i = 0; i < 4; ++i) {
1198-
table[i] = g_insecure_rand_ctx.randbits(3);
1198+
table[i] = g_insecure_rand_ctx.randbits<3>();
11991199
}
12001200
for (int order = 0; order < 4; ++order) {
12011201
MuHash3072 acc;
@@ -1215,8 +1215,8 @@ BOOST_AUTO_TEST_CASE(muhash_tests)
12151215
}
12161216
}
12171217

1218-
MuHash3072 x = FromInt(g_insecure_rand_ctx.randbits(4)); // x=X
1219-
MuHash3072 y = FromInt(g_insecure_rand_ctx.randbits(4)); // x=X, y=Y
1218+
MuHash3072 x = FromInt(g_insecure_rand_ctx.randbits<4>()); // x=X
1219+
MuHash3072 y = FromInt(g_insecure_rand_ctx.randbits<4>()); // x=X, y=Y
12201220
MuHash3072 z; // x=X, y=Y, z=1
12211221
z *= x; // x=X, y=Y, z=X
12221222
z *= y; // x=X, y=Y, z=X*Y

src/test/random_tests.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ BOOST_AUTO_TEST_CASE(fastrandom_randbits)
107107
BOOST_AUTO_TEST_CASE(randbits_test)
108108
{
109109
FastRandomContext ctx_lens; //!< RNG for producing the lengths requested from ctx_test.
110-
FastRandomContext ctx_test; //!< The RNG being tested.
110+
FastRandomContext ctx_test1(true), ctx_test2(true); //!< The RNGs being tested.
111111
int ctx_test_bitsleft{0}; //!< (Assumed value of) ctx_test::bitbuf_len
112112

113113
// Run the entire test 5 times.
@@ -122,7 +122,25 @@ BOOST_AUTO_TEST_CASE(randbits_test)
122122
// Decide on a number of bits to request (0 through 64, inclusive; don't use randbits/randrange).
123123
int bits = ctx_lens.rand64() % 65;
124124
// Generate that many bits.
125-
uint64_t gen = ctx_test.randbits(bits);
125+
uint64_t gen = ctx_test1.randbits(bits);
126+
// For certain bits counts, also test randbits<Bits> and compare.
127+
uint64_t gen2;
128+
if (bits == 0) {
129+
gen2 = ctx_test2.randbits<0>();
130+
} else if (bits == 1) {
131+
gen2 = ctx_test2.randbits<1>();
132+
} else if (bits == 7) {
133+
gen2 = ctx_test2.randbits<7>();
134+
} else if (bits == 32) {
135+
gen2 = ctx_test2.randbits<32>();
136+
} else if (bits == 51) {
137+
gen2 = ctx_test2.randbits<51>();
138+
} else if (bits == 64) {
139+
gen2 = ctx_test2.randbits<64>();
140+
} else {
141+
gen2 = ctx_test2.randbits(bits);
142+
}
143+
BOOST_CHECK_EQUAL(gen, gen2);
126144
// Make sure the result is in range.
127145
if (bits < 64) BOOST_CHECK_EQUAL(gen >> bits, 0);
128146
// Mark all the seen bits in the output.

test/sanitizer_suppressions/ubsan

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,4 @@ shift-base:streams.h
7777
shift-base:FormatHDKeypath
7878
shift-base:xoroshiro128plusplus.h
7979
shift-base:RandomMixin<*>::randbits
80+
shift-base:RandomMixin<*>::randbits<*>

0 commit comments

Comments
 (0)