| // Copyright 2008 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/rand_util.h" |
| |
| #include <fcntl.h> |
| #include <string.h> |
| |
| #include <algorithm> |
| #include <cmath> |
| #include <limits> |
| |
| #include "base/files/file_util.h" |
| #include "base/logging.h" |
| #include "build/build_config.h" |
| |
| #if defined(OS_FUCHSIA) |
| #include <zircon/syscalls.h> |
| #include "base/fuchsia/fuchsia_logging.h" |
| #elif defined(OS_POSIX) |
| #include "base/posix/eintr_wrapper.h" |
| #elif defined(OS_WIN) |
| #include <windows.h> |
| |
| // #define needed to link in RtlGenRandom(), a.k.a. SystemFunction036. See the |
| // "Community Additions" comment on MSDN here: |
| // http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx |
| #define SystemFunction036 NTAPI SystemFunction036 |
| #include <NTSecAPI.h> |
| #undef SystemFunction036 |
| |
| #endif // OS_WIN |
| |
| #if defined(OS_POSIX) && !defined(OS_FUCHSIA) |
| |
| namespace { |
| |
| int GetUrandomFDInternal() { |
| int fd = HANDLE_EINTR(open("/dev/urandom", O_RDONLY | O_NOCTTY | O_CLOEXEC)); |
| PCHECK(fd >= 0) << "open /dev/urandom"; |
| return fd; |
| } |
| |
| int GetUrandomFD() { |
| static int fd = GetUrandomFDInternal(); |
| return fd; |
| } |
| |
| } // namespace |
| |
| #endif // OS_POSIX && !OS_FUCHSIA |
| |
| namespace base { |
| |
| uint64_t RandUint64() { |
| uint64_t number; |
| RandBytes(&number, sizeof(number)); |
| return number; |
| } |
| |
| int RandInt(int min, int max) { |
| DCHECK_LE(min, max); |
| |
| uint64_t range = static_cast<uint64_t>(max) - min + 1; |
| int result = min + static_cast<int>(base::RandGenerator(range)); |
| DCHECK_GE(result, min); |
| DCHECK_LE(result, max); |
| |
| return result; |
| } |
| |
| uint64_t RandGenerator(uint64_t range) { |
| DCHECK_GT(range, 0u); |
| |
| uint64_t max_acceptable_value = |
| (std::numeric_limits<uint64_t>::max() / range) * range - 1; |
| |
| uint64_t value; |
| do { |
| value = base::RandUint64(); |
| } while (value > max_acceptable_value); |
| |
| return value % range; |
| } |
| |
| double RandDouble() { |
| static_assert(std::numeric_limits<double>::radix == 2, |
| "otherwise use scalbn"); |
| static_assert(std::numeric_limits<double>::digits < |
| std::numeric_limits<uint64_t>::digits, |
| "integer type must be wider than floating-point mantissa"); |
| |
| uint64_t random_bits = RandUint64(); |
| const int kMantissaBits = std::numeric_limits<double>::digits; |
| |
| uint64_t mantissa = random_bits & ((UINT64_C(1) << kMantissaBits) - 1); |
| |
| double result = std::ldexp(mantissa, -1 * kMantissaBits); |
| |
| DCHECK_GE(result, 0.0); |
| DCHECK_LT(result, 1.0); |
| |
| return result; |
| } |
| |
| void RandBytes(void* output, size_t output_length) { |
| if (output_length == 0) { |
| return; |
| } |
| |
| #if defined(OS_FUCHSIA) |
| zx_cprng_draw(output, output_length); |
| #elif defined(OS_POSIX) |
| int fd = GetUrandomFD(); |
| bool success = ReadFromFD(fd, static_cast<char*>(output), output_length); |
| CHECK(success); |
| #elif defined(OS_WIN) |
| char* output_ptr = static_cast<char*>(output); |
| while (output_length > 0) { |
| const ULONG output_bytes_this_pass = static_cast<ULONG>(std::min( |
| output_length, static_cast<size_t>(std::numeric_limits<ULONG>::max()))); |
| const bool success = |
| RtlGenRandom(output_ptr, output_bytes_this_pass) != FALSE; |
| CHECK(success); |
| output_length -= output_bytes_this_pass; |
| output_ptr += output_bytes_this_pass; |
| } |
| #endif |
| } |
| |
| std::string RandBytesAsString(size_t length) { |
| if (length == 0) { |
| return std::string(); |
| } |
| |
| std::string result(length, std::string::value_type()); |
| RandBytes(&result[0], length); |
| return result; |
| } |
| |
| } // namespace base |