RandomNumberGenerator.cpp 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. //===-- RandomNumberGenerator.cpp - Implement RNG class -------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file implements deterministic random number generation (RNG).
  10. // The current implementation is NOT cryptographically secure as it uses
  11. // the C++11 <random> facilities.
  12. //
  13. //===----------------------------------------------------------------------===//
  14. #include "llvm/Support/RandomNumberGenerator.h"
  15. #include "DebugOptions.h"
  16. #include "llvm/Support/CommandLine.h"
  17. #include "llvm/Support/Debug.h"
  18. #include "llvm/Support/raw_ostream.h"
  19. #ifdef _WIN32
  20. #include "llvm/Support/Windows/WindowsSupport.h"
  21. #else
  22. #include "Unix/Unix.h"
  23. #endif
  24. using namespace llvm;
  25. #define DEBUG_TYPE "rng"
  26. namespace {
  27. struct CreateSeed {
  28. static void *call() {
  29. return new cl::opt<uint64_t>(
  30. "rng-seed", cl::value_desc("seed"), cl::Hidden,
  31. cl::desc("Seed for the random number generator"), cl::init(0));
  32. }
  33. };
  34. } // namespace
  35. static ManagedStatic<cl::opt<uint64_t>, CreateSeed> Seed;
  36. void llvm::initRandomSeedOptions() { *Seed; }
  37. RandomNumberGenerator::RandomNumberGenerator(StringRef Salt) {
  38. LLVM_DEBUG(if (*Seed == 0) dbgs()
  39. << "Warning! Using unseeded random number generator.\n");
  40. // Combine seed and salts using std::seed_seq.
  41. // Data: Seed-low, Seed-high, Salt
  42. // Note: std::seed_seq can only store 32-bit values, even though we
  43. // are using a 64-bit RNG. This isn't a problem since the Mersenne
  44. // twister constructor copies these correctly into its initial state.
  45. std::vector<uint32_t> Data;
  46. Data.resize(2 + Salt.size());
  47. Data[0] = *Seed;
  48. Data[1] = *Seed >> 32;
  49. llvm::copy(Salt, Data.begin() + 2);
  50. std::seed_seq SeedSeq(Data.begin(), Data.end());
  51. Generator.seed(SeedSeq);
  52. }
  53. RandomNumberGenerator::result_type RandomNumberGenerator::operator()() {
  54. return Generator();
  55. }
  56. // Get random vector of specified size
  57. std::error_code llvm::getRandomBytes(void *Buffer, size_t Size) {
  58. #ifdef _WIN32
  59. HCRYPTPROV hProvider;
  60. if (CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL,
  61. CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
  62. ScopedCryptContext ScopedHandle(hProvider);
  63. if (CryptGenRandom(hProvider, Size, static_cast<BYTE *>(Buffer)))
  64. return std::error_code();
  65. }
  66. return std::error_code(GetLastError(), std::system_category());
  67. #else
  68. int Fd = open("/dev/urandom", O_RDONLY);
  69. if (Fd != -1) {
  70. std::error_code Ret;
  71. ssize_t BytesRead = read(Fd, Buffer, Size);
  72. if (BytesRead == -1)
  73. Ret = std::error_code(errno, std::system_category());
  74. else if (BytesRead != static_cast<ssize_t>(Size))
  75. Ret = std::error_code(EIO, std::system_category());
  76. if (close(Fd) == -1)
  77. Ret = std::error_code(errno, std::system_category());
  78. return Ret;
  79. }
  80. return std::error_code(errno, std::system_category());
  81. #endif
  82. }