1 // Copyright 2011 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "base/rand_util.h"
11
12 #include <stddef.h>
13 #include <stdint.h>
14
15 #include <algorithm>
16 #include <cmath>
17 #include <limits>
18 #include <memory>
19 #include <vector>
20
21 #include "base/containers/span.h"
22 #include "base/logging.h"
23 #include "base/time/time.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 namespace base {
27
28 namespace {
29
30 const int kIntMin = std::numeric_limits<int>::min();
31 const int kIntMax = std::numeric_limits<int>::max();
32
33 } // namespace
34
TEST(RandUtilTest,RandInt)35 TEST(RandUtilTest, RandInt) {
36 EXPECT_EQ(base::RandInt(0, 0), 0);
37 EXPECT_EQ(base::RandInt(kIntMin, kIntMin), kIntMin);
38 EXPECT_EQ(base::RandInt(kIntMax, kIntMax), kIntMax);
39
40 // Check that the DCHECKS in RandInt() don't fire due to internal overflow.
41 // There was a 50% chance of that happening, so calling it 40 times means
42 // the chances of this passing by accident are tiny (9e-13).
43 for (int i = 0; i < 40; ++i)
44 base::RandInt(kIntMin, kIntMax);
45 }
46
TEST(RandUtilTest,RandDouble)47 TEST(RandUtilTest, RandDouble) {
48 // Force 64-bit precision, making sure we're not in a 80-bit FPU register.
49 volatile double number = base::RandDouble();
50 EXPECT_GT(1.0, number);
51 EXPECT_LE(0.0, number);
52 }
53
TEST(RandUtilTest,RandFloat)54 TEST(RandUtilTest, RandFloat) {
55 // Force 32-bit precision, making sure we're not in an 80-bit FPU register.
56 volatile float number = base::RandFloat();
57 EXPECT_GT(1.f, number);
58 EXPECT_LE(0.f, number);
59 }
60
TEST(RandUtilTest,RandTimeDelta)61 TEST(RandUtilTest, RandTimeDelta) {
62 {
63 const auto delta =
64 base::RandTimeDelta(-base::Seconds(2), -base::Seconds(1));
65 EXPECT_GE(delta, -base::Seconds(2));
66 EXPECT_LT(delta, -base::Seconds(1));
67 }
68
69 {
70 const auto delta = base::RandTimeDelta(-base::Seconds(2), base::Seconds(2));
71 EXPECT_GE(delta, -base::Seconds(2));
72 EXPECT_LT(delta, base::Seconds(2));
73 }
74
75 {
76 const auto delta = base::RandTimeDelta(base::Seconds(1), base::Seconds(2));
77 EXPECT_GE(delta, base::Seconds(1));
78 EXPECT_LT(delta, base::Seconds(2));
79 }
80 }
81
TEST(RandUtilTest,RandTimeDeltaUpTo)82 TEST(RandUtilTest, RandTimeDeltaUpTo) {
83 const auto delta = base::RandTimeDeltaUpTo(base::Seconds(2));
84 EXPECT_FALSE(delta.is_negative());
85 EXPECT_LT(delta, base::Seconds(2));
86 }
87
TEST(RandUtilTest,BitsToOpenEndedUnitInterval)88 TEST(RandUtilTest, BitsToOpenEndedUnitInterval) {
89 // Force 64-bit precision, making sure we're not in an 80-bit FPU register.
90 volatile double all_zeros = BitsToOpenEndedUnitInterval(0x0);
91 EXPECT_EQ(0.0, all_zeros);
92
93 // Force 64-bit precision, making sure we're not in an 80-bit FPU register.
94 volatile double smallest_nonzero = BitsToOpenEndedUnitInterval(0x1);
95 EXPECT_LT(0.0, smallest_nonzero);
96
97 for (uint64_t i = 0x2; i < 0x10; ++i) {
98 // Force 64-bit precision, making sure we're not in an 80-bit FPU register.
99 volatile double number = BitsToOpenEndedUnitInterval(i);
100 EXPECT_EQ(i * smallest_nonzero, number);
101 }
102
103 // Force 64-bit precision, making sure we're not in an 80-bit FPU register.
104 volatile double all_ones = BitsToOpenEndedUnitInterval(UINT64_MAX);
105 EXPECT_GT(1.0, all_ones);
106 }
107
TEST(RandUtilTest,BitsToOpenEndedUnitIntervalF)108 TEST(RandUtilTest, BitsToOpenEndedUnitIntervalF) {
109 // Force 32-bit precision, making sure we're not in an 80-bit FPU register.
110 volatile float all_zeros = BitsToOpenEndedUnitIntervalF(0x0);
111 EXPECT_EQ(0.f, all_zeros);
112
113 // Force 32-bit precision, making sure we're not in an 80-bit FPU register.
114 volatile float smallest_nonzero = BitsToOpenEndedUnitIntervalF(0x1);
115 EXPECT_LT(0.f, smallest_nonzero);
116
117 for (uint64_t i = 0x2; i < 0x10; ++i) {
118 // Force 32-bit precision, making sure we're not in an 80-bit FPU register.
119 volatile float number = BitsToOpenEndedUnitIntervalF(i);
120 EXPECT_EQ(i * smallest_nonzero, number);
121 }
122
123 // Force 32-bit precision, making sure we're not in an 80-bit FPU register.
124 volatile float all_ones = BitsToOpenEndedUnitIntervalF(UINT64_MAX);
125 EXPECT_GT(1.f, all_ones);
126 }
127
TEST(RandUtilTest,RandBytes)128 TEST(RandUtilTest, RandBytes) {
129 const size_t buffer_size = 50;
130 uint8_t buffer[buffer_size];
131 memset(buffer, 0, buffer_size);
132 base::RandBytes(buffer);
133 std::sort(buffer, buffer + buffer_size);
134 // Probability of occurrence of less than 25 unique bytes in 50 random bytes
135 // is below 10^-25.
136 EXPECT_GT(std::unique(buffer, buffer + buffer_size) - buffer, 25);
137 }
138
139 // Verify that calling base::RandBytes with an empty buffer doesn't fail.
TEST(RandUtilTest,RandBytes0)140 TEST(RandUtilTest, RandBytes0) {
141 base::RandBytes(span<uint8_t>());
142 }
143
TEST(RandUtilTest,RandBytesAsVector)144 TEST(RandUtilTest, RandBytesAsVector) {
145 std::vector<uint8_t> random_vec = base::RandBytesAsVector(0);
146 EXPECT_TRUE(random_vec.empty());
147 random_vec = base::RandBytesAsVector(1);
148 EXPECT_EQ(1U, random_vec.size());
149 random_vec = base::RandBytesAsVector(145);
150 EXPECT_EQ(145U, random_vec.size());
151 char accumulator = 0;
152 for (auto i : random_vec) {
153 accumulator |= i;
154 }
155 // In theory this test can fail, but it won't before the universe dies of
156 // heat death.
157 EXPECT_NE(0, accumulator);
158 }
159
TEST(RandUtilTest,RandBytesAsString)160 TEST(RandUtilTest, RandBytesAsString) {
161 std::string random_string = base::RandBytesAsString(1);
162 EXPECT_EQ(1U, random_string.size());
163 random_string = base::RandBytesAsString(145);
164 EXPECT_EQ(145U, random_string.size());
165 char accumulator = 0;
166 for (auto i : random_string)
167 accumulator |= i;
168 // In theory this test can fail, but it won't before the universe dies of
169 // heat death.
170 EXPECT_NE(0, accumulator);
171 }
172
173 // Make sure that it is still appropriate to use RandGenerator in conjunction
174 // with std::random_shuffle().
TEST(RandUtilTest,RandGeneratorForRandomShuffle)175 TEST(RandUtilTest, RandGeneratorForRandomShuffle) {
176 EXPECT_EQ(base::RandGenerator(1), 0U);
177 EXPECT_LE(std::numeric_limits<ptrdiff_t>::max(),
178 std::numeric_limits<int64_t>::max());
179 }
180
TEST(RandUtilTest,RandGeneratorIsUniform)181 TEST(RandUtilTest, RandGeneratorIsUniform) {
182 // Verify that RandGenerator has a uniform distribution. This is a
183 // regression test that consistently failed when RandGenerator was
184 // implemented this way:
185 //
186 // return base::RandUint64() % max;
187 //
188 // A degenerate case for such an implementation is e.g. a top of
189 // range that is 2/3rds of the way to MAX_UINT64, in which case the
190 // bottom half of the range would be twice as likely to occur as the
191 // top half. A bit of calculus care of jar@ shows that the largest
192 // measurable delta is when the top of the range is 3/4ths of the
193 // way, so that's what we use in the test.
194 constexpr uint64_t kTopOfRange =
195 (std::numeric_limits<uint64_t>::max() / 4ULL) * 3ULL;
196 constexpr double kExpectedAverage = static_cast<double>(kTopOfRange / 2);
197 constexpr double kAllowedVariance = kExpectedAverage / 50.0; // +/- 2%
198 constexpr int kMinAttempts = 1000;
199 constexpr int kMaxAttempts = 1000000;
200
201 double cumulative_average = 0.0;
202 int count = 0;
203 while (count < kMaxAttempts) {
204 uint64_t value = base::RandGenerator(kTopOfRange);
205 cumulative_average = (count * cumulative_average + value) / (count + 1);
206
207 // Don't quit too quickly for things to start converging, or we may have
208 // a false positive.
209 if (count > kMinAttempts &&
210 kExpectedAverage - kAllowedVariance < cumulative_average &&
211 cumulative_average < kExpectedAverage + kAllowedVariance) {
212 break;
213 }
214
215 ++count;
216 }
217
218 ASSERT_LT(count, kMaxAttempts) << "Expected average was " << kExpectedAverage
219 << ", average ended at " << cumulative_average;
220 }
221
TEST(RandUtilTest,RandUint64ProducesBothValuesOfAllBits)222 TEST(RandUtilTest, RandUint64ProducesBothValuesOfAllBits) {
223 // This tests to see that our underlying random generator is good
224 // enough, for some value of good enough.
225 uint64_t kAllZeros = 0ULL;
226 uint64_t kAllOnes = ~kAllZeros;
227 uint64_t found_ones = kAllZeros;
228 uint64_t found_zeros = kAllOnes;
229
230 for (size_t i = 0; i < 1000; ++i) {
231 uint64_t value = base::RandUint64();
232 found_ones |= value;
233 found_zeros &= value;
234
235 if (found_zeros == kAllZeros && found_ones == kAllOnes)
236 return;
237 }
238
239 FAIL() << "Didn't achieve all bit values in maximum number of tries.";
240 }
241
TEST(RandUtilTest,RandBytesLonger)242 TEST(RandUtilTest, RandBytesLonger) {
243 // Fuchsia can only retrieve 256 bytes of entropy at a time, so make sure we
244 // handle longer requests than that.
245 std::string random_string0 = base::RandBytesAsString(255);
246 EXPECT_EQ(255u, random_string0.size());
247 std::string random_string1 = base::RandBytesAsString(1023);
248 EXPECT_EQ(1023u, random_string1.size());
249 std::string random_string2 = base::RandBytesAsString(4097);
250 EXPECT_EQ(4097u, random_string2.size());
251 }
252
253 // Benchmark test for RandBytes(). Disabled since it's intentionally slow and
254 // does not test anything that isn't already tested by the existing RandBytes()
255 // tests.
TEST(RandUtilTest,DISABLED_RandBytesPerf)256 TEST(RandUtilTest, DISABLED_RandBytesPerf) {
257 // Benchmark the performance of |kTestIterations| of RandBytes() using a
258 // buffer size of |kTestBufferSize|.
259 const int kTestIterations = 10;
260 const size_t kTestBufferSize = 1 * 1024 * 1024;
261
262 std::array<uint8_t, kTestBufferSize> buffer;
263 const base::TimeTicks now = base::TimeTicks::Now();
264 for (int i = 0; i < kTestIterations; ++i) {
265 base::RandBytes(buffer);
266 }
267 const base::TimeTicks end = base::TimeTicks::Now();
268
269 LOG(INFO) << "RandBytes(" << kTestBufferSize
270 << ") took: " << (end - now).InMicroseconds() << "µs";
271 }
272
TEST(RandUtilTest,InsecureRandomGeneratorProducesBothValuesOfAllBits)273 TEST(RandUtilTest, InsecureRandomGeneratorProducesBothValuesOfAllBits) {
274 // This tests to see that our underlying random generator is good
275 // enough, for some value of good enough.
276 uint64_t kAllZeros = 0ULL;
277 uint64_t kAllOnes = ~kAllZeros;
278 uint64_t found_ones = kAllZeros;
279 uint64_t found_zeros = kAllOnes;
280
281 InsecureRandomGenerator generator;
282
283 for (size_t i = 0; i < 1000; ++i) {
284 uint64_t value = generator.RandUint64();
285 found_ones |= value;
286 found_zeros &= value;
287
288 if (found_zeros == kAllZeros && found_ones == kAllOnes)
289 return;
290 }
291
292 FAIL() << "Didn't achieve all bit values in maximum number of tries.";
293 }
294
295 namespace {
296
297 constexpr double kXp1Percent = -2.33;
298 constexpr double kXp99Percent = 2.33;
299
ChiSquaredCriticalValue(double nu,double x_p)300 double ChiSquaredCriticalValue(double nu, double x_p) {
301 // From "The Art Of Computer Programming" (TAOCP), Volume 2, Section 3.3.1,
302 // Table 1. This is the asymptotic value for nu > 30, up to O(1 / sqrt(nu)).
303 return nu + sqrt(2. * nu) * x_p + 2. / 3. * (x_p * x_p) - 2. / 3.;
304 }
305
ExtractBits(uint64_t value,int from_bit,int num_bits)306 int ExtractBits(uint64_t value, int from_bit, int num_bits) {
307 return (value >> from_bit) & ((1 << num_bits) - 1);
308 }
309
310 // Performs a Chi-Squared test on a subset of |num_bits| extracted starting from
311 // |from_bit| in the generated value.
312 //
313 // See TAOCP, Volume 2, Section 3.3.1, and
314 // https://en.wikipedia.org/wiki/Pearson%27s_chi-squared_test for details.
315 //
316 // This is only one of the many, many random number generator test we could do,
317 // but they are cumbersome, as they are typically very slow, and expected to
318 // fail from time to time, due to their probabilistic nature.
319 //
320 // The generator we use has however been vetted with the BigCrush test suite
321 // from Marsaglia, so this should suffice as a smoke test that our
322 // implementation is wrong.
ChiSquaredTest(InsecureRandomGenerator & gen,size_t n,int from_bit,int num_bits)323 bool ChiSquaredTest(InsecureRandomGenerator& gen,
324 size_t n,
325 int from_bit,
326 int num_bits) {
327 const int range = 1 << num_bits;
328 CHECK_EQ(static_cast<int>(n % range), 0) << "Makes computations simpler";
329 std::vector<size_t> samples(range, 0);
330
331 // Count how many samples pf each value are found. All buckets should be
332 // almost equal if the generator is suitably uniformly random.
333 for (size_t i = 0; i < n; i++) {
334 int sample = ExtractBits(gen.RandUint64(), from_bit, num_bits);
335 samples[sample] += 1;
336 }
337
338 // Compute the Chi-Squared statistic, which is:
339 // \Sum_{k=0}^{range-1} \frac{(count - expected)^2}{expected}
340 double chi_squared = 0.;
341 double expected_count = n / range;
342 for (size_t sample_count : samples) {
343 double deviation = sample_count - expected_count;
344 chi_squared += (deviation * deviation) / expected_count;
345 }
346
347 // The generator should produce numbers that are not too far of (chi_squared
348 // lower than a given quantile), but not too close to the ideal distribution
349 // either (chi_squared is too low).
350 //
351 // See The Art Of Computer Programming, Volume 2, Section 3.3.1 for details.
352 return chi_squared > ChiSquaredCriticalValue(range - 1, kXp1Percent) &&
353 chi_squared < ChiSquaredCriticalValue(range - 1, kXp99Percent);
354 }
355
356 } // namespace
357
TEST(RandUtilTest,InsecureRandomGeneratorChiSquared)358 TEST(RandUtilTest, InsecureRandomGeneratorChiSquared) {
359 constexpr int kIterations = 50;
360
361 // Specifically test the low bits, which are usually weaker in random number
362 // generators. We don't use them for the 32 bit number generation, but let's
363 // make sure they are still suitable.
364 for (int start_bit : {1, 2, 3, 8, 12, 20, 32, 48, 54}) {
365 int pass_count = 0;
366 for (int i = 0; i < kIterations; i++) {
367 size_t samples = 1 << 16;
368 InsecureRandomGenerator gen;
369 // Fix the seed to make the test non-flaky.
370 gen.ReseedForTesting(kIterations + 1);
371 bool pass = ChiSquaredTest(gen, samples, start_bit, 8);
372 pass_count += pass;
373 }
374
375 // We exclude 1% on each side, so we expect 98% of tests to pass, meaning 98
376 // * kIterations / 100. However this is asymptotic, so add a bit of leeway.
377 int expected_pass_count = (kIterations * 98) / 100;
378 EXPECT_GE(pass_count, expected_pass_count - ((kIterations * 2) / 100))
379 << "For start_bit = " << start_bit;
380 }
381 }
382
TEST(RandUtilTest,InsecureRandomGeneratorRandDouble)383 TEST(RandUtilTest, InsecureRandomGeneratorRandDouble) {
384 InsecureRandomGenerator gen;
385
386 for (int i = 0; i < 1000; i++) {
387 volatile double x = gen.RandDouble();
388 EXPECT_GE(x, 0.);
389 EXPECT_LT(x, 1.);
390 }
391 }
392
TEST(RandUtilTest,MetricsSubSampler)393 TEST(RandUtilTest, MetricsSubSampler) {
394 MetricsSubSampler sub_sampler;
395 int true_count = 0;
396 int false_count = 0;
397 for (int i = 0; i < 1000; ++i) {
398 if (sub_sampler.ShouldSample(0.5)) {
399 ++true_count;
400 } else {
401 ++false_count;
402 }
403 }
404
405 // Validate that during normal operation MetricsSubSampler::ShouldSample()
406 // does not always give the same result. It's technically possible to fail
407 // this test during normal operation but if the sampling is realistic it
408 // should happen about once every 2^999 times (the likelihood of the [1,999]
409 // results being the same as [0], which can be either). This should not make
410 // this test flaky in the eyes of automated testing.
411 EXPECT_GT(true_count, 0);
412 EXPECT_GT(false_count, 0);
413 }
414
TEST(RandUtilTest,MetricsSubSamplerTestingSupport)415 TEST(RandUtilTest, MetricsSubSamplerTestingSupport) {
416 MetricsSubSampler sub_sampler;
417
418 // ScopedAlwaysSampleForTesting makes ShouldSample() return true with
419 // any probability.
420 {
421 MetricsSubSampler::ScopedAlwaysSampleForTesting always_sample;
422 for (int i = 0; i < 100; ++i) {
423 EXPECT_TRUE(sub_sampler.ShouldSample(0));
424 EXPECT_TRUE(sub_sampler.ShouldSample(0.5));
425 EXPECT_TRUE(sub_sampler.ShouldSample(1));
426 }
427 }
428
429 // ScopedNeverSampleForTesting makes ShouldSample() return true with
430 // any probability.
431 {
432 MetricsSubSampler::ScopedNeverSampleForTesting always_sample;
433 for (int i = 0; i < 100; ++i) {
434 EXPECT_FALSE(sub_sampler.ShouldSample(0));
435 EXPECT_FALSE(sub_sampler.ShouldSample(0.5));
436 EXPECT_FALSE(sub_sampler.ShouldSample(1));
437 }
438 }
439 }
440
441 } // namespace base
442