Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2011 The Chromium Authors |
[email protected] | 05f9b68 | 2008-09-29 22:18:01 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "base/rand_util.h" |
| 6 | |
avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 7 | #include <limits.h> |
[email protected] | 05f9b68 | 2008-09-29 22:18:01 | [diff] [blame] | 8 | #include <math.h> |
tfarina | 3208992 | 2015-05-18 22:14:09 | [diff] [blame] | 9 | #include <stdint.h> |
[email protected] | 94a0f31 | 2008-09-30 14:26:33 | [diff] [blame] | 10 | |
John Chen | 87cc25c | 2018-04-20 22:49:49 | [diff] [blame] | 11 | #include <algorithm> |
| 12 | #include <limits> |
| 13 | |
Hans Wennborg | c3cffa6 | 2020-04-27 10:09:12 | [diff] [blame] | 14 | #include "base/check_op.h" |
[email protected] | c851cfd | 2013-06-10 20:11:14 | [diff] [blame] | 15 | #include "base/strings/string_util.h" |
Peter Kasting | f18c8ca | 2023-10-04 16:31:51 | [diff] [blame] | 16 | #include "base/time/time.h" |
[email protected] | 05f9b68 | 2008-09-29 22:18:01 | [diff] [blame] | 17 | |
[email protected] | 05f9b68 | 2008-09-29 22:18:01 | [diff] [blame] | 18 | namespace base { |
| 19 | |
François Doray | 87e35a8 | 2023-05-05 14:44:28 | [diff] [blame] | 20 | namespace { |
| 21 | |
| 22 | bool g_subsampling_enabled = true; |
| 23 | |
| 24 | } // namespace |
| 25 | |
John Mellor | afab972d | 2017-09-26 16:28:19 | [diff] [blame] | 26 | uint64_t RandUint64() { |
| 27 | uint64_t number; |
| 28 | RandBytes(&number, sizeof(number)); |
| 29 | return number; |
| 30 | } |
| 31 | |
[email protected] | 05f9b68 | 2008-09-29 22:18:01 | [diff] [blame] | 32 | int RandInt(int min, int max) { |
[email protected] | d7a93ad | 2011-04-22 13:13:07 | [diff] [blame] | 33 | DCHECK_LE(min, max); |
[email protected] | 05f9b68 | 2008-09-29 22:18:01 | [diff] [blame] | 34 | |
Peter Kasting | 28b51cf | 2022-06-28 15:02:43 | [diff] [blame] | 35 | uint64_t range = static_cast<uint64_t>(max) - static_cast<uint64_t>(min) + 1; |
John Chen | 87cc25c | 2018-04-20 22:49:49 | [diff] [blame] | 36 | // |range| is at most UINT_MAX + 1, so the result of RandGenerator(range) |
| 37 | // is at most UINT_MAX. Hence it's safe to cast it from uint64_t to int64_t. |
| 38 | int result = |
| 39 | static_cast<int>(min + static_cast<int64_t>(base::RandGenerator(range))); |
[email protected] | e1be56d | 2011-05-04 01:29:38 | [diff] [blame] | 40 | DCHECK_GE(result, min); |
| 41 | DCHECK_LE(result, max); |
[email protected] | 05f9b68 | 2008-09-29 22:18:01 | [diff] [blame] | 42 | return result; |
| 43 | } |
| 44 | |
| 45 | double RandDouble() { |
[email protected] | edafd4c | 2011-05-10 17:18:53 | [diff] [blame] | 46 | return BitsToOpenEndedUnitInterval(base::RandUint64()); |
| 47 | } |
| 48 | |
Avery Musbach | eff342b | 2022-10-06 18:36:07 | [diff] [blame] | 49 | float RandFloat() { |
| 50 | return BitsToOpenEndedUnitIntervalF(base::RandUint64()); |
| 51 | } |
| 52 | |
Peter Kasting | f18c8ca | 2023-10-04 16:31:51 | [diff] [blame] | 53 | TimeDelta RandTimeDelta(TimeDelta start, TimeDelta limit) { |
| 54 | // We must have a finite, non-empty, non-reversed interval. |
| 55 | CHECK_LT(start, limit); |
| 56 | CHECK(!start.is_min()); |
| 57 | CHECK(!limit.is_max()); |
| 58 | |
| 59 | const int64_t range = (limit - start).InMicroseconds(); |
| 60 | // Because of the `CHECK_LT()` above, range > 0, so this cast is safe. |
| 61 | const uint64_t delta_us = base::RandGenerator(static_cast<uint64_t>(range)); |
| 62 | // ...and because `range` fit in an `int64_t`, so will `delta_us`. |
| 63 | return start + Microseconds(static_cast<int64_t>(delta_us)); |
| 64 | } |
| 65 | |
| 66 | TimeDelta RandTimeDeltaUpTo(TimeDelta limit) { |
| 67 | return RandTimeDelta(TimeDelta(), limit); |
| 68 | } |
| 69 | |
Nico Weber | 0a3852a7 | 2015-10-29 20:42:58 | [diff] [blame] | 70 | double BitsToOpenEndedUnitInterval(uint64_t bits) { |
[email protected] | 94a0f31 | 2008-09-30 14:26:33 | [diff] [blame] | 71 | // We try to get maximum precision by masking out as many bits as will fit |
| 72 | // in the target type's mantissa, and raising it to an appropriate power to |
| 73 | // produce output in the range [0, 1). For IEEE 754 doubles, the mantissa |
Avery Musbach | 92a30e38 | 2022-09-08 23:30:41 | [diff] [blame] | 74 | // is expected to accommodate 53 bits (including the implied bit). |
avi | 4ec0dff | 2015-11-24 14:26:24 | [diff] [blame] | 75 | static_assert(std::numeric_limits<double>::radix == 2, |
| 76 | "otherwise use scalbn"); |
Avery Musbach | 92a30e38 | 2022-09-08 23:30:41 | [diff] [blame] | 77 | constexpr int kBits = std::numeric_limits<double>::digits; |
| 78 | return ldexp(bits & ((UINT64_C(1) << kBits) - 1u), -kBits); |
[email protected] | 05f9b68 | 2008-09-29 22:18:01 | [diff] [blame] | 79 | } |
| 80 | |
Avery Musbach | eff342b | 2022-10-06 18:36:07 | [diff] [blame] | 81 | float BitsToOpenEndedUnitIntervalF(uint64_t bits) { |
| 82 | // We try to get maximum precision by masking out as many bits as will fit |
| 83 | // in the target type's mantissa, and raising it to an appropriate power to |
| 84 | // produce output in the range [0, 1). For IEEE 754 floats, the mantissa is |
| 85 | // expected to accommodate 12 bits (including the implied bit). |
| 86 | static_assert(std::numeric_limits<float>::radix == 2, "otherwise use scalbn"); |
| 87 | constexpr int kBits = std::numeric_limits<float>::digits; |
| 88 | return ldexpf(bits & ((UINT64_C(1) << kBits) - 1u), -kBits); |
| 89 | } |
| 90 | |
Nico Weber | 0a3852a7 | 2015-10-29 20:42:58 | [diff] [blame] | 91 | uint64_t RandGenerator(uint64_t range) { |
[email protected] | 0173b96 | 2011-08-24 19:58:36 | [diff] [blame] | 92 | DCHECK_GT(range, 0u); |
[email protected] | af2e192b | 2011-05-30 17:39:09 | [diff] [blame] | 93 | // We must discard random results above this number, as they would |
| 94 | // make the random generator non-uniform (consider e.g. if |
[email protected] | 0173b96 | 2011-08-24 19:58:36 | [diff] [blame] | 95 | // MAX_UINT64 was 7 and |range| was 5, then a result of 1 would be twice |
| 96 | // as likely as a result of 3 or 4). |
Nico Weber | 0a3852a7 | 2015-10-29 20:42:58 | [diff] [blame] | 97 | uint64_t max_acceptable_value = |
| 98 | (std::numeric_limits<uint64_t>::max() / range) * range - 1; |
[email protected] | af2e192b | 2011-05-30 17:39:09 | [diff] [blame] | 99 | |
Nico Weber | 0a3852a7 | 2015-10-29 20:42:58 | [diff] [blame] | 100 | uint64_t value; |
[email protected] | af2e192b | 2011-05-30 17:39:09 | [diff] [blame] | 101 | do { |
| 102 | value = base::RandUint64(); |
[email protected] | 0173b96 | 2011-08-24 19:58:36 | [diff] [blame] | 103 | } while (value > max_acceptable_value); |
[email protected] | af2e192b | 2011-05-30 17:39:09 | [diff] [blame] | 104 | |
[email protected] | 0173b96 | 2011-08-24 19:58:36 | [diff] [blame] | 105 | return value % range; |
[email protected] | a74dcae | 2010-08-30 21:07:05 | [diff] [blame] | 106 | } |
| 107 | |
[email protected] | 51a0181 | 2011-05-05 08:46:11 | [diff] [blame] | 108 | std::string RandBytesAsString(size_t length) { |
[email protected] | fdce478 | 2011-11-29 20:06:18 | [diff] [blame] | 109 | DCHECK_GT(length, 0u); |
[email protected] | 51a0181 | 2011-05-05 08:46:11 | [diff] [blame] | 110 | std::string result; |
| 111 | RandBytes(WriteInto(&result, length + 1), length); |
[email protected] | 29548d8 | 2011-04-29 21:03:54 | [diff] [blame] | 112 | return result; |
| 113 | } |
| 114 | |
Tom Sepez | 230a75c6 | 2023-11-13 23:27:16 | [diff] [blame^] | 115 | std::vector<uint8_t> RandBytesAsVector(size_t length) { |
| 116 | std::vector<uint8_t> result(length); |
| 117 | if (result.size()) { |
| 118 | RandBytes(result.data(), result.size()); |
| 119 | } |
| 120 | return result; |
| 121 | } |
| 122 | |
Benoit Lize | 7532d4af | 2021-08-24 11:34:04 | [diff] [blame] | 123 | InsecureRandomGenerator::InsecureRandomGenerator() { |
Benoit Lize | 73de21b | 2021-07-02 08:17:56 | [diff] [blame] | 124 | a_ = base::RandUint64(); |
| 125 | b_ = base::RandUint64(); |
Benoit Lize | 73de21b | 2021-07-02 08:17:56 | [diff] [blame] | 126 | } |
| 127 | |
Benoit Lize | 7532d4af | 2021-08-24 11:34:04 | [diff] [blame] | 128 | void InsecureRandomGenerator::ReseedForTesting(uint64_t seed) { |
Benoit Lize | 73de21b | 2021-07-02 08:17:56 | [diff] [blame] | 129 | a_ = seed; |
| 130 | b_ = seed; |
Benoit Lize | 73de21b | 2021-07-02 08:17:56 | [diff] [blame] | 131 | } |
| 132 | |
| 133 | uint64_t InsecureRandomGenerator::RandUint64() { |
Benoit Lize | 73de21b | 2021-07-02 08:17:56 | [diff] [blame] | 134 | // Using XorShift128+, which is simple and widely used. See |
| 135 | // https://en.wikipedia.org/wiki/Xorshift#xorshift+ for details. |
| 136 | uint64_t t = a_; |
| 137 | const uint64_t s = b_; |
| 138 | |
| 139 | a_ = s; |
| 140 | t ^= t << 23; |
| 141 | t ^= t >> 17; |
| 142 | t ^= s ^ (s >> 26); |
| 143 | b_ = t; |
| 144 | |
| 145 | return t + s; |
| 146 | } |
| 147 | |
| 148 | uint32_t InsecureRandomGenerator::RandUint32() { |
| 149 | // The generator usually returns an uint64_t, truncate it. |
| 150 | // |
| 151 | // It is noted in this paper (https://arxiv.org/abs/1810.05313) that the |
| 152 | // lowest 32 bits fail some statistical tests from the Big Crush |
| 153 | // suite. Use the higher ones instead. |
| 154 | return this->RandUint64() >> 32; |
| 155 | } |
| 156 | |
Benoit Lize | d637714 | 2021-07-05 10:17:16 | [diff] [blame] | 157 | double InsecureRandomGenerator::RandDouble() { |
| 158 | uint64_t x = RandUint64(); |
| 159 | // From https://vigna.di.unimi.it/xorshift/. |
| 160 | // 53 bits of mantissa, hence the "hexadecimal exponent" 1p-53. |
| 161 | return (x >> 11) * 0x1.0p-53; |
| 162 | } |
| 163 | |
Benoit Lize | ee4fe1e4 | 2022-06-29 19:13:48 | [diff] [blame] | 164 | MetricsSubSampler::MetricsSubSampler() = default; |
| 165 | bool MetricsSubSampler::ShouldSample(double probability) { |
François Doray | 87e35a8 | 2023-05-05 14:44:28 | [diff] [blame] | 166 | return !g_subsampling_enabled || generator_.RandDouble() < probability; |
| 167 | } |
| 168 | |
| 169 | MetricsSubSampler::ScopedDisableForTesting::ScopedDisableForTesting() { |
| 170 | DCHECK(g_subsampling_enabled); |
| 171 | g_subsampling_enabled = false; |
| 172 | } |
| 173 | |
| 174 | MetricsSubSampler::ScopedDisableForTesting::~ScopedDisableForTesting() { |
| 175 | DCHECK(!g_subsampling_enabled); |
| 176 | g_subsampling_enabled = true; |
Benoit Lize | ee4fe1e4 | 2022-06-29 19:13:48 | [diff] [blame] | 177 | } |
| 178 | |
[email protected] | 05f9b68 | 2008-09-29 22:18:01 | [diff] [blame] | 179 | } // namespace base |