|
13 | 13 | // limitations under the License. |
14 | 14 |
|
15 | 15 | #include "google/cloud/internal/random.h" |
| 16 | +#include <algorithm> |
| 17 | +#include <limits> |
16 | 18 |
|
17 | 19 | namespace google { |
18 | 20 | namespace cloud { |
19 | 21 | inline namespace GOOGLE_CLOUD_CPP_NS { |
20 | 22 | namespace internal { |
| 23 | +std::vector<unsigned int> FetchEntropy(std::size_t desired_bits) { |
| 24 | + // We use the default C++ random device to generate entropy. The quality of |
| 25 | + // this source of entropy is implementation-defined: |
| 26 | + // http://en.cppreference.com/w/cpp/numeric/random/random_device/random_device |
| 27 | + // However, in all the platforms we care about, this seems to be a reasonably |
| 28 | + // non-deterministic source of entropy. |
| 29 | + // |
| 30 | + // On Linux with libstdc++ (the most common library on Linux) is based on |
| 31 | + // either `/dev/urandom`, or (if available) the RDRAND [1], or the RDSEED [1] |
| 32 | + // CPU instructions. |
| 33 | + // |
| 34 | + // On Linux with libc++ the default seems to be using `/dev/urandom`, but the |
| 35 | + // library could have been compiled [2] to use `getentropy(3)` [3], |
| 36 | + // `arc4random()` [4], or even `nacl` [5]. It does not seem like the library |
| 37 | + // uses the RDRAND or RDSEED instructions directly. In any case, it seems that |
| 38 | + // all the choices are good entropy sources. |
| 39 | + // |
| 40 | + // With MSVC the documentation says that the numbers are not deterministic, |
| 41 | + // and cryptographically secure, but no further details are available: |
| 42 | + // https://docs.microsoft.com/en-us/cpp/standard-library/random-device-class |
| 43 | + // |
| 44 | + // On macOS the library is libc++ implementation so the previous comments |
| 45 | + // apply. |
| 46 | + // |
| 47 | + // One would want to simply pass a `std::random_device` to the constructor for |
| 48 | + // the random bit generators, but the C++11 approach is annoying, see this |
| 49 | + // critique for the details: |
| 50 | + // http://www.pcg-random.org/posts/simple-portable-cpp-seed-entropy.html |
| 51 | + // |
| 52 | + // [1]: https://en.wikipedia.org/wiki/RDRAND |
| 53 | + // [2]: https://github.com/llvm-mirror/libcxx/blob/master/src/random.cpp |
| 54 | + // [3]: http://man7.org/linux/man-pages/man3/getentropy.3.html |
| 55 | + // [4]: https://linux.die.net/man/3/arc4random |
| 56 | + // [5]: https://en.wikipedia.org/wiki/NaCl_(software) |
| 57 | + // |
| 58 | +#if defined(__GLIBCXX__) && __GLIBCXX__ >= 20200128 |
| 59 | + // Workaround for a libstd++ bug: |
| 60 | + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087 |
| 61 | + // we cannot simply use `rdrand` everywhere because this is library and |
| 62 | + // version specific, i.e., other standard C++ libraries do not support |
| 63 | + // `rdrand`, and even older versions of libstdc++ do not support `rdrand`. |
| 64 | + std::random_device rd("rdrand"); |
| 65 | +#else |
| 66 | + std::random_device rd; |
| 67 | +#endif // defined(__GLIBCXX__) && __GLIBCXX__ >= 20200128 |
| 68 | + |
| 69 | + auto constexpr kWordSize = std::numeric_limits<unsigned int>::digits; |
| 70 | + auto const n = (desired_bits + kWordSize - 1) / kWordSize; |
| 71 | + std::vector<unsigned int> entropy(n); |
| 72 | + std::generate(entropy.begin(), entropy.end(), [&rd]() { return rd(); }); |
| 73 | + return entropy; |
| 74 | +} |
| 75 | + |
21 | 76 | std::string Sample(DefaultPRNG& gen, int n, std::string const& population) { |
22 | 77 | std::uniform_int_distribution<std::size_t> rd(0, population.size() - 1); |
23 | 78 |
|
|
0 commit comments