Creating a new RNG and replacing rand().

[ Merge of http://go/wvgerrit/84607 ]
[ Merge of http://go/wvgerrit/84608 ]

The primary goal is to replace the use of `rand()` with the random
number generators provided with the C++11 standard.

This simplified generator wraps some of the technical aspects of the
<random> library and provides an interface for uniformly distributed
integers.

As part of the `rand()` purge in the CDM, all uses of the C random int
function in `core()` have been removed.  Places that previously used
`rand()` now use `CdmRandom` facilities.

Test: Linux unittest and Android unittest
Bug: 130680365
Change-Id: Ica383870536ed462dbb80e630c2d66845e38b937
This commit is contained in:
Alex Dale
2019-08-26 14:39:50 -07:00
parent 9da0617606
commit ee56d93454
12 changed files with 406 additions and 78 deletions

View File

@@ -0,0 +1,109 @@
// Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#ifndef WVCDM_CORE_CDM_RANDOM_H_
#define WVCDM_CORE_CDM_RANDOM_H_
#include <mutex>
#include <random>
#include <string>
namespace wvcdm {
// CdmRandomGenerator is a thread safe, pseudo-random number generator.
// It's purpose is to simplified interface for C++11's <random> library.
// Some of the methods use a "device specific" random seed, if the
// compiler/device does not support device specific randomizers, then the
// actual value supplied may not be random.
class CdmRandomGenerator {
public:
// The maximum number of bytes that can be generated at once for
// `RandomData()`.
static constexpr size_t kMaxRandomDataLength = 8192; // 8 kB
// Initializes the pseudo-random generator with a value from a device
// specific random number generator.
CdmRandomGenerator();
// Initializes the pseudo-random generator with the specified seed value.
explicit CdmRandomGenerator(unsigned int seed) : generator_(seed) {}
// All of these methods are thread-safe.
// Seeds the pseudo-random generator with a value from a device specific
// random number generator.
void Seed();
// Seeds the pseudo-random generator with the specified seed value.
// This is somewhat similar to `srand()` from the C standard library;
// except that the sequence generated from successive calls to `Rand()`
// will not necessarily be the same as they would be from the
// standard library `rand()`. This is due to the underlying pseudo-random
// generator that is used.
void Seed(unsigned int seed);
// Returns a pseudo-random integer.
// This is similar to `rand()` from the C standard library. The integer
// returned is in the range of [0, RAND_MAX].
int Rand();
// Allows for RNG to be callable, this is to make it similar to the
// C++11 generator interfaces.
int operator()() { return Rand(); }
// Returns a pseudo-random integer within the provided inclusive range.
uint64_t RandomInRange(uint64_t lower, uint64_t upper);
uint64_t RandomInRange(uint64_t upper) { return RandomInRange(0, upper); }
// Returns a byte string containing randomized bytes of the specified
// length.
// If |length| is greater than |CdmRandomGenerator::kMaxRandomDataLength|,
// then an error is logged and an empty string is returned.
std::string RandomData(size_t length);
// Random true/false using Bernoulli distribution of equal probability.
bool RandomBool();
private:
// Mutex is used to lock the object, and allowing it to be used
// concurrently in different threads.
std::mutex generator_lock_;
// The `default_random_engine` depends on the compiler used and
// potentially its version. This is important to know if you need to
// create reproducible tests between platforms.
std::default_random_engine generator_;
};
// Provides a static interface to a process-wide instance of
// CdmRandomGenerator.
class CdmRandom {
public:
static int Rand() { return GetInstance()->Rand(); }
static uint64_t RandomInRange(uint64_t lower, uint64_t upper) {
return GetInstance()->RandomInRange(lower, upper);
}
static uint64_t RandomInRange(uint64_t upper) {
return GetInstance()->RandomInRange(upper);
}
static std::string RandomData(size_t length) {
return GetInstance()->RandomData(length);
}
static bool RandomBool() { return GetInstance()->RandomBool(); }
private:
// These are intended to be used by tests if needed.
static void Seed(unsigned int seed) { GetInstance()->Seed(seed); }
static void Seed() { GetInstance()->Seed(); }
// Returns the process-wide instance of CdmRandomGenerator.
// It the global instance has not yet been created, then a new instance
// is created using a device-specific random seed.
static CdmRandomGenerator* GetInstance();
};
} // namespace wvcdm
#endif // WVCDM_CORE_CDM_RANDOM_H_