brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.0 KiB · 2959fc2 Raw
97 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements deterministic random number generation (RNG).10// The current implementation is NOT cryptographically secure as it uses11// the C++11 <random> facilities.12//13//===----------------------------------------------------------------------===//14 15#include "llvm/Support/RandomNumberGenerator.h"16 17#include "DebugOptions.h"18 19#include "llvm/Support/CommandLine.h"20#include "llvm/Support/Debug.h"21#include "llvm/Support/Error.h"22#include "llvm/Support/ManagedStatic.h"23#include "llvm/Support/raw_ostream.h"24#ifdef _WIN3225#include "llvm/Support/Windows/WindowsSupport.h"26#else27#include "Unix/Unix.h"28#endif29 30using namespace llvm;31 32#define DEBUG_TYPE "rng"33namespace {34struct CreateSeed {35  static void *call() {36    return new cl::opt<uint64_t>(37        "rng-seed", cl::value_desc("seed"), cl::Hidden,38        cl::desc("Seed for the random number generator"), cl::init(0));39  }40};41} // namespace42static ManagedStatic<cl::opt<uint64_t>, CreateSeed> Seed;43void llvm::initRandomSeedOptions() { *Seed; }44 45RandomNumberGenerator::RandomNumberGenerator(StringRef Salt) {46  LLVM_DEBUG(if (*Seed == 0) dbgs()47             << "Warning! Using unseeded random number generator.\n");48 49  // Combine seed and salts using std::seed_seq.50  // Data: Seed-low, Seed-high, Salt51  // Note: std::seed_seq can only store 32-bit values, even though we52  // are using a 64-bit RNG. This isn't a problem since the Mersenne53  // twister constructor copies these correctly into its initial state.54  std::vector<uint32_t> Data;55  Data.resize(2 + Salt.size());56  Data[0] = *Seed;57  Data[1] = *Seed >> 32;58 59  llvm::copy(Salt, Data.begin() + 2);60 61  std::seed_seq SeedSeq(Data.begin(), Data.end());62  Generator.seed(SeedSeq);63}64 65RandomNumberGenerator::result_type RandomNumberGenerator::operator()() {66  return Generator();67}68 69// Get random vector of specified size70std::error_code llvm::getRandomBytes(void *Buffer, size_t Size) {71#ifdef _WIN3272  HCRYPTPROV hProvider;73  if (CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL,74                           CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {75    ScopedCryptContext ScopedHandle(hProvider);76    if (CryptGenRandom(hProvider, Size, static_cast<BYTE *>(Buffer)))77      return std::error_code();78  }79  return std::error_code(GetLastError(), std::system_category());80#else81  int Fd = open("/dev/urandom", O_RDONLY);82  if (Fd != -1) {83    std::error_code Ret;84    ssize_t BytesRead = read(Fd, Buffer, Size);85    if (BytesRead == -1)86      Ret = errnoAsErrorCode();87    else if (BytesRead != static_cast<ssize_t>(Size))88      Ret = std::error_code(EIO, std::system_category());89    if (close(Fd) == -1)90      Ret = errnoAsErrorCode();91 92    return Ret;93  }94  return errnoAsErrorCode();95#endif96}97