Commit a72e7903 authored by Dustin Pho's avatar Dustin Pho Committed by Facebook Github Bot

Secure RNG utilities

Summary: Adding secure RNG utility functions (rand32, rand64, oneIn, randDouble01, randDouble).

Reviewed By: yfeldblum

Differential Revision: D6551975

fbshipit-source-id: 720d138de1329669b1a15eb3e9cb3fe91ce982a4
parent 7fc3f917
...@@ -50,9 +50,9 @@ namespace folly { ...@@ -50,9 +50,9 @@ namespace folly {
*/ */
class ThreadLocalPRNG { class ThreadLocalPRNG {
public: public:
typedef uint32_t result_type; using result_type = uint32_t;
uint32_t operator()() { result_type operator()() {
// Using a static method allows the compiler to avoid allocating stack space // Using a static method allows the compiler to avoid allocating stack space
// for this class. // for this class.
return getImpl(local_); return getImpl(local_);
...@@ -75,15 +75,33 @@ class ThreadLocalPRNG { ...@@ -75,15 +75,33 @@ class ThreadLocalPRNG {
LocalInstancePRNG* local_; LocalInstancePRNG* local_;
}; };
class Random { class Random {
private: private:
template <class RNG> template <class RNG>
using ValidRNG = typename std::enable_if< using ValidRNG = typename std::enable_if<
std::is_unsigned<typename std::result_of<RNG&()>::type>::value, std::is_unsigned<typename std::result_of<RNG&()>::type>::value,
RNG>::type; RNG>::type;
template <class T>
class SecureRNG {
public:
using result_type = typename std::enable_if<
std::is_integral<T>::value && !std::is_same<T, bool>::value,
T>::type;
result_type operator()() {
return Random::secureRandom<result_type>();
}
static constexpr result_type min() {
return std::numeric_limits<result_type>::min();
}
static constexpr result_type max() {
return std::numeric_limits<result_type>::max();
}
};
public: public:
// Default generator type. // Default generator type.
#if FOLLY_HAVE_EXTRANDOM_SFMT19937 #if FOLLY_HAVE_EXTRANDOM_SFMT19937
...@@ -102,14 +120,84 @@ class Random { ...@@ -102,14 +120,84 @@ class Random {
*/ */
template <class T> template <class T>
static typename std::enable_if< static typename std::enable_if<
std::is_integral<T>::value && !std::is_same<T,bool>::value, std::is_integral<T>::value && !std::is_same<T, bool>::value,
T>::type T>::type
secureRandom() { secureRandom() {
T val; T val;
secureRandom(&val, sizeof(val)); secureRandom(&val, sizeof(val));
return val; return val;
} }
/**
* Returns a secure random uint32_t
*/
static uint32_t secureRand32() {
return secureRandom<uint32_t>();
}
/**
* Returns a secure random uint32_t in [0, max). If max == 0, returns 0.
*/
static uint32_t secureRand32(uint32_t max) {
SecureRNG<uint32_t> srng;
return rand32(max, srng);
}
/**
* Returns a secure random uint32_t in [min, max). If min == max, returns 0.
*/
static uint32_t secureRand32(uint32_t min, uint32_t max) {
SecureRNG<uint32_t> srng;
return rand32(min, max, srng);
}
/**
* Returns a secure random uint64_t
*/
static uint64_t secureRand64() {
return secureRandom<uint64_t>();
}
/**
* Returns a secure random uint64_t in [0, max). If max == 0, returns 0.
*/
static uint64_t secureRand64(uint64_t max) {
SecureRNG<uint64_t> srng;
return rand64(max, srng);
}
/**
* Returns a secure random uint64_t in [min, max). If min == max, returns 0.
*/
static uint64_t secureRand64(uint64_t min, uint64_t max) {
SecureRNG<uint64_t> srng;
return rand64(min, max, srng);
}
/**
* Returns true 1/n of the time. If n == 0, always returns false
*/
static bool secureOneIn(uint32_t n) {
SecureRNG<uint32_t> srng;
return rand32(0, n, srng) == 0;
}
/**
* Returns a secure double in [0, 1)
*/
static double secureRandDouble01() {
SecureRNG<uint64_t> srng;
return randDouble01(srng);
}
/**
* Returns a secure double in [min, max), if min == max, returns 0.
*/
static double secureRandDouble(double min, double max) {
SecureRNG<uint64_t> srng;
return randDouble(min, max, srng);
}
/** /**
* (Re-)Seed an existing RNG with a good seed. * (Re-)Seed an existing RNG with a good seed.
* *
...@@ -265,15 +353,15 @@ class Random { ...@@ -265,15 +353,15 @@ class Random {
} }
/** /**
* Returns a double in [min, max), if min == max, returns 0. * Returns a double in [min, max), if min == max, returns 0.
*/ */
static double randDouble(double min, double max) { static double randDouble(double min, double max) {
return randDouble(min, max, ThreadLocalPRNG()); return randDouble(min, max, ThreadLocalPRNG());
} }
/** /**
* Returns a double in [min, max), if min == max, returns 0. * Returns a double in [min, max), if min == max, returns 0.
*/ */
template <class RNG = ThreadLocalPRNG, class /* EnableIf */ = ValidRNG<RNG>> template <class RNG = ThreadLocalPRNG, class /* EnableIf */ = ValidRNG<RNG>>
static double randDouble(double min, double max, RNG&& rng) { static double randDouble(double min, double max, RNG&& rng) {
if (std::fabs(max - min) < std::numeric_limits<double>::epsilon()) { if (std::fabs(max - min) < std::numeric_limits<double>::epsilon()) {
...@@ -281,7 +369,6 @@ class Random { ...@@ -281,7 +369,6 @@ class Random {
} }
return std::uniform_real_distribution<double>(min, max)(rng); return std::uniform_real_distribution<double>(min, max)(rng);
} }
}; };
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment